![dependabot[bot]](/assets/img/avatar_default.png)
Bumps [github.com/Microsoft/hcsshim](https://github.com/Microsoft/hcsshim) from 0.9.9 to 0.11.1. - [Release notes](https://github.com/Microsoft/hcsshim/releases) - [Commits](https://github.com/Microsoft/hcsshim/compare/v0.9.9...v0.11.1) --- updated-dependencies: - dependency-name: github.com/Microsoft/hcsshim dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
187 lines
5.5 KiB
Go
187 lines
5.5 KiB
Go
//go:build windows
|
|
// +build windows
|
|
|
|
package security
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
type (
|
|
accessMask uint32
|
|
accessMode uint32
|
|
desiredAccess uint32
|
|
inheritMode uint32
|
|
objectType uint32
|
|
shareMode uint32
|
|
securityInformation uint32
|
|
trusteeForm uint32
|
|
trusteeType uint32
|
|
)
|
|
|
|
type explicitAccess struct {
|
|
accessPermissions accessMask
|
|
accessMode accessMode
|
|
inheritance inheritMode
|
|
trustee trustee
|
|
}
|
|
|
|
type trustee struct {
|
|
multipleTrustee *trustee
|
|
multipleTrusteeOperation int32
|
|
trusteeForm trusteeForm
|
|
trusteeType trusteeType
|
|
name uintptr
|
|
}
|
|
|
|
const (
|
|
AccessMaskNone accessMask = 0
|
|
AccessMaskRead accessMask = 1 << 31 // GENERIC_READ
|
|
AccessMaskWrite accessMask = 1 << 30 // GENERIC_WRITE
|
|
AccessMaskExecute accessMask = 1 << 29 // GENERIC_EXECUTE
|
|
AccessMaskAll accessMask = 1 << 28 // GENERIC_ALL
|
|
|
|
accessMaskDesiredPermission = AccessMaskRead
|
|
|
|
accessModeGrant accessMode = 1
|
|
|
|
desiredAccessReadControl desiredAccess = 0x20000
|
|
desiredAccessWriteDac desiredAccess = 0x40000
|
|
|
|
gvmga = "GrantVmGroupAccess:"
|
|
|
|
inheritModeNoInheritance inheritMode = 0x0
|
|
inheritModeSubContainersAndObjectsInherit inheritMode = 0x3
|
|
|
|
objectTypeFileObject objectType = 0x1
|
|
|
|
securityInformationDACL securityInformation = 0x4
|
|
|
|
shareModeRead shareMode = 0x1
|
|
shareModeWrite shareMode = 0x2
|
|
|
|
//nolint:stylecheck // ST1003
|
|
sidVmGroup = "S-1-5-83-0"
|
|
|
|
trusteeFormIsSid trusteeForm = 0
|
|
|
|
trusteeTypeWellKnownGroup trusteeType = 5
|
|
)
|
|
|
|
// GrantVmGroupAccess sets the DACL for a specified file or directory to
|
|
// include Grant ACE entries for the VM Group SID. This is a golang re-
|
|
// implementation of the same function in vmcompute, just not exported in
|
|
// RS5. Which kind of sucks. Sucks a lot :/
|
|
func GrantVmGroupAccess(name string) error { //nolint:stylecheck // ST1003
|
|
return GrantVmGroupAccessWithMask(name, accessMaskDesiredPermission)
|
|
}
|
|
|
|
// GrantVmGroupAccessWithMask sets the desired DACL for a specified file or
|
|
// directory.
|
|
func GrantVmGroupAccessWithMask(name string, access accessMask) error { //nolint:stylecheck // ST1003
|
|
if access == 0 || access<<4 != 0 {
|
|
return fmt.Errorf("invalid access mask: 0x%08x", access)
|
|
}
|
|
// Stat (to determine if `name` is a directory).
|
|
s, err := os.Stat(name)
|
|
if err != nil {
|
|
return fmt.Errorf("%s os.Stat %s: %w", gvmga, name, err)
|
|
}
|
|
|
|
// Get a handle to the file/directory. Must defer Close on success.
|
|
fd, err := createFile(name, s.IsDir())
|
|
if err != nil {
|
|
return err // Already wrapped
|
|
}
|
|
defer func() {
|
|
_ = syscall.CloseHandle(fd)
|
|
}()
|
|
|
|
// Get the current DACL and Security Descriptor. Must defer LocalFree on success.
|
|
ot := objectTypeFileObject
|
|
si := securityInformationDACL
|
|
sd := uintptr(0)
|
|
origDACL := uintptr(0)
|
|
if err := getSecurityInfo(fd, uint32(ot), uint32(si), nil, nil, &origDACL, nil, &sd); err != nil {
|
|
return fmt.Errorf("%s GetSecurityInfo %s: %w", gvmga, name, err)
|
|
}
|
|
defer func() {
|
|
_, _ = syscall.LocalFree((syscall.Handle)(unsafe.Pointer(sd)))
|
|
}()
|
|
|
|
// Generate a new DACL which is the current DACL with the required ACEs added.
|
|
// Must defer LocalFree on success.
|
|
newDACL, err := generateDACLWithAcesAdded(name, s.IsDir(), access, origDACL)
|
|
if err != nil {
|
|
return err // Already wrapped
|
|
}
|
|
defer func() {
|
|
_, _ = syscall.LocalFree((syscall.Handle)(unsafe.Pointer(newDACL)))
|
|
}()
|
|
|
|
// And finally use SetSecurityInfo to apply the updated DACL.
|
|
if err := setSecurityInfo(fd, uint32(ot), uint32(si), uintptr(0), uintptr(0), newDACL, uintptr(0)); err != nil {
|
|
return fmt.Errorf("%s SetSecurityInfo %s: %w", gvmga, name, err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// createFile is a helper function to call [Nt]CreateFile to get a handle to
|
|
// the file or directory.
|
|
func createFile(name string, isDir bool) (syscall.Handle, error) {
|
|
namep, err := syscall.UTF16FromString(name)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("syscall.UTF16FromString %s: %w", name, err)
|
|
}
|
|
da := uint32(desiredAccessReadControl | desiredAccessWriteDac)
|
|
sm := uint32(shareModeRead | shareModeWrite)
|
|
fa := uint32(syscall.FILE_ATTRIBUTE_NORMAL)
|
|
if isDir {
|
|
fa = uint32(fa | syscall.FILE_FLAG_BACKUP_SEMANTICS)
|
|
}
|
|
fd, err := syscall.CreateFile(&namep[0], da, sm, nil, syscall.OPEN_EXISTING, fa, 0)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("%s syscall.CreateFile %s: %w", gvmga, name, err)
|
|
}
|
|
return fd, nil
|
|
}
|
|
|
|
// generateDACLWithAcesAdded generates a new DACL with the two needed ACEs added.
|
|
// The caller is responsible for LocalFree of the returned DACL on success.
|
|
func generateDACLWithAcesAdded(name string, isDir bool, desiredAccess accessMask, origDACL uintptr) (uintptr, error) {
|
|
// Generate pointers to the SIDs based on the string SIDs
|
|
sid, err := syscall.StringToSid(sidVmGroup)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("%s syscall.StringToSid %s %s: %w", gvmga, name, sidVmGroup, err)
|
|
}
|
|
|
|
inheritance := inheritModeNoInheritance
|
|
if isDir {
|
|
inheritance = inheritModeSubContainersAndObjectsInherit
|
|
}
|
|
|
|
eaArray := []explicitAccess{
|
|
{
|
|
accessPermissions: desiredAccess,
|
|
accessMode: accessModeGrant,
|
|
inheritance: inheritance,
|
|
trustee: trustee{
|
|
trusteeForm: trusteeFormIsSid,
|
|
trusteeType: trusteeTypeWellKnownGroup,
|
|
name: uintptr(unsafe.Pointer(sid)),
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedDACL := uintptr(0)
|
|
if err := setEntriesInAcl(uintptr(uint32(1)), uintptr(unsafe.Pointer(&eaArray[0])), origDACL, &modifiedDACL); err != nil {
|
|
return 0, fmt.Errorf("%s SetEntriesInAcl %s: %w", gvmga, name, err)
|
|
}
|
|
|
|
return modifiedDACL, nil
|
|
}
|