Skip to content

Commit

Permalink
Windows: revendor go-winio
Browse files Browse the repository at this point in the history
This fixes a variety of small bugs in layer handling and adds a new API
for acquiring privileges for the whole process.

Fixes moby#22404 (but only for new images -- existing images will need to be
re-pushed).

Signed-off-by: John Starks <[email protected]>
  • Loading branch information
jstarks committed May 13, 2016
1 parent 9de21de commit 6d40104
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 37 deletions.
2 changes: 1 addition & 1 deletion hack/vendor.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ source 'hack/.vendor-helpers.sh'
# the following lines are in sorted order, FYI
clone git github.com/Azure/go-ansiterm 388960b655244e76e24c75f48631564eaefade62
clone git github.com/Microsoft/hcsshim v0.2.2
clone git github.com/Microsoft/go-winio v0.3.0
clone git github.com/Microsoft/go-winio v0.3.4
clone git github.com/Sirupsen/logrus v0.9.0 # logrus is a common dependency among multiple deps
clone git github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
clone git github.com/go-check/check 03a4d9dcf2f92eae8e90ed42aa2656f63fdd0b14 https://github.com/cpuguy83/check.git
Expand Down
1 change: 1 addition & 0 deletions vendor/src/github.com/Microsoft/go-winio/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.exe
34 changes: 22 additions & 12 deletions vendor/src/github.com/Microsoft/go-winio/backuptar/tar.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package backuptar

import (
"encoding/base64"
"errors"
"fmt"
"io"
Expand Down Expand Up @@ -29,9 +30,10 @@ const (
)

const (
hdrFileAttributes = "fileattr"
hdrSecurityDescriptor = "sd"
hdrMountPoint = "mountpoint"
hdrFileAttributes = "fileattr"
hdrSecurityDescriptor = "sd"
hdrRawSecurityDescriptor = "rawsd"
hdrMountPoint = "mountpoint"
)

func writeZeroes(w io.Writer, count int64) error {
Expand Down Expand Up @@ -108,7 +110,7 @@ func BasicInfoHeader(name string, size int64, fileInfo *winio.FileBasicInfo) *ta
//
// MSWINDOWS.fileattr: The Win32 file attributes, as a decimal value
//
// MSWINDOWS.sd: The Win32 security descriptor, in SDDL (string) format
// MSWINDOWS.rawsd: The Win32 security descriptor, in raw binary format
//
// MSWINDOWS.mountpoint: If present, this is a mount point and not a symlink, even though the type is '2' (symlink)
func WriteTarFileFromBackupStream(t *tar.Writer, r io.Reader, name string, size int64, fileInfo *winio.FileBasicInfo) error {
Expand All @@ -133,11 +135,7 @@ func WriteTarFileFromBackupStream(t *tar.Writer, r io.Reader, name string, size
if err != nil {
return err
}
sddl, err := winio.SecurityDescriptorToSddl(sd)
if err != nil {
return err
}
hdr.Winheaders[hdrSecurityDescriptor] = sddl
hdr.Winheaders[hdrRawSecurityDescriptor] = base64.StdEncoding.EncodeToString(sd)

case winio.BackupReparseData:
hdr.Mode |= c_ISLNK
Expand Down Expand Up @@ -263,16 +261,28 @@ func FileInfoFromHeader(hdr *tar.Header) (name string, size int64, fileInfo *win
// tar file that was not processed, or io.EOF is there are no more.
func WriteBackupStreamFromTarFile(w io.Writer, t *tar.Reader, hdr *tar.Header) (*tar.Header, error) {
bw := winio.NewBackupStreamWriter(w)
var sd []byte
var err error
// Maintaining old SDDL-based behavior for backward compatibility. All new tar headers written
// by this library will have raw binary for the security descriptor.
if sddl, ok := hdr.Winheaders[hdrSecurityDescriptor]; ok {
sd, err := winio.SddlToSecurityDescriptor(sddl)
sd, err = winio.SddlToSecurityDescriptor(sddl)
if err != nil {
return nil, err
}
}
if sdraw, ok := hdr.Winheaders[hdrRawSecurityDescriptor]; ok {
sd, err = base64.StdEncoding.DecodeString(sdraw)
if err != nil {
return nil, err
}
}
if len(sd) != 0 {
bhdr := winio.BackupHeader{
Id: winio.BackupSecurity,
Size: int64(len(sd)),
}
err = bw.WriteHeader(&bhdr)
err := bw.WriteHeader(&bhdr)
if err != nil {
return nil, err
}
Expand All @@ -284,7 +294,7 @@ func WriteBackupStreamFromTarFile(w io.Writer, t *tar.Reader, hdr *tar.Header) (
if hdr.Typeflag == tar.TypeSymlink {
_, isMountPoint := hdr.Winheaders[hdrMountPoint]
rp := winio.ReparsePoint{
Target: hdr.Linkname,
Target: filepath.FromSlash(hdr.Linkname),
IsMountPoint: isMountPoint,
}
reparse := winio.EncodeReparsePoint(&rp)
Expand Down
79 changes: 60 additions & 19 deletions vendor/src/github.com/Microsoft/go-winio/privilege.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ import (
"encoding/binary"
"fmt"
"runtime"
"sync"
"syscall"
"unicode/utf16"

"golang.org/x/sys/windows"
)

//sys adjustTokenPrivileges(token syscall.Handle, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges
//sys adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges
//sys impersonateSelf(level uint32) (err error) = advapi32.ImpersonateSelf
//sys revertToSelf() (err error) = advapi32.RevertToSelf
//sys openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *syscall.Handle) (err error) = advapi32.OpenThreadToken
//sys openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) = advapi32.OpenThreadToken
//sys getCurrentThread() (h syscall.Handle) = GetCurrentThread
//sys lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) = advapi32.LookupPrivilegeValueW
//sys lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW
Expand All @@ -34,6 +37,12 @@ const (
securityDelegation
)

var (
privNames = make(map[string]uint64)
privNameMutex sync.Mutex
)

// PrivilegeError represents an error enabling privileges.
type PrivilegeError struct {
privileges []uint64
}
Expand All @@ -56,19 +65,16 @@ func (e *PrivilegeError) Error() string {
return s
}

// RunWithPrivilege enables a single privilege for a function call.
func RunWithPrivilege(name string, fn func() error) error {
return RunWithPrivileges([]string{name}, fn)
}

// RunWithPrivileges enables privileges for a function call.
func RunWithPrivileges(names []string, fn func() error) error {
var privileges []uint64
for _, name := range names {
p := uint64(0)
err := lookupPrivilegeValue("", name, &p)
if err != nil {
return err
}
privileges = append(privileges, p)
privileges, err := mapPrivileges(names)
if err != nil {
return err
}
runtime.LockOSThread()
defer runtime.UnlockOSThread()
Expand All @@ -84,7 +90,43 @@ func RunWithPrivileges(names []string, fn func() error) error {
return fn()
}

func adjustPrivileges(token syscall.Handle, privileges []uint64) error {
func mapPrivileges(names []string) ([]uint64, error) {
var privileges []uint64
privNameMutex.Lock()
defer privNameMutex.Unlock()
for _, name := range names {
p, ok := privNames[name]
if !ok {
err := lookupPrivilegeValue("", name, &p)
if err != nil {
return nil, err
}
privNames[name] = p
}
privileges = append(privileges, p)
}
return privileges, nil
}

// EnableProcessPrivileges enables privileges globally for the process.
func EnableProcessPrivileges(names []string) error {
privileges, err := mapPrivileges(names)
if err != nil {
return err
}

p, _ := windows.GetCurrentProcess()
var token windows.Token
err = windows.OpenProcessToken(p, windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, &token)
if err != nil {
return err
}

defer token.Close()
return adjustPrivileges(token, privileges)
}

func adjustPrivileges(token windows.Token, privileges []uint64) error {
var b bytes.Buffer
binary.Write(&b, binary.LittleEndian, uint32(len(privileges)))
for _, p := range privileges {
Expand Down Expand Up @@ -113,23 +155,22 @@ func getPrivilegeName(luid uint64) string {

var displayNameBuffer [256]uint16
displayBufSize := uint32(len(displayNameBuffer))
var langId uint32
err = lookupPrivilegeDisplayName("", &nameBuffer[0], &displayNameBuffer[0], &displayBufSize, &langId)
var langID uint32
err = lookupPrivilegeDisplayName("", &nameBuffer[0], &displayNameBuffer[0], &displayBufSize, &langID)
if err != nil {
return fmt.Sprintf("<unknown privilege %s>", utf16.Decode(nameBuffer[:bufSize]))
return fmt.Sprintf("<unknown privilege %s>", string(utf16.Decode(nameBuffer[:bufSize])))
}

return string(utf16.Decode(displayNameBuffer[:displayBufSize]))
}

func newThreadToken() (syscall.Handle, error) {
func newThreadToken() (windows.Token, error) {
err := impersonateSelf(securityImpersonation)
if err != nil {
panic(err)
return 0, err
}

var token syscall.Handle
var token windows.Token
err = openThreadToken(getCurrentThread(), syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, false, &token)
if err != nil {
rerr := revertToSelf()
Expand All @@ -141,10 +182,10 @@ func newThreadToken() (syscall.Handle, error) {
return token, nil
}

func releaseThreadToken(h syscall.Handle) {
func releaseThreadToken(h windows.Token) {
err := revertToSelf()
if err != nil {
panic(err)
}
syscall.Close(h)
h.Close()
}
2 changes: 1 addition & 1 deletion vendor/src/github.com/Microsoft/go-winio/reparse.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func EncodeReparsePoint(rp *ReparsePoint) []byte {
var ntTarget string
relative := false
if strings.HasPrefix(rp.Target, `\\?\`) {
ntTarget = rp.Target
ntTarget = `\??\` + rp.Target[4:]
} else if strings.HasPrefix(rp.Target, `\\`) {
ntTarget = `\??\UNC\` + rp.Target[2:]
} else if len(rp.Target) >= 2 && isDriveLetter(rp.Target[0]) && rp.Target[1] == ':' {
Expand Down
12 changes: 8 additions & 4 deletions vendor/src/github.com/Microsoft/go-winio/zsyscall.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

package winio

import "unsafe"
import "syscall"
import (
"syscall"
"unsafe"

"golang.org/x/sys/windows"
)

var _ unsafe.Pointer

Expand Down Expand Up @@ -300,7 +304,7 @@ func setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, si
return
}

func adjustTokenPrivileges(token syscall.Handle, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) {
func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) {
var _p0 uint32
if releaseAll {
_p0 = 1
Expand Down Expand Up @@ -343,7 +347,7 @@ func revertToSelf() (err error) {
return
}

func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *syscall.Handle) (err error) {
func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) {
var _p0 uint32
if openAsSelf {
_p0 = 1
Expand Down

0 comments on commit 6d40104

Please sign in to comment.