9897bb
From 4a0243ecb4c94e2d73510d096c5ea4d0711fc6c0 Mon Sep 17 00:00:00 2001
9897bb
From: Seunghun Han <kkamagui@gmail.com>
9897bb
Date: Fri, 23 Jun 2017 14:19:48 +0900
9897bb
Subject: [PATCH] acpi: acpica: fix acpi parse and parseext cache leaks
9897bb
MIME-Version: 1.0
9897bb
Content-Type: text/plain; charset=UTF-8
9897bb
Content-Transfer-Encoding: 8bit
9897bb
9897bb
I'm Seunghun Han, and I work for National Security Research Institute of
9897bb
South Korea.
9897bb
9897bb
I have been doing a research on ACPI and found an ACPI cache leak in ACPI
9897bb
early abort cases.
9897bb
9897bb
Boot log of ACPI cache leak is as follows:
9897bb
[    0.352414] ACPI: Added _OSI(Module Device)
9897bb
[    0.353182] ACPI: Added _OSI(Processor Device)
9897bb
[    0.353182] ACPI: Added _OSI(3.0 _SCP Extensions)
9897bb
[    0.353182] ACPI: Added _OSI(Processor Aggregator Device)
9897bb
[    0.356028] ACPI: Unable to start the ACPI Interpreter
9897bb
[    0.356799] ACPI Error: Could not remove SCI handler (20170303/evmisc-281)
9897bb
[    0.360215] kmem_cache_destroy Acpi-State: Slab cache still has objects
9897bb
[    0.360648] CPU: 0 PID: 1 Comm: swapper/0 Tainted: G        W
9897bb
4.12.0-rc4-next-20170608+ #10
9897bb
[    0.361273] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS
9897bb
VirtualBox 12/01/2006
9897bb
[    0.361873] Call Trace:
9897bb
[    0.362243]  ? dump_stack+0x5c/0x81
9897bb
[    0.362591]  ? kmem_cache_destroy+0x1aa/0x1c0
9897bb
[    0.362944]  ? acpi_sleep_proc_init+0x27/0x27
9897bb
[    0.363296]  ? acpi_os_delete_cache+0xa/0x10
9897bb
[    0.363646]  ? acpi_ut_delete_caches+0x6d/0x7b
9897bb
[    0.364000]  ? acpi_terminate+0xa/0x14
9897bb
[    0.364000]  ? acpi_init+0x2af/0x34f
9897bb
[    0.364000]  ? __class_create+0x4c/0x80
9897bb
[    0.364000]  ? video_setup+0x7f/0x7f
9897bb
[    0.364000]  ? acpi_sleep_proc_init+0x27/0x27
9897bb
[    0.364000]  ? do_one_initcall+0x4e/0x1a0
9897bb
[    0.364000]  ? kernel_init_freeable+0x189/0x20a
9897bb
[    0.364000]  ? rest_init+0xc0/0xc0
9897bb
[    0.364000]  ? kernel_init+0xa/0x100
9897bb
[    0.364000]  ? ret_from_fork+0x25/0x30
9897bb
9897bb
I analyzed this memory leak in detail. I found that “Acpi-State” cache and
9897bb
“Acpi-Parse” cache were merged because the size of cache objects was same
9897bb
slab cache size.
9897bb
9897bb
I finally found “Acpi-Parse” cache and “Acpi-ParseExt” cache were leaked
9897bb
using SLAB_NEVER_MERGE flag in kmem_cache_create() function.
9897bb
9897bb
Real ACPI cache leak point is as follows:
9897bb
[    0.360101] ACPI: Added _OSI(Module Device)
9897bb
[    0.360101] ACPI: Added _OSI(Processor Device)
9897bb
[    0.360101] ACPI: Added _OSI(3.0 _SCP Extensions)
9897bb
[    0.361043] ACPI: Added _OSI(Processor Aggregator Device)
9897bb
[    0.364016] ACPI: Unable to start the ACPI Interpreter
9897bb
[    0.365061] ACPI Error: Could not remove SCI handler (20170303/evmisc-281)
9897bb
[    0.368174] kmem_cache_destroy Acpi-Parse: Slab cache still has objects
9897bb
[    0.369332] CPU: 1 PID: 1 Comm: swapper/0 Tainted: G        W
9897bb
4.12.0-rc4-next-20170608+ #8
9897bb
[    0.371256] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS
9897bb
VirtualBox 12/01/2006
9897bb
[    0.372000] Call Trace:
9897bb
[    0.372000]  ? dump_stack+0x5c/0x81
9897bb
[    0.372000]  ? kmem_cache_destroy+0x1aa/0x1c0
9897bb
[    0.372000]  ? acpi_sleep_proc_init+0x27/0x27
9897bb
[    0.372000]  ? acpi_os_delete_cache+0xa/0x10
9897bb
[    0.372000]  ? acpi_ut_delete_caches+0x56/0x7b
9897bb
[    0.372000]  ? acpi_terminate+0xa/0x14
9897bb
[    0.372000]  ? acpi_init+0x2af/0x34f
9897bb
[    0.372000]  ? __class_create+0x4c/0x80
9897bb
[    0.372000]  ? video_setup+0x7f/0x7f
9897bb
[    0.372000]  ? acpi_sleep_proc_init+0x27/0x27
9897bb
[    0.372000]  ? do_one_initcall+0x4e/0x1a0
9897bb
[    0.372000]  ? kernel_init_freeable+0x189/0x20a
9897bb
[    0.372000]  ? rest_init+0xc0/0xc0
9897bb
[    0.372000]  ? kernel_init+0xa/0x100
9897bb
[    0.372000]  ? ret_from_fork+0x25/0x30
9897bb
[    0.388039] kmem_cache_destroy Acpi-ParseExt: Slab cache still has objects
9897bb
[    0.389063] CPU: 1 PID: 1 Comm: swapper/0 Tainted: G        W
9897bb
4.12.0-rc4-next-20170608+ #8
9897bb
[    0.390557] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS
9897bb
VirtualBox 12/01/2006
9897bb
[    0.392000] Call Trace:
9897bb
[    0.392000]  ? dump_stack+0x5c/0x81
9897bb
[    0.392000]  ? kmem_cache_destroy+0x1aa/0x1c0
9897bb
[    0.392000]  ? acpi_sleep_proc_init+0x27/0x27
9897bb
[    0.392000]  ? acpi_os_delete_cache+0xa/0x10
9897bb
[    0.392000]  ? acpi_ut_delete_caches+0x6d/0x7b
9897bb
[    0.392000]  ? acpi_terminate+0xa/0x14
9897bb
[    0.392000]  ? acpi_init+0x2af/0x34f
9897bb
[    0.392000]  ? __class_create+0x4c/0x80
9897bb
[    0.392000]  ? video_setup+0x7f/0x7f
9897bb
[    0.392000]  ? acpi_sleep_proc_init+0x27/0x27
9897bb
[    0.392000]  ? do_one_initcall+0x4e/0x1a0
9897bb
[    0.392000]  ? kernel_init_freeable+0x189/0x20a
9897bb
[    0.392000]  ? rest_init+0xc0/0xc0
9897bb
[    0.392000]  ? kernel_init+0xa/0x100
9897bb
[    0.392000]  ? ret_from_fork+0x25/0x30
9897bb
9897bb
When early abort is occurred due to invalid ACPI information, Linux kernel
9897bb
terminates ACPI by calling acpi_terminate() function. The function calls
9897bb
acpi_ut_delete_caches() function to delete local caches (acpi_gbl_namespace_
9897bb
cache, state_cache, operand_cache, ps_node_cache, ps_node_ext_cache).
9897bb
9897bb
But the deletion codes in acpi_ut_delete_caches() function only delete
9897bb
slab caches using kmem_cache_destroy() function, therefore the cache
9897bb
objects should be flushed before acpi_ut_delete_caches() function.
9897bb
9897bb
“Acpi-Parse” cache and “Acpi-ParseExt” cache are used in an AML parse
9897bb
function, acpi_ps_parse_loop(). The function should have flush codes to
9897bb
handle an error state due to invalid AML codes.
9897bb
9897bb
This cache leak has a security threat because an old kernel (<= 4.9) shows
9897bb
memory locations of kernel functions in stack dump. Some malicious users
9897bb
could use this information to neutralize kernel ASLR.
9897bb
9897bb
To fix ACPI cache leak for enhancing security, I made a patch which has
9897bb
flush codes in acpi_ps_parse_loop() function.
9897bb
9897bb
I hope that this patch improves the security of Linux kernel.
9897bb
9897bb
Thank you.
9897bb
9897bb
Signed-off-by: Seunghun Han <kkamagui@gmail.com>
9897bb
9897bb
Github-Location: https://github.com/acpica/acpica/pull/278/commits/4a0243ecb4c94e2d73510d096c5ea4d0711fc6c0
9897bb
9897bb
---
9897bb
 source/components/parser/psobject.c | 44 ++++++++++++++-----------------------
9897bb
 1 file changed, 16 insertions(+), 28 deletions(-)
9897bb
9897bb
Index: acpica-unix2-20200925/source/components/parser/psobject.c
9897bb
===================================================================
9897bb
--- acpica-unix2-20200925.orig/source/components/parser/psobject.c
9897bb
+++ acpica-unix2-20200925/source/components/parser/psobject.c
9897bb
@@ -707,7 +707,8 @@ AcpiPsCompleteFinalOp (
9897bb
     ACPI_PARSE_OBJECT       *Op,
9897bb
     ACPI_STATUS             Status)
9897bb
 {
9897bb
-    ACPI_STATUS             Status2;
9897bb
+    ACPI_STATUS             ReturnStatus = AE_OK;
9897bb
+    BOOLEAN                 Ascending = TRUE;
9897bb
 
9897bb
 
9897bb
     ACPI_FUNCTION_TRACE_PTR (PsCompleteFinalOp, WalkState);
9897bb
@@ -724,7 +725,7 @@ AcpiPsCompleteFinalOp (
9897bb
     {
9897bb
         if (Op)
9897bb
         {
9897bb
-            if (WalkState->AscendingCallback != NULL)
9897bb
+            if (Ascending && WalkState->AscendingCallback != NULL)
9897bb
             {
9897bb
                 WalkState->Op = Op;
9897bb
                 WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
9897bb
@@ -743,41 +744,28 @@ AcpiPsCompleteFinalOp (
9897bb
 
9897bb
                 if (Status == AE_CTRL_TERMINATE)
9897bb
                 {
9897bb
-                    Status = AE_OK;
9897bb
-
9897bb
-                    /* Clean up */
9897bb
-                    do
9897bb
-                    {
9897bb
-                        if (Op)
9897bb
-                        {
9897bb
-                            Status2 = AcpiPsCompleteThisOp (WalkState, Op);
9897bb
-                            if (ACPI_FAILURE (Status2))
9897bb
-                            {
9897bb
-                                return_ACPI_STATUS (Status2);
9897bb
-                            }
9897bb
-                        }
9897bb
-
9897bb
-                        AcpiPsPopScope (&(WalkState->ParserState), &Op,
9897bb
-                            &WalkState->ArgTypes, &WalkState->ArgCount);
9897bb
-
9897bb
-                    } while (Op);
9897bb
-
9897bb
-                    return_ACPI_STATUS (Status);
9897bb
+                    Ascending = FALSE;
9897bb
+                    ReturnStatus = AE_CTRL_TERMINATE;
9897bb
                 }
9897bb
 
9897bb
                 else if (ACPI_FAILURE (Status))
9897bb
                 {
9897bb
                     /* First error is most important */
9897bb
 
9897bb
-                    (void) AcpiPsCompleteThisOp (WalkState, Op);
9897bb
-                    return_ACPI_STATUS (Status);
9897bb
+                    Ascending = FALSE;
9897bb
+                    ReturnStatus = Status;
9897bb
                 }
9897bb
             }
9897bb
 
9897bb
-            Status2 = AcpiPsCompleteThisOp (WalkState, Op);
9897bb
-            if (ACPI_FAILURE (Status2))
9897bb
+            Status = AcpiPsCompleteThisOp (WalkState, Op);
9897bb
+            if (ACPI_FAILURE (Status))
9897bb
             {
9897bb
-                return_ACPI_STATUS (Status2);
9897bb
+                Ascending = FALSE;
9897bb
+                if (ACPI_SUCCESS (ReturnStatus) ||
9897bb
+                    ReturnStatus == AE_CTRL_TERMINATE)
9897bb
+                {
9897bb
+                    ReturnStatus = Status;
9897bb
+                }
9897bb
             }
9897bb
         }
9897bb
 
9897bb
@@ -786,5 +774,5 @@ AcpiPsCompleteFinalOp (
9897bb
 
9897bb
     } while (Op);
9897bb
 
9897bb
-    return_ACPI_STATUS (Status);
9897bb
+    return_ACPI_STATUS (ReturnStatus);
9897bb
 }