Invalid ACL error from SetKernelObjectSecurity API call

Posted on 2009-07-16
Last Modified: 2013-11-07
I need to change the security descriptor of a process to either deny or allow certain users to kill a process.  The application must do some critical operations that do not happen (of course) when the process is killed.

The code below always returns "The Access control list (ACL) structure is invalid." after the SetKernelObjectSecurity call.  

If I pass in nothing for the ACL when I create my RawSecurityDescriptor, the call to SetKernelObjectSecurity succeeds.  However, since no ACL exists, it gives everyone full control of the process, something that really shouldn't happen.  This has been verified by using ProcessExplorer.

I am at wits end trying to figure out what is wrong with the ACL.  

Imports System.Runtime.InteropServices


<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> Public Structure ACL

   Public AclRevision As Byte

   Public Sbz1 As Byte

   Public AclSize As Short

   Public AceCount As Short

   Public Sbz2 As Short

End Structure


<StructLayout(LayoutKind.Sequential)> Public Structure SECURITY_DESCRIPTOR

   Public Revision As Byte

   Public Sbz1 As Byte

   Public Control As Integer

   Public Owner As IntPtr

   Public Group As IntPtr

   Public Sacl As IntPtr

   Public Dacl As IntPtr

End Structure




Public Class Form1


   <DllImport("advapi32.dll", CharSet:=CharSet.Ansi, setlasterror:=True)> _

   Public Shared Function SetKernelObjectSecurity( _

      ByVal hObject As IntPtr, _

      ByVal SecurityInformation As Integer, _

      <MarshalAs(UnmanagedType.Struct)> ByRef pSecurityDescriptor As SECURITY_DESCRIPTOR) _

      As Integer


   End Function


   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

      Dim LastError As Integer = 0

      Dim iResult As Integer = 0


      Dim myACL As New System.Security.AccessControl.RawAcl(1, 1)

      Dim newACE As System.Security.AccessControl.GenericAce

      Dim myByte((4 * 12) - 1) As Byte


      Dim myAccessMask As Integer = 0

      Dim mySid As New System.Security.Principal.SecurityIdentifier(Security.Principal.WellKnownSidType.BuiltinAdministratorsSid, Nothing)



      newACE = New System.Security.AccessControl.CommonAce(Security.AccessControl.AceFlags.None, _

                                                            Security.AccessControl.AceQualifier.AccessDenied, _

                                                            myAccessMask, _

                                                            mySid, _

                                                            False, _




      myACL.InsertAce(0, newACE)


      Dim mySD As New System.Security.AccessControl.RawSecurityDescriptor( _

         Security.AccessControl.ControlFlags.DiscretionaryAclPresent, _

         Nothing, _

         Nothing, _

         Nothing, _

         myACL)  ' acl goes here

      ' If you change "myACL" to nothing, it removes the SD/ACLs from the process

      ' which means everyone has full control--don't want that.



      Dim intptrACL As IntPtr = IntPtr.Zero

      Dim descACL(myACL.BinaryLength - 1) As Byte

      myACL.GetBinaryForm(descACL, 0)

      intptrACL = Marshal.AllocHGlobal(descACL.Length)

      Marshal.Copy(descACL, 0, intptrACL, descACL.Length)

      Dim testACL As New ACL

      testACL = Marshal.PtrToStructure(intptrACL, testACL.GetType)



      Dim intptrSD As IntPtr = IntPtr.Zero

      Dim desc(mySD.BinaryLength - 1) As Byte

      mySD.GetBinaryForm(desc, 0)

      intptrSD = Marshal.AllocHGlobal(desc.Length)

      Marshal.Copy(desc, 0, intptrSD, desc.Length)


      testSD = Marshal.PtrToStructure(intptrSD, testSD.GetType)


      iResult = SetKernelObjectSecurity(System.Diagnostics.Process.GetCurrentProcess.Handle, &H4, testSD)

      If (iResult = 0) Then

         ' Always returns "The Access control list (ACL) structure is invalid."

         LastError = Marshal.GetLastWin32Error

         MessageBox.Show(New System.ComponentModel.Win32Exception(LastError).ToString, "SetKernelObjectSecurity")


         MessageBox.Show("Worked", "SetKernelObjectSecurity")

      End If


      ' Clean up




   End Sub

End Class

Open in new window

Question by:kekal
  • 4
  • 3
LVL 41

Expert Comment

ID: 24880818
I'd recommend that you start with the retrieving the existing SD on the process first... that way it will "fill in the blanks" with all of the other parts of the DS that have nothing to do with the DACL
After you've got the "before" SD you can just modify the DACL and then write back the "after" SD

Author Comment

ID: 24881617
Thanks for the suggestion.  However, it will not work because the .NET framework does not give me any methods to get the SecurityDescriptor from a Process (unless Im missing something.)  Even if I could, I may run in to the same problem because I need to assign permissions to other users that do not have current ACLs.  For example, if Steve runs a process, I may need to give Sally (a non-administrator) the permission to kill it.

In the code above, I am using BuiltinAdministratorsSid as an example, but the SID may be from any user.  

I can get the code to Deny terminate to all users by calling the SetSecurityInfo API  (see code snippet below)&but this is only a partial solution since I may need to give the Terminate right (PROCESS_TERMINATE) to a other users.  Using the example above, I would create an explicit deny ACL for Steve and an explicit PROCESS_TERMINATE ACL for Sally.  


iResult = SetSecurityInfo(myProcessHandle, _



          Nothing, _

          Nothing, _

          intptrACL, _


Open in new window

LVL 41

Accepted Solution

graye earned 500 total points
ID: 24882264
Yes, so just use the GET version of GetSecurityInfo or GetKernelObjectSecurity to retrieve the existing SD
Take a look at the article as it describes the steps required by build or modify a DACL using the low-level APIs 
DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.


Author Comment

ID: 24884789
The information in the link provided only works for named objects, such as files.

The code (according to the return value) succeeds.  However, I don't know how to turn the IntPtrs in for the Sid, Dacl, and SD in to something useful, like a .NET RawACL object.

I know RawACL has a constructor that accepts a byte array.  However, I do not know how to turn the Dacl pointer in to a byte array.  Marshal.Copy should work for me, except that I do not know how long the DACL is!  

If you uncomment the AllocHGlobal lines, I get something back.
        Dim iResult As Integer

        Dim ipSidOwner, ipSidGroup, ipDacl, ipSacl, ipSD As New IntPtr

        ipSidGroup = IntPtr.Zero

        ipSidOwner = IntPtr.Zero

        ipDacl = IntPtr.Zero

        ipSacl = IntPtr.Zero

        ipSD = IntPtr.Zero


        'ipSidOwner = Marshal.AllocHGlobal(100)

        'ipDacl = Marshal.AllocHGlobal(100)

        'ipSD = Marshal.AllocHGlobal(100)

        iResult = GetSecurityInfo( _

                System.Diagnostics.Process.GetCurrentProcess.Handle, _



                ipSidOwner, _

                Nothing, _

                ipDacl, _

                Nothing, _


        DisplayError(iResult, "GetSecurityInfo", True)

Open in new window

LVL 41

Expert Comment

ID: 24885928
You don't need to "turn them into something useful"... they already are useful.
Looking back at that example, the flow of the program would be:
  • get the Security Descriptor and DACL
  • build an explicit access structure
  • merge this Explict Access with the existing DACL
  • write the new Security Descriptor/DACL back
  • clean up and go home


Author Comment

ID: 24888039 were right!!!  I couldn't see the forest for the trees and was making life too complicated.  It would be nice to use the managed objects, but that is not a requirement.  Thanks!

I did find that BuildExplicitAccessWithName does NOT appear to work on a x64 system (compiled with the Any CPU setting).  Using the code from the link above (without modification as a test), it produces an application crash when running outside of the VS IDE.  In the IDE in either debug or release modes, the application just exits without errors.

Author Comment

ID: 24976369

This solution may not work on x64 bit systems.  For more information, do an EE search on BuildExplicitAccessWithName.

I found that the app crash goes away if you turn optimizations off.  I'll try to post more here once (if) I found a solution.  We may have found a Microsoft bug.

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Help with solving error related to resources file 4 36
C# application error "Parameter Is Not Valid". 3 79
Word Directory is not in the drop down list 4 25
Syntax Error 2 46
This document covers how to connect to SQL Server and browse its contents.  It is meant for those new to Visual Studio and/or working with Microsoft SQL Server.  It is not a guide to building SQL Server database connections in your code.  This is mo…
This article shows how to deploy dynamic backgrounds to computers depending on the aspect ratio of display
This Micro Tutorial will give you a basic overview how to record your screen with Microsoft Expression Encoder. This program is still free and open for the public to download. This will be demonstrated using Microsoft Expression Encoder 4.
This tutorial gives a high-level tour of the interface of Marketo (a marketing automation tool to help businesses track and engage prospective customers and drive them to purchase). You will see the main areas including Marketing Activities, Design …

895 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now