diff --git a/internal/conpty/conpty.go b/internal/conpty/conpty.go new file mode 100644 index 0000000000..1e19b676b4 --- /dev/null +++ b/internal/conpty/conpty.go @@ -0,0 +1,153 @@ +package conpty + +import ( + "errors" + "fmt" + "os" + "sync" + "unsafe" + + "github.com/Microsoft/hcsshim/internal/winapi" + "golang.org/x/sys/windows" +) + +var ( + errClosedConPty = errors.New("pseudo console is closed") + errNotInitialized = errors.New("pseudo console hasn't been initialized") +) + +// CPty is a wrapper around a Windows PseudoConsole handle. Create a new instance by calling `New()`. +type CPty struct { + // handleLock guards hPc + handleLock sync.RWMutex + // hpc is the pseudo console handle + hpc windows.Handle + // inPipe and outPipe are our end of the pipes to read/write to the pseudo console. + inPipe *os.File + outPipe *os.File +} + +// New returns a new `CPty` object. This object is not ready for IO until `UpdateProcThreadAttribute` is called and a process has been started. +func New(columns, rows int16, flags uint32) (*CPty, error) { + // First we need to make both ends of the conpty's pipes, two to get passed into a process to use as input/output, and two for us to keep to + // make use of this data. + ptyIn, inPipeOurs, err := os.Pipe() + if err != nil { + return nil, fmt.Errorf("failed to create pipes for pseudo console: %w", err) + } + + outPipeOurs, ptyOut, err := os.Pipe() + if err != nil { + return nil, fmt.Errorf("failed to create pipes for pseudo console: %w", err) + } + + var hpc windows.Handle + coord := windows.Coord{X: columns, Y: rows} + err = winapi.CreatePseudoConsole(coord, windows.Handle(ptyIn.Fd()), windows.Handle(ptyOut.Fd()), 0, &hpc) + if err != nil { + return nil, fmt.Errorf("failed to create pseudo console: %w", err) + } + + // The pty's end of its pipes can be closed here without worry. They're duped into the conhost + // that will be launched and will be released on a call to ClosePseudoConsole() (Close() on the CPty object). + if err := ptyOut.Close(); err != nil { + return nil, fmt.Errorf("failed to close pseudo console handle: %w", err) + } + if err := ptyIn.Close(); err != nil { + return nil, fmt.Errorf("failed to close pseudo console handle: %w", err) + } + + return &CPty{ + hpc: hpc, + inPipe: inPipeOurs, + outPipe: outPipeOurs, + }, nil +} + +// UpdateProcThreadAttribute updates the passed in attribute list to contain the entry necessary for use with +// CreateProcess. +func (c *CPty) UpdateProcThreadAttribute(attributeList *winapi.ProcThreadAttributeList) error { + c.handleLock.RLock() + defer c.handleLock.RUnlock() + + if c.hpc == 0 { + return errClosedConPty + } + + err := winapi.UpdateProcThreadAttribute( + attributeList, + 0, + winapi.PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, + unsafe.Pointer(c.hpc), + unsafe.Sizeof(c.hpc), + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to update proc thread attributes for pseudo console: %w", err) + } + return nil +} + +// Resize resizes the internal buffers of the pseudo console to the passed in size +func (c *CPty) Resize(columns, rows int16) error { + c.handleLock.RLock() + defer c.handleLock.RUnlock() + + if c.hpc == 0 { + return errClosedConPty + } + + coord := windows.Coord{X: columns, Y: rows} + if err := winapi.ResizePseudoConsole(c.hpc, coord); err != nil { + return fmt.Errorf("failed to resize pseudo console: %w", err) + } + return nil +} + +// Close closes the pseudo-terminal and cleans up all attached resources +func (c *CPty) Close() error { + c.handleLock.Lock() + defer c.handleLock.Unlock() + + if c.hpc == 0 { + return errClosedConPty + } + + // Close the pseudo console, set the handle to 0 to invalidate this object and then close the side of the pipes that we own. + winapi.ClosePseudoConsole(c.hpc) + c.hpc = 0 + if err := c.inPipe.Close(); err != nil { + return fmt.Errorf("failed to close pseudo console input pipe: %w", err) + } + if err := c.outPipe.Close(); err != nil { + return fmt.Errorf("failed to close pseudo console output pipe: %w", err) + } + return nil +} + +// OutPipe returns the output pipe of the pseudo console. +func (c *CPty) OutPipe() *os.File { + return c.outPipe +} + +// InPipe returns the input pipe of the pseudo console. +func (c *CPty) InPipe() *os.File { + return c.inPipe +} + +// Write writes the contents of `buf` to the pseudo console. Returns the number of bytes written and an error if there is one. +func (c *CPty) Write(buf []byte) (int, error) { + if c.inPipe == nil { + return 0, errNotInitialized + } + return c.inPipe.Write(buf) +} + +// Read reads from the pseudo console into `buf`. Returns the number of bytes read and an error if there is one. +func (c *CPty) Read(buf []byte) (int, error) { + if c.outPipe == nil { + return 0, errNotInitialized + } + return c.outPipe.Read(buf) +} diff --git a/internal/winapi/console.go b/internal/winapi/console.go new file mode 100644 index 0000000000..95c710fd97 --- /dev/null +++ b/internal/winapi/console.go @@ -0,0 +1,42 @@ +package winapi + +import ( + "unsafe" + + "golang.org/x/sys/windows" +) + +const PSEUDOCONSOLE_INHERIT_CURSOR = 0x1 + +// CreatePseudoConsole creates a windows pseudo console. +func CreatePseudoConsole(size windows.Coord, hInput windows.Handle, hOutput windows.Handle, dwFlags uint32, hpcon *windows.Handle) error { + // We need this wrapper as the function takes a COORD struct and not a pointer to one, so we need to cast to something beforehand. + return createPseudoConsole(*((*uint32)(unsafe.Pointer(&size))), hInput, hOutput, 0, hpcon) +} + +func ResizePseudoConsole(hpcon windows.Handle, size windows.Coord) error { + return resizePseudoConsole(hpcon, *((*uint32)(unsafe.Pointer(&size)))) +} + +// HRESULT WINAPI CreatePseudoConsole( +// _In_ COORD size, +// _In_ HANDLE hInput, +// _In_ HANDLE hOutput, +// _In_ DWORD dwFlags, +// _Out_ HPCON* phPC +// ); +// +//sys createPseudoConsole(size uint32, hInput windows.Handle, hOutput windows.Handle, dwFlags uint32, hpcon *windows.Handle) (hr error) = kernel32.CreatePseudoConsole + +// void WINAPI ClosePseudoConsole( +// _In_ HPCON hPC +// ); +// +//sys ClosePseudoConsole(hpc windows.Handle) = kernel32.ClosePseudoConsole + +// HRESULT WINAPI ResizePseudoConsole( +// _In_ HPCON hPC , +// _In_ COORD size +// ); +// +//sys resizePseudoConsole(hPc windows.Handle, size uint32) (hr error) = kernel32.ResizePseudoConsole diff --git a/internal/winapi/process.go b/internal/winapi/process.go index b87068327c..977df04b87 100644 --- a/internal/winapi/process.go +++ b/internal/winapi/process.go @@ -1,10 +1,80 @@ package winapi +import ( + "errors" + "unsafe" + + "golang.org/x/sys/windows" +) + const PROCESS_ALL_ACCESS uint32 = 2097151 -// DWORD GetProcessImageFileNameW( -// HANDLE hProcess, -// LPWSTR lpImageFileName, -// DWORD nSize +const ( + PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE = 0x20016 + PROC_THREAD_ATTRIBUTE_JOB_LIST = 0x2000D +) + +type ProcThreadAttributeList struct { + _ [1]byte +} + +// typedef struct _STARTUPINFOEXW { +// STARTUPINFOW StartupInfo; +// LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList; +// } STARTUPINFOEXW, *LPSTARTUPINFOEXW; +type StartupInfoEx struct { + // This is a recreation of the same binding from the stdlib. The x/sys/windows variant for whatever reason + // doesn't work when updating the list for the pseudo console attribute. It has the process immediately exit + // with exit code 0xc0000142 shortly after start. + windows.StartupInfo + ProcThreadAttributeList *ProcThreadAttributeList +} + +// NewProcThreadAttributeList allocates a new ProcThreadAttributeList, with +// the requested maximum number of attributes. This must be cleaned up by calling +// DeleteProcThreadAttributeList. +func NewProcThreadAttributeList(maxAttrCount uint32) (*ProcThreadAttributeList, error) { + var size uintptr + err := InitializeProcThreadAttributeList(nil, maxAttrCount, 0, &size) + if err != windows.ERROR_INSUFFICIENT_BUFFER { + if err == nil { + return nil, errors.New("unable to query buffer size from InitializeProcThreadAttributeList") + } + return nil, err + } + al := (*ProcThreadAttributeList)(unsafe.Pointer(&make([]byte, size)[0])) + err = InitializeProcThreadAttributeList(al, maxAttrCount, 0, &size) + if err != nil { + return nil, err + } + return al, nil +} + +// BOOL InitializeProcThreadAttributeList( +// [out, optional] LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList, +// [in] DWORD dwAttributeCount, +// DWORD dwFlags, +// [in, out] PSIZE_T lpSize // ); -//sys GetProcessImageFileName(hProcess windows.Handle, imageFileName *uint16, nSize uint32) (size uint32, err error) = kernel32.GetProcessImageFileNameW +// +//sys InitializeProcThreadAttributeList(lpAttributeList *ProcThreadAttributeList, dwAttributeCount uint32, dwFlags uint32, lpSize *uintptr) (err error) = kernel32.InitializeProcThreadAttributeList + +// void DeleteProcThreadAttributeList( +// [in, out] LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList +// ); +// +//sys DeleteProcThreadAttributeList(lpAttributeList *ProcThreadAttributeList) = kernel32.DeleteProcThreadAttributeList + +// BOOL UpdateProcThreadAttribute( +// [in, out] LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList, +// [in] DWORD dwFlags, +// [in] DWORD_PTR Attribute, +// [in] PVOID lpValue, +// [in] SIZE_T cbSize, +// [out, optional] PVOID lpPreviousValue, +// [in, optional] PSIZE_T lpReturnSize +// ); +// +//sys UpdateProcThreadAttribute(lpAttributeList *ProcThreadAttributeList, dwFlags uint32, attribute uintptr, lpValue unsafe.Pointer, cbSize uintptr, lpPreviousValue unsafe.Pointer, lpReturnSize *uintptr) (err error) = kernel32.UpdateProcThreadAttribute + +//sys CreateProcessAsUser(token windows.Token, appName *uint16, commandLine *uint16, procSecurity *windows.SecurityAttributes, threadSecurity *windows.SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *windows.StartupInfo, outProcInfo *windows.ProcessInformation) (err error) = advapi32.CreateProcessAsUserW diff --git a/internal/winapi/winapi.go b/internal/winapi/winapi.go index ec88c0d212..1d4ba3c4f8 100644 --- a/internal/winapi/winapi.go +++ b/internal/winapi/winapi.go @@ -2,4 +2,4 @@ // be thought of as an extension to golang.org/x/sys/windows. package winapi -//go:generate go run ..\..\mksyscall_windows.go -output zsyscall_windows.go system.go net.go path.go thread.go iocp.go jobobject.go logon.go memory.go process.go processor.go devices.go filesystem.go errors.go +//go:generate go run ..\..\mksyscall_windows.go -output zsyscall_windows.go console.go system.go net.go path.go thread.go iocp.go jobobject.go logon.go memory.go process.go processor.go devices.go filesystem.go errors.go diff --git a/internal/winapi/zsyscall_windows.go b/internal/winapi/zsyscall_windows.go index 59ddee274e..caf54c82c9 100644 --- a/internal/winapi/zsyscall_windows.go +++ b/internal/winapi/zsyscall_windows.go @@ -37,12 +37,15 @@ func errnoErr(e syscall.Errno) error { } var ( + modkernel32 = windows.NewLazySystemDLL("kernel32.dll") modntdll = windows.NewLazySystemDLL("ntdll.dll") modiphlpapi = windows.NewLazySystemDLL("iphlpapi.dll") - modkernel32 = windows.NewLazySystemDLL("kernel32.dll") modadvapi32 = windows.NewLazySystemDLL("advapi32.dll") modcfgmgr32 = windows.NewLazySystemDLL("cfgmgr32.dll") + procCreatePseudoConsole = modkernel32.NewProc("CreatePseudoConsole") + procClosePseudoConsole = modkernel32.NewProc("ClosePseudoConsole") + procResizePseudoConsole = modkernel32.NewProc("ResizePseudoConsole") procNtQuerySystemInformation = modntdll.NewProc("NtQuerySystemInformation") procSetJobCompartmentId = modiphlpapi.NewProc("SetJobCompartmentId") procSearchPathW = modkernel32.NewProc("SearchPathW") @@ -58,7 +61,10 @@ var ( procLogonUserW = modadvapi32.NewProc("LogonUserW") procLocalAlloc = modkernel32.NewProc("LocalAlloc") procLocalFree = modkernel32.NewProc("LocalFree") - procGetProcessImageFileNameW = modkernel32.NewProc("GetProcessImageFileNameW") + procInitializeProcThreadAttributeList = modkernel32.NewProc("InitializeProcThreadAttributeList") + procDeleteProcThreadAttributeList = modkernel32.NewProc("DeleteProcThreadAttributeList") + procUpdateProcThreadAttribute = modkernel32.NewProc("UpdateProcThreadAttribute") + procCreateProcessAsUserW = modadvapi32.NewProc("CreateProcessAsUserW") procGetActiveProcessorCount = modkernel32.NewProc("GetActiveProcessorCount") procCM_Get_Device_ID_List_SizeA = modcfgmgr32.NewProc("CM_Get_Device_ID_List_SizeA") procCM_Get_Device_ID_ListA = modcfgmgr32.NewProc("CM_Get_Device_ID_ListA") @@ -71,6 +77,33 @@ var ( procRtlNtStatusToDosError = modntdll.NewProc("RtlNtStatusToDosError") ) +func createPseudoConsole(size uint32, hInput windows.Handle, hOutput windows.Handle, dwFlags uint32, hpcon *windows.Handle) (hr error) { + r0, _, _ := syscall.Syscall6(procCreatePseudoConsole.Addr(), 5, uintptr(size), uintptr(hInput), uintptr(hOutput), uintptr(dwFlags), uintptr(unsafe.Pointer(hpcon)), 0) + if int32(r0) < 0 { + if r0&0x1fff0000 == 0x00070000 { + r0 &= 0xffff + } + hr = syscall.Errno(r0) + } + return +} + +func ClosePseudoConsole(hpc windows.Handle) { + syscall.Syscall(procClosePseudoConsole.Addr(), 1, uintptr(hpc), 0, 0) + return +} + +func resizePseudoConsole(hPc windows.Handle, size uint32) (hr error) { + r0, _, _ := syscall.Syscall(procResizePseudoConsole.Addr(), 2, uintptr(hPc), uintptr(size), 0) + if int32(r0) < 0 { + if r0&0x1fff0000 == 0x00070000 { + r0 &= 0xffff + } + hr = syscall.Errno(r0) + } + return +} + func NtQuerySystemInformation(systemInfoClass int, systemInformation uintptr, systemInfoLength uint32, returnLength *uint32) (status uint32) { r0, _, _ := syscall.Syscall6(procNtQuerySystemInformation.Addr(), 4, uintptr(systemInfoClass), uintptr(systemInformation), uintptr(systemInfoLength), uintptr(unsafe.Pointer(returnLength)), 0, 0) status = uint32(r0) @@ -227,10 +260,44 @@ func LocalFree(ptr uintptr) { return } -func GetProcessImageFileName(hProcess windows.Handle, imageFileName *uint16, nSize uint32) (size uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetProcessImageFileNameW.Addr(), 3, uintptr(hProcess), uintptr(unsafe.Pointer(imageFileName)), uintptr(nSize)) - size = uint32(r0) - if size == 0 { +func InitializeProcThreadAttributeList(lpAttributeList *ProcThreadAttributeList, dwAttributeCount uint32, dwFlags uint32, lpSize *uintptr) (err error) { + r1, _, e1 := syscall.Syscall6(procInitializeProcThreadAttributeList.Addr(), 4, uintptr(unsafe.Pointer(lpAttributeList)), uintptr(dwAttributeCount), uintptr(dwFlags), uintptr(unsafe.Pointer(lpSize)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func DeleteProcThreadAttributeList(lpAttributeList *ProcThreadAttributeList) { + syscall.Syscall(procDeleteProcThreadAttributeList.Addr(), 1, uintptr(unsafe.Pointer(lpAttributeList)), 0, 0) + return +} + +func UpdateProcThreadAttribute(lpAttributeList *ProcThreadAttributeList, dwFlags uint32, attribute uintptr, lpValue unsafe.Pointer, cbSize uintptr, lpPreviousValue unsafe.Pointer, lpReturnSize *uintptr) (err error) { + r1, _, e1 := syscall.Syscall9(procUpdateProcThreadAttribute.Addr(), 7, uintptr(unsafe.Pointer(lpAttributeList)), uintptr(dwFlags), uintptr(attribute), uintptr(lpValue), uintptr(cbSize), uintptr(lpPreviousValue), uintptr(unsafe.Pointer(lpReturnSize)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CreateProcessAsUser(token windows.Token, appName *uint16, commandLine *uint16, procSecurity *windows.SecurityAttributes, threadSecurity *windows.SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *windows.StartupInfo, outProcInfo *windows.ProcessInformation) (err error) { + var _p0 uint32 + if inheritHandles { + _p0 = 1 + } else { + _p0 = 0 + } + r1, _, e1 := syscall.Syscall12(procCreateProcessAsUserW.Addr(), 11, uintptr(token), uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0) + if r1 == 0 { if e1 != 0 { err = errnoErr(e1) } else { diff --git a/test/vendor/github.com/Microsoft/hcsshim/internal/winapi/console.go b/test/vendor/github.com/Microsoft/hcsshim/internal/winapi/console.go new file mode 100644 index 0000000000..95c710fd97 --- /dev/null +++ b/test/vendor/github.com/Microsoft/hcsshim/internal/winapi/console.go @@ -0,0 +1,42 @@ +package winapi + +import ( + "unsafe" + + "golang.org/x/sys/windows" +) + +const PSEUDOCONSOLE_INHERIT_CURSOR = 0x1 + +// CreatePseudoConsole creates a windows pseudo console. +func CreatePseudoConsole(size windows.Coord, hInput windows.Handle, hOutput windows.Handle, dwFlags uint32, hpcon *windows.Handle) error { + // We need this wrapper as the function takes a COORD struct and not a pointer to one, so we need to cast to something beforehand. + return createPseudoConsole(*((*uint32)(unsafe.Pointer(&size))), hInput, hOutput, 0, hpcon) +} + +func ResizePseudoConsole(hpcon windows.Handle, size windows.Coord) error { + return resizePseudoConsole(hpcon, *((*uint32)(unsafe.Pointer(&size)))) +} + +// HRESULT WINAPI CreatePseudoConsole( +// _In_ COORD size, +// _In_ HANDLE hInput, +// _In_ HANDLE hOutput, +// _In_ DWORD dwFlags, +// _Out_ HPCON* phPC +// ); +// +//sys createPseudoConsole(size uint32, hInput windows.Handle, hOutput windows.Handle, dwFlags uint32, hpcon *windows.Handle) (hr error) = kernel32.CreatePseudoConsole + +// void WINAPI ClosePseudoConsole( +// _In_ HPCON hPC +// ); +// +//sys ClosePseudoConsole(hpc windows.Handle) = kernel32.ClosePseudoConsole + +// HRESULT WINAPI ResizePseudoConsole( +// _In_ HPCON hPC , +// _In_ COORD size +// ); +// +//sys resizePseudoConsole(hPc windows.Handle, size uint32) (hr error) = kernel32.ResizePseudoConsole diff --git a/test/vendor/github.com/Microsoft/hcsshim/internal/winapi/process.go b/test/vendor/github.com/Microsoft/hcsshim/internal/winapi/process.go index b87068327c..977df04b87 100644 --- a/test/vendor/github.com/Microsoft/hcsshim/internal/winapi/process.go +++ b/test/vendor/github.com/Microsoft/hcsshim/internal/winapi/process.go @@ -1,10 +1,80 @@ package winapi +import ( + "errors" + "unsafe" + + "golang.org/x/sys/windows" +) + const PROCESS_ALL_ACCESS uint32 = 2097151 -// DWORD GetProcessImageFileNameW( -// HANDLE hProcess, -// LPWSTR lpImageFileName, -// DWORD nSize +const ( + PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE = 0x20016 + PROC_THREAD_ATTRIBUTE_JOB_LIST = 0x2000D +) + +type ProcThreadAttributeList struct { + _ [1]byte +} + +// typedef struct _STARTUPINFOEXW { +// STARTUPINFOW StartupInfo; +// LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList; +// } STARTUPINFOEXW, *LPSTARTUPINFOEXW; +type StartupInfoEx struct { + // This is a recreation of the same binding from the stdlib. The x/sys/windows variant for whatever reason + // doesn't work when updating the list for the pseudo console attribute. It has the process immediately exit + // with exit code 0xc0000142 shortly after start. + windows.StartupInfo + ProcThreadAttributeList *ProcThreadAttributeList +} + +// NewProcThreadAttributeList allocates a new ProcThreadAttributeList, with +// the requested maximum number of attributes. This must be cleaned up by calling +// DeleteProcThreadAttributeList. +func NewProcThreadAttributeList(maxAttrCount uint32) (*ProcThreadAttributeList, error) { + var size uintptr + err := InitializeProcThreadAttributeList(nil, maxAttrCount, 0, &size) + if err != windows.ERROR_INSUFFICIENT_BUFFER { + if err == nil { + return nil, errors.New("unable to query buffer size from InitializeProcThreadAttributeList") + } + return nil, err + } + al := (*ProcThreadAttributeList)(unsafe.Pointer(&make([]byte, size)[0])) + err = InitializeProcThreadAttributeList(al, maxAttrCount, 0, &size) + if err != nil { + return nil, err + } + return al, nil +} + +// BOOL InitializeProcThreadAttributeList( +// [out, optional] LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList, +// [in] DWORD dwAttributeCount, +// DWORD dwFlags, +// [in, out] PSIZE_T lpSize // ); -//sys GetProcessImageFileName(hProcess windows.Handle, imageFileName *uint16, nSize uint32) (size uint32, err error) = kernel32.GetProcessImageFileNameW +// +//sys InitializeProcThreadAttributeList(lpAttributeList *ProcThreadAttributeList, dwAttributeCount uint32, dwFlags uint32, lpSize *uintptr) (err error) = kernel32.InitializeProcThreadAttributeList + +// void DeleteProcThreadAttributeList( +// [in, out] LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList +// ); +// +//sys DeleteProcThreadAttributeList(lpAttributeList *ProcThreadAttributeList) = kernel32.DeleteProcThreadAttributeList + +// BOOL UpdateProcThreadAttribute( +// [in, out] LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList, +// [in] DWORD dwFlags, +// [in] DWORD_PTR Attribute, +// [in] PVOID lpValue, +// [in] SIZE_T cbSize, +// [out, optional] PVOID lpPreviousValue, +// [in, optional] PSIZE_T lpReturnSize +// ); +// +//sys UpdateProcThreadAttribute(lpAttributeList *ProcThreadAttributeList, dwFlags uint32, attribute uintptr, lpValue unsafe.Pointer, cbSize uintptr, lpPreviousValue unsafe.Pointer, lpReturnSize *uintptr) (err error) = kernel32.UpdateProcThreadAttribute + +//sys CreateProcessAsUser(token windows.Token, appName *uint16, commandLine *uint16, procSecurity *windows.SecurityAttributes, threadSecurity *windows.SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *windows.StartupInfo, outProcInfo *windows.ProcessInformation) (err error) = advapi32.CreateProcessAsUserW diff --git a/test/vendor/github.com/Microsoft/hcsshim/internal/winapi/winapi.go b/test/vendor/github.com/Microsoft/hcsshim/internal/winapi/winapi.go index ec88c0d212..1d4ba3c4f8 100644 --- a/test/vendor/github.com/Microsoft/hcsshim/internal/winapi/winapi.go +++ b/test/vendor/github.com/Microsoft/hcsshim/internal/winapi/winapi.go @@ -2,4 +2,4 @@ // be thought of as an extension to golang.org/x/sys/windows. package winapi -//go:generate go run ..\..\mksyscall_windows.go -output zsyscall_windows.go system.go net.go path.go thread.go iocp.go jobobject.go logon.go memory.go process.go processor.go devices.go filesystem.go errors.go +//go:generate go run ..\..\mksyscall_windows.go -output zsyscall_windows.go console.go system.go net.go path.go thread.go iocp.go jobobject.go logon.go memory.go process.go processor.go devices.go filesystem.go errors.go diff --git a/test/vendor/github.com/Microsoft/hcsshim/internal/winapi/zsyscall_windows.go b/test/vendor/github.com/Microsoft/hcsshim/internal/winapi/zsyscall_windows.go index 59ddee274e..caf54c82c9 100644 --- a/test/vendor/github.com/Microsoft/hcsshim/internal/winapi/zsyscall_windows.go +++ b/test/vendor/github.com/Microsoft/hcsshim/internal/winapi/zsyscall_windows.go @@ -37,12 +37,15 @@ func errnoErr(e syscall.Errno) error { } var ( + modkernel32 = windows.NewLazySystemDLL("kernel32.dll") modntdll = windows.NewLazySystemDLL("ntdll.dll") modiphlpapi = windows.NewLazySystemDLL("iphlpapi.dll") - modkernel32 = windows.NewLazySystemDLL("kernel32.dll") modadvapi32 = windows.NewLazySystemDLL("advapi32.dll") modcfgmgr32 = windows.NewLazySystemDLL("cfgmgr32.dll") + procCreatePseudoConsole = modkernel32.NewProc("CreatePseudoConsole") + procClosePseudoConsole = modkernel32.NewProc("ClosePseudoConsole") + procResizePseudoConsole = modkernel32.NewProc("ResizePseudoConsole") procNtQuerySystemInformation = modntdll.NewProc("NtQuerySystemInformation") procSetJobCompartmentId = modiphlpapi.NewProc("SetJobCompartmentId") procSearchPathW = modkernel32.NewProc("SearchPathW") @@ -58,7 +61,10 @@ var ( procLogonUserW = modadvapi32.NewProc("LogonUserW") procLocalAlloc = modkernel32.NewProc("LocalAlloc") procLocalFree = modkernel32.NewProc("LocalFree") - procGetProcessImageFileNameW = modkernel32.NewProc("GetProcessImageFileNameW") + procInitializeProcThreadAttributeList = modkernel32.NewProc("InitializeProcThreadAttributeList") + procDeleteProcThreadAttributeList = modkernel32.NewProc("DeleteProcThreadAttributeList") + procUpdateProcThreadAttribute = modkernel32.NewProc("UpdateProcThreadAttribute") + procCreateProcessAsUserW = modadvapi32.NewProc("CreateProcessAsUserW") procGetActiveProcessorCount = modkernel32.NewProc("GetActiveProcessorCount") procCM_Get_Device_ID_List_SizeA = modcfgmgr32.NewProc("CM_Get_Device_ID_List_SizeA") procCM_Get_Device_ID_ListA = modcfgmgr32.NewProc("CM_Get_Device_ID_ListA") @@ -71,6 +77,33 @@ var ( procRtlNtStatusToDosError = modntdll.NewProc("RtlNtStatusToDosError") ) +func createPseudoConsole(size uint32, hInput windows.Handle, hOutput windows.Handle, dwFlags uint32, hpcon *windows.Handle) (hr error) { + r0, _, _ := syscall.Syscall6(procCreatePseudoConsole.Addr(), 5, uintptr(size), uintptr(hInput), uintptr(hOutput), uintptr(dwFlags), uintptr(unsafe.Pointer(hpcon)), 0) + if int32(r0) < 0 { + if r0&0x1fff0000 == 0x00070000 { + r0 &= 0xffff + } + hr = syscall.Errno(r0) + } + return +} + +func ClosePseudoConsole(hpc windows.Handle) { + syscall.Syscall(procClosePseudoConsole.Addr(), 1, uintptr(hpc), 0, 0) + return +} + +func resizePseudoConsole(hPc windows.Handle, size uint32) (hr error) { + r0, _, _ := syscall.Syscall(procResizePseudoConsole.Addr(), 2, uintptr(hPc), uintptr(size), 0) + if int32(r0) < 0 { + if r0&0x1fff0000 == 0x00070000 { + r0 &= 0xffff + } + hr = syscall.Errno(r0) + } + return +} + func NtQuerySystemInformation(systemInfoClass int, systemInformation uintptr, systemInfoLength uint32, returnLength *uint32) (status uint32) { r0, _, _ := syscall.Syscall6(procNtQuerySystemInformation.Addr(), 4, uintptr(systemInfoClass), uintptr(systemInformation), uintptr(systemInfoLength), uintptr(unsafe.Pointer(returnLength)), 0, 0) status = uint32(r0) @@ -227,10 +260,44 @@ func LocalFree(ptr uintptr) { return } -func GetProcessImageFileName(hProcess windows.Handle, imageFileName *uint16, nSize uint32) (size uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetProcessImageFileNameW.Addr(), 3, uintptr(hProcess), uintptr(unsafe.Pointer(imageFileName)), uintptr(nSize)) - size = uint32(r0) - if size == 0 { +func InitializeProcThreadAttributeList(lpAttributeList *ProcThreadAttributeList, dwAttributeCount uint32, dwFlags uint32, lpSize *uintptr) (err error) { + r1, _, e1 := syscall.Syscall6(procInitializeProcThreadAttributeList.Addr(), 4, uintptr(unsafe.Pointer(lpAttributeList)), uintptr(dwAttributeCount), uintptr(dwFlags), uintptr(unsafe.Pointer(lpSize)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func DeleteProcThreadAttributeList(lpAttributeList *ProcThreadAttributeList) { + syscall.Syscall(procDeleteProcThreadAttributeList.Addr(), 1, uintptr(unsafe.Pointer(lpAttributeList)), 0, 0) + return +} + +func UpdateProcThreadAttribute(lpAttributeList *ProcThreadAttributeList, dwFlags uint32, attribute uintptr, lpValue unsafe.Pointer, cbSize uintptr, lpPreviousValue unsafe.Pointer, lpReturnSize *uintptr) (err error) { + r1, _, e1 := syscall.Syscall9(procUpdateProcThreadAttribute.Addr(), 7, uintptr(unsafe.Pointer(lpAttributeList)), uintptr(dwFlags), uintptr(attribute), uintptr(lpValue), uintptr(cbSize), uintptr(lpPreviousValue), uintptr(unsafe.Pointer(lpReturnSize)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CreateProcessAsUser(token windows.Token, appName *uint16, commandLine *uint16, procSecurity *windows.SecurityAttributes, threadSecurity *windows.SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *windows.StartupInfo, outProcInfo *windows.ProcessInformation) (err error) { + var _p0 uint32 + if inheritHandles { + _p0 = 1 + } else { + _p0 = 0 + } + r1, _, e1 := syscall.Syscall12(procCreateProcessAsUserW.Addr(), 11, uintptr(token), uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0) + if r1 == 0 { if e1 != 0 { err = errnoErr(e1) } else {