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