]> Cypherpunks repositories - gostls13.git/commitdiff
os: pass correct environment when creating Windows processes
authorJason A. Donenfeld <Jason@zx2c4.com>
Sun, 12 May 2019 12:34:30 +0000 (14:34 +0200)
committerAlex Brainman <alex.brainman@gmail.com>
Thu, 16 May 2019 10:24:10 +0000 (10:24 +0000)
This is CVE-2019-11888.

Previously, passing a nil environment but a non-nil token would result
in the new potentially unprivileged process inheriting the parent
potentially privileged environment, or would result in the new
potentially privileged process inheriting the parent potentially
unprivileged environment. Either way, it's bad. In the former case, it's
an infoleak. In the latter case, it's a possible EoP, since things like
PATH could be overwritten.

Not specifying an environment currently means, "use the existing
environment". This commit amends the behavior to be, "use the existing
environment of the token the process is being created for." The behavior
therefore stays the same when creating processes without specifying a
token. And it does the correct thing when creating processes when
specifying a token.

Fixes #32000

Change-Id: Ia57f6e89b97bdbaf7274d6a89c1d9948b6d40ef5
Reviewed-on: https://go-review.googlesource.com/c/go/+/176619
Run-TryBot: Jason Donenfeld <Jason@zx2c4.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
src/internal/syscall/windows/syscall_windows.go
src/internal/syscall/windows/zsyscall_windows.go
src/os/env_default.go [new file with mode: 0644]
src/os/env_windows.go [new file with mode: 0644]
src/os/exec_posix.go

index 121132f6f7326b90cc12c6078995d159afb1dca8..099e91ed68c9b4303e51fdb55d16bf6968e9fed2 100644 (file)
@@ -305,3 +305,6 @@ const (
 func LoadGetFinalPathNameByHandle() error {
        return procGetFinalPathNameByHandleW.Find()
 }
+
+//sys  CreateEnvironmentBlock(block **uint16, token syscall.Token, inheritExisting bool) (err error) = userenv.CreateEnvironmentBlock
+//sys  DestroyEnvironmentBlock(block *uint16) (err error) = userenv.DestroyEnvironmentBlock
index 9527a370a4e011aff92e6638311ca757110a57e3..ca5b4e6f16ddb3165718d12349e36865aaa5a353 100644 (file)
@@ -58,6 +58,8 @@ var (
        procNetShareAdd                  = modnetapi32.NewProc("NetShareAdd")
        procNetShareDel                  = modnetapi32.NewProc("NetShareDel")
        procGetFinalPathNameByHandleW    = modkernel32.NewProc("GetFinalPathNameByHandleW")
+       procCreateEnvironmentBlock       = moduserenv.NewProc("CreateEnvironmentBlock")
+       procDestroyEnvironmentBlock      = moduserenv.NewProc("DestroyEnvironmentBlock")
        procImpersonateSelf              = modadvapi32.NewProc("ImpersonateSelf")
        procRevertToSelf                 = modadvapi32.NewProc("RevertToSelf")
        procOpenThreadToken              = modadvapi32.NewProc("OpenThreadToken")
@@ -220,6 +222,36 @@ func GetFinalPathNameByHandle(file syscall.Handle, filePath *uint16, filePathSiz
        return
 }
 
+func CreateEnvironmentBlock(block **uint16, token syscall.Token, inheritExisting bool) (err error) {
+       var _p0 uint32
+       if inheritExisting {
+               _p0 = 1
+       } else {
+               _p0 = 0
+       }
+       r1, _, e1 := syscall.Syscall(procCreateEnvironmentBlock.Addr(), 3, uintptr(unsafe.Pointer(block)), uintptr(token), uintptr(_p0))
+       if r1 == 0 {
+               if e1 != 0 {
+                       err = errnoErr(e1)
+               } else {
+                       err = syscall.EINVAL
+               }
+       }
+       return
+}
+
+func DestroyEnvironmentBlock(block *uint16) (err error) {
+       r1, _, e1 := syscall.Syscall(procDestroyEnvironmentBlock.Addr(), 1, uintptr(unsafe.Pointer(block)), 0, 0)
+       if r1 == 0 {
+               if e1 != 0 {
+                       err = errnoErr(e1)
+               } else {
+                       err = syscall.EINVAL
+               }
+       }
+       return
+}
+
 func ImpersonateSelf(impersonationlevel uint32) (err error) {
        r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(impersonationlevel), 0, 0)
        if r1 == 0 {
diff --git a/src/os/env_default.go b/src/os/env_default.go
new file mode 100644 (file)
index 0000000..c11ccce
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !windows
+
+package os
+
+import "syscall"
+
+func environForSysProcAttr(sys *syscall.SysProcAttr) ([]string, error) {
+       return Environ(), nil
+}
diff --git a/src/os/env_windows.go b/src/os/env_windows.go
new file mode 100644 (file)
index 0000000..e8f647e
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+       "internal/syscall/windows"
+       "syscall"
+       "unicode/utf16"
+       "unsafe"
+)
+
+func environForSysProcAttr(sys *syscall.SysProcAttr) (env []string, err error) {
+       if sys == nil || sys.Token == 0 {
+               return Environ(), nil
+       }
+       var block *uint16
+       err = windows.CreateEnvironmentBlock(&block, sys.Token, false)
+       if err != nil {
+               return nil, err
+       }
+       defer windows.DestroyEnvironmentBlock(block)
+       blockp := uintptr(unsafe.Pointer(block))
+       for {
+               entry := (*[(1 << 30) - 1]uint16)(unsafe.Pointer(blockp))[:]
+               for i, v := range entry {
+                       if v == 0 {
+                               entry = entry[:i]
+                               break
+                       }
+               }
+               if len(entry) == 0 {
+                       break
+               }
+               env = append(env, string(utf16.Decode(entry)))
+               blockp += 2 * (uintptr(len(entry)) + 1)
+       }
+       return
+}
index 7b1ef67d1cd95c7ea98f306b4c8b39932af81ac2..505931b488323b380efe7647654676e9c2bac3cd 100644 (file)
@@ -38,7 +38,10 @@ func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err e
                Sys: attr.Sys,
        }
        if sysattr.Env == nil {
-               sysattr.Env = Environ()
+               sysattr.Env, err = environForSysProcAttr(sysattr.Sys)
+               if err != nil {
+                       return nil, err
+               }
        }
        sysattr.Files = make([]uintptr, 0, len(attr.Files))
        for _, f := range attr.Files {