security.cc: bug report, question and suggestion

Pierre A. Humblet Pierre.Humblet@ieee.org
Fri Jan 18 16:52:00 GMT 2002


At 06:38 PM 12/30/01 +0100, Corinna Vinschen wrote:
>On Sun, Dec 30, 2001 at 11:26:15AM -0500, Pierre A. Humblet wrote:
>> At 11:15 PM 12/29/01 +0100, Corinna Vinschen wrote:

>> While I am at it, here is another weird observation:
>> base case above: prog reads some registry key. Succeeds.
>> cases 1 and 2: prog reads some registry key. Access denied.
>> But if xxx has admins privilege, prog can read the registry in 
>> cases 1 and 2...
>> Can this be explained somehow? It's all on a standalone Win2000.
>
>Hmm, some debgging would help here, perhaps.
>
Hi Corinna

Well, I had to learn a few things to track this one.
Please cc me directly. Sorry about the length. 
What follows was observed on NT 4, it's somewhat 
different on Windows 2000.
The keys are related to the perflib, e.g.
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009"
and others.

Initially I thought that the error 5 ERROR_ACCESS_DENIED
meant that, following setuid(), the user did not have
query access to the key, even though he could open it
without problems. This guess was wrong.

The real problem is that following setuid(), the ACL (not default 
ACL) of the impersonation token (which is inherited from the
default ACL of the process token) makes the impersonation
token non-accessible by its user
(normally the user has full access to its token,
and it seems that setuid() should preserve that).
ERROR_ACCESS_DENIED is thus generated when some Microsoft
code tries to access the token while getting the key.

This is demonstrated in the debug.out attachment where I print 
the impersonation token, try to access the key (fail), 
then clear the token ACL and succeed reading the key.

I tried to patch security.cc, without success.
In the attached diff file I set an acl (actually I
reuse your default ACL) in a security descriptor "sd".
sd is pointed to by your security attribute "sa", which
is passed to DuplicateTokenEx() in create_token(). 
I also added a new call to SetKernelObjectSecurity(),
for good measure.
This runs without errors, but nothing happens.
I have no idea why. Any help or suggestions will be 
appreciated.

Here are four other things I noticed:

1) If setuid(gid) with a gid that doesn't exist, the
system silently sets the gid to "administrators". That
is not fail safe! 
The problem is that getgrgid() never fails. It should
have a flag to tell it whether it should default or not. 
[The default is fine when specifying a SET_ACCESS ACE]

2) my_token isn't closed in create_token()

3) Why is it necessary to set the PrimaryGroup in the
process token in setegid()? (That can fail silently).
Is that field ever read? I thought that PrimaryGroup 
only needs to be set in impersonation tokens, so that 
seteuid() can decide if an existing token can be
reused.

4) If in "cygrunsrv -u user ..."  the Cygwin and Windows 
user names differ, then the process will have the wrong
uid.

Entry in passwd (note Cygwin name != Windows name)
exim:unused_by_nt/2000/xp:1002:1005:daemon,U-PHumblet\Mail,S-1-5-21-21273915
03-1594901184-99485923-1002:/h
ome/Mail:/bin/bash

/> cygrunsrv -I test -u mail -e CYGWIN=ntsec -p /a.exe
Enter password of user `.\mail': 
Reenter, please: 
/> cygrunsrv -S test
/> head /var/log/test.log
CYGWIN = ntsec USERNAME = UNDEF UID = 500 GID = 513 PID = 619
<==INCORRECT UID/GID
/******************* Token Start ****************************/
/******************* Token User */  
Mail PHumblet SidTypeUser                           <=== CORRECT USER
S-1-5-21-2127391503-1594901184-99485923-1002        <=== CORRECT SID
 
Changed entry in passwd
mail:unused_by_nt/2000/xp:1002:1005:daemon,U-PHumblet\Mail,S-1-5-21-21273915
03-1594901184-99485923-1002:/home/Mail:/bin/bash

/> cygrunsrv -S test
/> head /var/log/test.log
CYGWIN = ntsec USERNAME = UNDEF UID = 1002 GID = 1005 PID = 654 <==
EVERYTHING OK
/******************* Token Start ****************************/
/******************* Token User */
Mail PHumblet SidTypeUser
S-1-5-21-2127391503-1594901184-99485923-1002


Pierre

-------------- next part --------------
--- security.cc.in	Wed Jan  9 20:35:04 2002
+++ security.cc	Tue Jan 15 18:58:46 2002
@@ -696,6 +696,18 @@
   return TRUE;
 }

+static BOOL
+get_sd (PSECURITY_DESCRIPTOR psd, PACL acl)
+{
+  if (!(InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION) &&
+        SetSecurityDescriptorDacl(psd, TRUE, acl, FALSE)))
+  {
+    __seterrno ();
+    return FALSE;
+  }
+  return TRUE;
+}
+
 HANDLE
 create_token (cygsid &usersid, cygsid &pgrpsid)
 {
@@ -710,7 +722,8 @@
     { sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE };
   OBJECT_ATTRIBUTES oa =
     { sizeof oa, 0, 0, 0, 0, &sqos };
-  SECURITY_ATTRIBUTES sa = { sizeof sa, NULL, TRUE };
+  SECURITY_DESCRIPTOR sd;
+  SECURITY_ATTRIBUTES sa = { sizeof sa, &sd, TRUE };
   LUID auth_luid = SYSTEM_LUID;
   LARGE_INTEGER exp = { QuadPart:0x7fffffffffffffffLL  };

@@ -813,10 +826,14 @@
     goto out;
   dacl.DefaultDacl = (PACL) acl_buf;

+  /* Create security info */
+  if (!get_sd (& sd, (PACL) acl_buf))
+	goto out;
+
   /* Let's be heroic... */
   ret = NtCreateToken (&token, TOKEN_ALL_ACCESS, &oa, TokenImpersonation,
 		       &auth_luid, &exp, &user, grps, privs, &owner, &pgrp,
-		       &dacl, &source);
+	           &dacl, &source);
   if (ret)
     set_errno (RtlNtStatusToDosError (ret));
   else if (GetLastError () == ERROR_PROC_NOT_FOUND)
@@ -827,9 +844,18 @@

   /* Convert to primary token. */
   if (!DuplicateTokenEx (token, TOKEN_ALL_ACCESS, &sa,
-			 SecurityImpersonation, TokenPrimary,
-			 &primary_token))
-    __seterrno ();
+						 SecurityImpersonation, TokenPrimary,
+						 &primary_token))
+    {
+      __seterrno ();
+      debug_printf ("DuplicateTokenEx failed.");
+    }
+  /* Convert to primary token. */
+  if (!SetKernelObjectSecurity(token, DACL_SECURITY_INFORMATION, &sd))
+    {
+      __seterrno ();
+      debug_printf ("SetKernelObjectSecurity failed.");
+    }

 out:
   if (old_priv_state >= 0)
-------------- next part --------------
**************************************************************************
Debug output demonstrating the token ACL problem
NT 4
**************************************************************************

1) For reference, here is process token of a normal unprivileged user.
The "SECURITY INFO" section shows that the user has full access
to its token. Such a user has no problem reading the perflib registry
key, even though it is non privileged.

/******************* Token Start ****************************/
/******************* Token User */
testuser PHumblet SidTypeUser
/******************* Token Type */
TokenPrimary
/******************* Token Source */
Token source User32
/******************* Token Security */
*************** SECURITY INFO START *************
Owner: testuser PHumblet SidTypeUser
Group: None PHumblet SidTypeGroup
ACL:
0 PHumblet\testuser (form==name)
SET_ACCESS Inher 0 TRUSTEE_IS_USER
TOKEN_ASSIGN_PRIMARY, TOKEN_DUPLICATE, TOKEN_IMPERSONATE, TOKEN_QUERY, TOKEN_QUERY_SOURCE, TOKEN_ADJUST_PRIVILEGES, TOKEN_ADJUST_GROUPS, TOKEN_ADJUST_DEFAULT, DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER,
1 NT AUTHORITY\SYSTEM (form==name)
SET_ACCESS Inher 0 TRUSTEE_IS_WELL_KNOWN_GROUP
TOKEN_ASSIGN_PRIMARY, TOKEN_DUPLICATE, TOKEN_IMPERSONATE, TOKEN_QUERY, TOKEN_QUERY_SOURCE, TOKEN_ADJUST_PRIVILEGES, TOKEN_ADJUST_GROUPS, TOKEN_ADJUST_DEFAULT, DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER,
*************** SECURITY INFO END *************
/******************* Token Groups */
None PHumblet SidTypeGroup
SE_GROUP_ENABLED, SE_GROUP_ENABLED_BY_DEFAULT, SE_GROUP_MANDATORY,
Everyone  SidTypeWellKnownGroup
SE_GROUP_ENABLED, SE_GROUP_ENABLED_BY_DEFAULT, SE_GROUP_MANDATORY,
Users BUILTIN SidTypeAlias
SE_GROUP_ENABLED, SE_GROUP_ENABLED_BY_DEFAULT, SE_GROUP_MANDATORY,
LookupAccountSid: error 1332
1 3 0 0 0 0 0 5 5 0
SE_GROUP_ENABLED, SE_GROUP_ENABLED_BY_DEFAULT, SE_GROUP_LOGON_ID, SE_GROUP_MANDATORY,
LOCAL  SidTypeWellKnownGroup
SE_GROUP_ENABLED, SE_GROUP_ENABLED_BY_DEFAULT, SE_GROUP_MANDATORY,
INTERACTIVE NT AUTHORITY SidTypeWellKnownGroup
SE_GROUP_ENABLED, SE_GROUP_ENABLED_BY_DEFAULT, SE_GROUP_MANDATORY,
Authenticated Users NT AUTHORITY SidTypeWellKnownGroup
SE_GROUP_ENABLED, SE_GROUP_ENABLED_BY_DEFAULT, SE_GROUP_MANDATORY,
/******************* Token restricted sids */
GetTokenInfo 87 300 172   <=== No restricted SIDs
/******************* Token privileges */
SeChangeNotifyPrivilege SE_PRIVILEGE_ENABLED, SE_PRIVILEGE_ENABLED_BY_DEFAULT,
SeShutdownPrivilege
/******************* Token Owner */
testuser PHumblet SidTypeUser
/******************* Token Primary group */
None PHumblet SidTypeGroup
/******************* Token DACL */
0 PHumblet\testuser (form==name)
SET_ACCESS Inher 0 TRUSTEE_IS_USER

1 NT AUTHORITY\SYSTEM (form==name)
SET_ACCESS Inher 0 TRUSTEE_IS_WELL_KNOWN_GROUP

/******************* Token End ****************************/




2) This is the impersonation token when both setgid(1005) and
setuid(1004) have been called.
Process was started by cygrunsrv under SYSTEM

/******************* Token Start ****************************/
/******************* Token User */
SYSTEM NT AUTHORITY SidTypeUser              <=== STRANGE LookupAccountSid()
S-1-5-21-2127391503-1594901184-99485923-1004 <=== CORRECT SID
/******************* Token Type */
TokenImpersonation
/******************* Token Source */
Token source Cygwin.1
/******************* Token Security */
*************** SECURITY INFO START *************
Owner: SYSTEM NT AUTHORITY SidTypeWellKnownGroup
S-1-5-18
Group: mailgrp PHumblet SidTypeAlias         <=== CORRECT GID
S-1-5-21-2127391503-1594901184-99485923-1005
ACL:                                         <=== 1004 has no access
0 NT AUTHORITY\SYSTEM (form==name)
SET_ACCESS Inher 0 TRUSTEE_IS_USER
TOKEN_ASSIGN_PRIMARY, TOKEN_DUPLICATE, TOKEN_IMPERSONATE, TOKEN_QUERY, TOKEN_QUERY_SOURCE, TOKEN_ADJUST_PRIVILEGES, TOKEN_ADJUST_GROUPS, TOKEN_ADJUST_DEFAULT, DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER,
1 BUILTIN\Administrators (form==name)
SET_ACCESS Inher 0 TRUSTEE_IS_ALIAS
TOKEN_QUERY, READ_CONTROL,
*************** SECURITY INFO END *************
/******************* Token Groups */
Everyone  SidTypeWellKnownGroup
S-1-1-0
SE_GROUP_ENABLED, SE_GROUP_ENABLED_BY_DEFAULT, SE_GROUP_MANDATORY,
Authenticated Users NT AUTHORITY SidTypeWellKnownGroup
S-1-5-11
SE_GROUP_ENABLED, SE_GROUP_ENABLED_BY_DEFAULT, SE_GROUP_MANDATORY,
Users BUILTIN SidTypeAlias
S-1-5-32-545
SE_GROUP_ENABLED, SE_GROUP_ENABLED_BY_DEFAULT, SE_GROUP_MANDATORY,
mailgrp PHumblet SidTypeAlias
S-1-5-21-2127391503-1594901184-99485923-1005
SE_GROUP_ENABLED, SE_GROUP_ENABLED_BY_DEFAULT, SE_GROUP_MANDATORY,
/******************* Token restricted sids */
GetTokenInfo 87     <=== No restricted SIDs
/******************* Token privileges */
SeChangeNotifyPrivilege SE_PRIVILEGE_ENABLED, SE_PRIVILEGE_ENABLED_BY_DEFAULT,
SeShutdownPrivilege SE_PRIVILEGE_ENABLED, SE_PRIVILEGE_ENABLED_BY_DEFAULT,
/******************* Token Owner */
SYSTEM NT AUTHORITY SidTypeUser
S-1-5-21-2127391503-1594901184-99485923-1004
/******************* Token Primary group */
mailgrp PHumblet SidTypeAlias
S-1-5-21-2127391503-1594901184-99485923-1005
/******************* Token DACL */
0 NT AUTHORITY\SYSTEM (form==name)
SET_ACCESS Inher 0 TRUSTEE_IS_USER

1 ?????????????????????????????????????????????????? (form==name)  <=== NO IDEA WHY THIS IS GARBLED
SET_ACCESS Inher 0 TRUSTEE_IS_USER                                 <=== WILL LOOK AT IT NEXT WEEK

/******************* Token End ****************************/
RegOpenKeyEx returned 0       <======= Success
RegQueryValueEx returned 5    <======= FAILS


3) Impersonation token, after I clear its ACL

InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
SetKernelObjectSecurity(ThreadHandle,
					DACL_SECURITY_INFORMATION, &sd);
(I did this for simplicity, I should set the ACL to something.
 Putting such code in seteuid(0 [syscalls.c] should work)

The thread is now able to read the registry key.

UNFORTUNATELY, after a fork() the ACL goes back to its
non-null value and the registry key can't be read again.
(This is not shown here).

/******************* Token Start ****************************/
/******************* Token User */
SYSTEM NT AUTHORITY SidTypeUser
S-1-5-21-2127391503-1594901184-99485923-1004
/******************* Token Type */
TokenImpersonation
/******************* Token Source */
Token source Cygwin.1
/******************* Token Security */
*************** SECURITY INFO START *************
Owner: SYSTEM NT AUTHORITY SidTypeWellKnownGroup
S-1-5-18
Group: mailgrp PHumblet SidTypeAlias
S-1-5-21-2127391503-1594901184-99485923-1005
ACL:                         <====== ACL was cleared
ACL is null
*************** SECURITY INFO END *************
/******************* Token Groups */
Everyone  SidTypeWellKnownGroup
S-1-1-0
SE_GROUP_ENABLED, SE_GROUP_ENABLED_BY_DEFAULT, SE_GROUP_MANDATORY,
Authenticated Users NT AUTHORITY SidTypeWellKnownGroup
S-1-5-11
SE_GROUP_ENABLED, SE_GROUP_ENABLED_BY_DEFAULT, SE_GROUP_MANDATORY,
Users BUILTIN SidTypeAlias
S-1-5-32-545
SE_GROUP_ENABLED, SE_GROUP_ENABLED_BY_DEFAULT, SE_GROUP_MANDATORY,
mailgrp PHumblet SidTypeAlias
S-1-5-21-2127391503-1594901184-99485923-1005
SE_GROUP_ENABLED, SE_GROUP_ENABLED_BY_DEFAULT, SE_GROUP_MANDATORY,
/******************* Token restricted sids */
GetTokenInfo 87 300 104
/******************* Token privileges */
SeChangeNotifyPrivilege SE_PRIVILEGE_ENABLED, SE_PRIVILEGE_ENABLED_BY_DEFAULT,
SeShutdownPrivilege SE_PRIVILEGE_ENABLED, SE_PRIVILEGE_ENABLED_BY_DEFAULT,
/******************* Token Owner */
SYSTEM NT AUTHORITY SidTypeUser
S-1-5-21-2127391503-1594901184-99485923-1004
/******************* Token Primary group */
mailgrp PHumblet SidTypeAlias
S-1-5-21-2127391503-1594901184-99485923-1005
/******************* Token DACL */
0 NT AUTHORITY\SYSTEM (form==name)
SET_ACCESS Inher 0 TRUSTEE_IS_USER

1 ?????????????????????????????????????????????????? (form==name)
SET_ACCESS Inher 0 TRUSTEE_IS_USER

/******************* Token End ****************************/
RegOpenKeyEx returned 0
RegQueryValueEx returned 0 <==== IT WORKS





4) For reference, here is the SECURITY INFO of the key
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009"

*************** SECURITY INFO START *************
Owner: Administrators BUILTIN SidTypeAlias
Group: LookupAccountSid: error 1332
1 5 0 0 0 0 0 5 15 0
ACL:
0 Everyone (form==name)
SET_ACCESS Inher 2 TRUSTEE_IS_WELL_KNOWN_GROUP
KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, READ_CONTROL,
1 BUILTIN\Administrators (form==name)
SET_ACCESS Inher 2 TRUSTEE_IS_ALIAS
KEY_QUERY_VALUE, KEY_SET_VALUE, KEY_CREATE_SUB_KEY, KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, KEY_CREATE_LINK, DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER,
2 NT AUTHORITY\SYSTEM (form==name)
SET_ACCESS Inher 2 TRUSTEE_IS_USER
KEY_QUERY_VALUE, KEY_SET_VALUE, KEY_CREATE_SUB_KEY, KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, KEY_CREATE_LINK, DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER,
3 CREATOR OWNER (form==name)
SET_ACCESS Inher 2 TRUSTEE_IS_WELL_KNOWN_GROUP
KEY_QUERY_VALUE, KEY_SET_VALUE, KEY_CREATE_SUB_KEY, KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, KEY_CREATE_LINK, DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER,
*************** SECURITY INFO END *************

-------------- next part --------------
--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Bug reporting:         http://cygwin.com/bugs.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/


More information about the Cygwin mailing list