...

Source file src/github.com/Microsoft/hcsshim/internal/security/grantvmgroupaccess.go

Documentation: github.com/Microsoft/hcsshim/internal/security

     1  //go:build windows
     2  // +build windows
     3  
     4  package security
     5  
     6  import (
     7  	"fmt"
     8  	"os"
     9  	"syscall"
    10  	"unsafe"
    11  )
    12  
    13  type (
    14  	accessMask          uint32
    15  	accessMode          uint32
    16  	desiredAccess       uint32
    17  	inheritMode         uint32
    18  	objectType          uint32
    19  	shareMode           uint32
    20  	securityInformation uint32
    21  	trusteeForm         uint32
    22  	trusteeType         uint32
    23  )
    24  
    25  type explicitAccess struct {
    26  	accessPermissions accessMask
    27  	accessMode        accessMode
    28  	inheritance       inheritMode
    29  	trustee           trustee
    30  }
    31  
    32  type trustee struct {
    33  	multipleTrustee          *trustee
    34  	multipleTrusteeOperation int32
    35  	trusteeForm              trusteeForm
    36  	trusteeType              trusteeType
    37  	name                     uintptr
    38  }
    39  
    40  const (
    41  	AccessMaskNone    accessMask = 0
    42  	AccessMaskRead    accessMask = 1 << 31 // GENERIC_READ
    43  	AccessMaskWrite   accessMask = 1 << 30 // GENERIC_WRITE
    44  	AccessMaskExecute accessMask = 1 << 29 // GENERIC_EXECUTE
    45  	AccessMaskAll     accessMask = 1 << 28 // GENERIC_ALL
    46  
    47  	accessMaskDesiredPermission = AccessMaskRead
    48  
    49  	accessModeGrant accessMode = 1
    50  
    51  	desiredAccessReadControl desiredAccess = 0x20000
    52  	desiredAccessWriteDac    desiredAccess = 0x40000
    53  
    54  	gvmga = "GrantVmGroupAccess:"
    55  
    56  	inheritModeNoInheritance                  inheritMode = 0x0
    57  	inheritModeSubContainersAndObjectsInherit inheritMode = 0x3
    58  
    59  	objectTypeFileObject objectType = 0x1
    60  
    61  	securityInformationDACL securityInformation = 0x4
    62  
    63  	shareModeRead  shareMode = 0x1
    64  	shareModeWrite shareMode = 0x2
    65  
    66  	//nolint:stylecheck // ST1003
    67  	sidVmGroup = "S-1-5-83-0"
    68  
    69  	trusteeFormIsSid trusteeForm = 0
    70  
    71  	trusteeTypeWellKnownGroup trusteeType = 5
    72  )
    73  
    74  // GrantVmGroupAccess sets the DACL for a specified file or directory to
    75  // include Grant ACE entries for the VM Group SID. This is a golang re-
    76  // implementation of the same function in vmcompute, just not exported in
    77  // RS5. Which kind of sucks. Sucks a lot :/
    78  func GrantVmGroupAccess(name string) error { //nolint:stylecheck // ST1003
    79  	return GrantVmGroupAccessWithMask(name, accessMaskDesiredPermission)
    80  }
    81  
    82  // GrantVmGroupAccessWithMask sets the desired DACL for a specified file or
    83  // directory.
    84  func GrantVmGroupAccessWithMask(name string, access accessMask) error { //nolint:stylecheck // ST1003
    85  	if access == 0 || access<<4 != 0 {
    86  		return fmt.Errorf("invalid access mask: 0x%08x", access)
    87  	}
    88  	// Stat (to determine if `name` is a directory).
    89  	s, err := os.Stat(name)
    90  	if err != nil {
    91  		return fmt.Errorf("%s os.Stat %s: %w", gvmga, name, err)
    92  	}
    93  
    94  	// Get a handle to the file/directory. Must defer Close on success.
    95  	fd, err := createFile(name, s.IsDir())
    96  	if err != nil {
    97  		return err // Already wrapped
    98  	}
    99  	defer func() {
   100  		_ = syscall.CloseHandle(fd)
   101  	}()
   102  
   103  	// Get the current DACL and Security Descriptor. Must defer LocalFree on success.
   104  	ot := objectTypeFileObject
   105  	si := securityInformationDACL
   106  	sd := uintptr(0)
   107  	origDACL := uintptr(0)
   108  	if err := getSecurityInfo(fd, uint32(ot), uint32(si), nil, nil, &origDACL, nil, &sd); err != nil {
   109  		return fmt.Errorf("%s GetSecurityInfo %s: %w", gvmga, name, err)
   110  	}
   111  	defer func() {
   112  		_, _ = syscall.LocalFree((syscall.Handle)(unsafe.Pointer(sd)))
   113  	}()
   114  
   115  	// Generate a new DACL which is the current DACL with the required ACEs added.
   116  	// Must defer LocalFree on success.
   117  	newDACL, err := generateDACLWithAcesAdded(name, s.IsDir(), access, origDACL)
   118  	if err != nil {
   119  		return err // Already wrapped
   120  	}
   121  	defer func() {
   122  		_, _ = syscall.LocalFree((syscall.Handle)(unsafe.Pointer(newDACL)))
   123  	}()
   124  
   125  	// And finally use SetSecurityInfo to apply the updated DACL.
   126  	if err := setSecurityInfo(fd, uint32(ot), uint32(si), uintptr(0), uintptr(0), newDACL, uintptr(0)); err != nil {
   127  		return fmt.Errorf("%s SetSecurityInfo %s: %w", gvmga, name, err)
   128  	}
   129  
   130  	return nil
   131  }
   132  
   133  // createFile is a helper function to call [Nt]CreateFile to get a handle to
   134  // the file or directory.
   135  func createFile(name string, isDir bool) (syscall.Handle, error) {
   136  	namep, err := syscall.UTF16FromString(name)
   137  	if err != nil {
   138  		return 0, fmt.Errorf("syscall.UTF16FromString %s: %w", name, err)
   139  	}
   140  	da := uint32(desiredAccessReadControl | desiredAccessWriteDac)
   141  	sm := uint32(shareModeRead | shareModeWrite)
   142  	fa := uint32(syscall.FILE_ATTRIBUTE_NORMAL)
   143  	if isDir {
   144  		fa = uint32(fa | syscall.FILE_FLAG_BACKUP_SEMANTICS)
   145  	}
   146  	fd, err := syscall.CreateFile(&namep[0], da, sm, nil, syscall.OPEN_EXISTING, fa, 0)
   147  	if err != nil {
   148  		return 0, fmt.Errorf("%s syscall.CreateFile %s: %w", gvmga, name, err)
   149  	}
   150  	return fd, nil
   151  }
   152  
   153  // generateDACLWithAcesAdded generates a new DACL with the two needed ACEs added.
   154  // The caller is responsible for LocalFree of the returned DACL on success.
   155  func generateDACLWithAcesAdded(name string, isDir bool, desiredAccess accessMask, origDACL uintptr) (uintptr, error) {
   156  	// Generate pointers to the SIDs based on the string SIDs
   157  	sid, err := syscall.StringToSid(sidVmGroup)
   158  	if err != nil {
   159  		return 0, fmt.Errorf("%s syscall.StringToSid %s %s: %w", gvmga, name, sidVmGroup, err)
   160  	}
   161  
   162  	inheritance := inheritModeNoInheritance
   163  	if isDir {
   164  		inheritance = inheritModeSubContainersAndObjectsInherit
   165  	}
   166  
   167  	eaArray := []explicitAccess{
   168  		{
   169  			accessPermissions: desiredAccess,
   170  			accessMode:        accessModeGrant,
   171  			inheritance:       inheritance,
   172  			trustee: trustee{
   173  				trusteeForm: trusteeFormIsSid,
   174  				trusteeType: trusteeTypeWellKnownGroup,
   175  				name:        uintptr(unsafe.Pointer(sid)),
   176  			},
   177  		},
   178  	}
   179  
   180  	modifiedDACL := uintptr(0)
   181  	if err := setEntriesInAcl(uintptr(uint32(1)), uintptr(unsafe.Pointer(&eaArray[0])), origDACL, &modifiedDACL); err != nil {
   182  		return 0, fmt.Errorf("%s SetEntriesInAcl %s: %w", gvmga, name, err)
   183  	}
   184  
   185  	return modifiedDACL, nil
   186  }
   187  

View as plain text