https://git.reactos.org/?p=reactos.git;a=commitdiff;h=389a2da7ff94cfcefff32…
commit 389a2da7ff94cfcefff3220797f61311519d6fa0
Author:     Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Thu May 19 23:43:18 2022 +0200
Commit:     Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Mon May 23 19:30:34 2022 +0200
    [NTOS:SE] SepCaptureAcl(): Add missing validation of the captured ACL (#4523)
    - The ACL is however not validated when the function is called within
      kernel mode and no capture is actually being done.
    - Simplify aspects of the function (returning early when possible).
---
 ntoskrnl/se/acl.c   | 85 ++++++++++++++++++++++++++++-------------------------
 ntoskrnl/se/token.c |  2 +-
 2 files changed, 46 insertions(+), 41 deletions(-)
diff --git a/ntoskrnl/se/acl.c b/ntoskrnl/se/acl.c
index e160b34c429..d7c53d4ac17 100644
--- a/ntoskrnl/se/acl.c
+++ b/ntoskrnl/se/acl.c
@@ -329,15 +329,15 @@ SepCreateImpersonationTokenDacl(
  *
  * @param[in] AccessMode
  * Processor level access mode. The processor mode determines how
- * are the input arguments probed.
+ * the input arguments are probed.
  *
  * @param[in] PoolType
  * Pool type for new captured ACL for creation. The pool type determines
- * how the ACL data should reside in the pool memory.
+ * in which memory pool the ACL data should reside.
  *
  * @param[in] CaptureIfKernel
- * If set to TRUE and the processor access mode being KernelMode, we're
- * capturing an ACL directly in the kernel. Otherwise we're capturing
+ * If set to TRUE and the processor access mode being KernelMode, we are
+ * capturing an ACL directly in the kernel. Otherwise we are capturing
  * within a kernel mode driver.
  *
  * @param[out] CapturedAcl
@@ -357,11 +357,19 @@ SepCaptureAcl(
     _Out_ PACL *CapturedAcl)
 {
     PACL NewAcl;
-    ULONG AclSize = 0;
-    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG AclSize;
     PAGED_CODE();
+    /* If in kernel mode and we do not capture, just
+     * return the given ACL and don't validate it. */
+    if ((AccessMode == KernelMode) && !CaptureIfKernel)
+    {
+        *CapturedAcl = InputAcl;
+        return STATUS_SUCCESS;
+    }
+
+    /* Otherwise, capture and validate the ACL, depending on the access mode */
     if (AccessMode != KernelMode)
     {
         _SEH2_TRY
@@ -381,59 +389,56 @@ SepCaptureAcl(
         }
         _SEH2_END;
+        /* Validate the minimal size an ACL can have */
+        if (AclSize < sizeof(ACL))
+            return STATUS_INVALID_ACL;
+
         NewAcl = ExAllocatePoolWithTag(PoolType,
                                        AclSize,
                                        TAG_ACL);
-        if (NewAcl != NULL)
-        {
-            _SEH2_TRY
-            {
-                RtlCopyMemory(NewAcl,
-                              InputAcl,
-                              AclSize);
+        if (!NewAcl)
+            return STATUS_INSUFFICIENT_RESOURCES;
-                *CapturedAcl = NewAcl;
-            }
-            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-            {
-                /* Free the ACL and return the exception code */
-                ExFreePoolWithTag(NewAcl, TAG_ACL);
-                _SEH2_YIELD(return _SEH2_GetExceptionCode());
-            }
-            _SEH2_END;
+        _SEH2_TRY
+        {
+            RtlCopyMemory(NewAcl, InputAcl, AclSize);
         }
-        else
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-            Status = STATUS_INSUFFICIENT_RESOURCES;
+            /* Free the ACL and return the exception code */
+            ExFreePoolWithTag(NewAcl, TAG_ACL);
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
         }
-    }
-    else if (!CaptureIfKernel)
-    {
-        *CapturedAcl = InputAcl;
+        _SEH2_END;
     }
     else
     {
         AclSize = InputAcl->AclSize;
+        /* Validate the minimal size an ACL can have */
+        if (AclSize < sizeof(ACL))
+            return STATUS_INVALID_ACL;
+
         NewAcl = ExAllocatePoolWithTag(PoolType,
                                        AclSize,
                                        TAG_ACL);
+        if (!NewAcl)
+            return STATUS_INSUFFICIENT_RESOURCES;
-        if (NewAcl != NULL)
-        {
-            RtlCopyMemory(NewAcl,
-                          InputAcl,
-                          AclSize);
+        RtlCopyMemory(NewAcl, InputAcl, AclSize);
+    }
-            *CapturedAcl = NewAcl;
-        }
-        else
-        {
-            Status = STATUS_INSUFFICIENT_RESOURCES;
-        }
+    /* Validate the captured ACL */
+    if (!RtlValidAcl(NewAcl))
+    {
+        /* Free the ACL and fail */
+        ExFreePoolWithTag(NewAcl, TAG_ACL);
+        return STATUS_INVALID_ACL;
     }
-    return Status;
+    /* It's valid, return it */
+    *CapturedAcl = NewAcl;
+    return STATUS_SUCCESS;
 }
 /**
diff --git a/ntoskrnl/se/token.c b/ntoskrnl/se/token.c
index 1415e36009d..f215f4c1fe2 100644
--- a/ntoskrnl/se/token.c
+++ b/ntoskrnl/se/token.c
@@ -4518,7 +4518,7 @@ NtSetInformationToken(
                     {
                         PACL CapturedAcl;
-                        /* Capture and copy the dacl */
+                        /* Capture, validate, and copy the DACL */
                         Status = SepCaptureAcl(InputAcl,
                                                PreviousMode,
                                                PagedPool,