Skip to content

Commit

Permalink
Extend GrantVmGroupAccess to support write/execute/all permissions
Browse files Browse the repository at this point in the history
Add masks for GENERIC_WRITE, GENERIC_EXECUTE and GENERIC_ALL and update
function signatures accordingly.
Update grantvmgroupaccess tool to support granting permissions from above.

Ignore various linter errors resurfaced after code copy-paste.
Remove mksyscall_windows.go and update old unit tests and cleanup helper
functions and packages used.

Add unit test coverage for new functionality.

Signed-off-by: Maksim An <maksiman@microsoft.com>
  • Loading branch information
anmaxvl committed Apr 22, 2022
1 parent fb706b3 commit 6b92044
Show file tree
Hide file tree
Showing 9 changed files with 348 additions and 1,140 deletions.
82 changes: 57 additions & 25 deletions internal/security/grantvmgroupaccess.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build windows
// +build windows

package security
Expand All @@ -19,25 +20,37 @@ type (
securityInformation uint32
trusteeForm uint32
trusteeType uint32
)

explicitAccess struct {
accessPermissions accessMask
accessMode accessMode
inheritance inheritMode
trustee trustee
}
type explicitAccess struct {
//nolint:structcheck
accessPermissions accessMask
//nolint:structcheck
accessMode accessMode
//nolint:structcheck
inheritance inheritMode
//nolint:structcheck
trustee trustee
}

trustee struct {
multipleTrustee *trustee
multipleTrusteeOperation int32
trusteeForm trusteeForm
trusteeType trusteeType
name uintptr
}
)
type trustee struct {
//nolint:unused,structcheck
multipleTrustee *trustee
//nolint:unused,structcheck
multipleTrusteeOperation int32
trusteeForm trusteeForm
trusteeType trusteeType
name uintptr
}

const (
accessMaskDesiredPermission accessMask = 1 << 31 // GENERIC_READ
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

Expand All @@ -56,18 +69,28 @@ const (
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
// 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 {
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 {
Expand All @@ -79,7 +102,9 @@ func GrantVmGroupAccess(name string) error {
if err != nil {
return err // Already wrapped
}
defer syscall.CloseHandle(fd)
defer func() {
_ = syscall.CloseHandle(fd)
}()

// Get the current DACL and Security Descriptor. Must defer LocalFree on success.
ot := objectTypeFileObject
Expand All @@ -89,15 +114,19 @@ func GrantVmGroupAccess(name string) error {
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 syscall.LocalFree((syscall.Handle)(unsafe.Pointer(sd)))
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(), origDACL)
newDACL, err := generateDACLWithAcesAdded(name, s.IsDir(), access, origDACL)
if err != nil {
return err // Already wrapped
}
defer syscall.LocalFree((syscall.Handle)(unsafe.Pointer(newDACL)))
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 {
Expand All @@ -110,7 +139,10 @@ func GrantVmGroupAccess(name string) error {
// 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 := syscall.StringToUTF16(name)
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)
Expand All @@ -126,7 +158,7 @@ func createFile(name string, isDir bool) (syscall.Handle, error) {

// 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, origDACL uintptr) (uintptr, error) {
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 {
Expand All @@ -139,8 +171,8 @@ func generateDACLWithAcesAdded(name string, isDir bool, origDACL uintptr) (uintp
}

eaArray := []explicitAccess{
explicitAccess{
accessPermissions: accessMaskDesiredPermission,
{
accessPermissions: desiredAccess,
accessMode: accessModeGrant,
inheritance: inheritance,
trustee: trustee{
Expand Down
Loading

0 comments on commit 6b92044

Please sign in to comment.