瀏覽代碼

Merge pull request #28002 from Microsoft/jjh/noreexec

Windows: Allow a no-reexec option for importLayer
Tibor Vass 8 年之前
父節點
當前提交
5e3d777401
共有 3 個文件被更改,包括 78 次插入51 次删除
  1. 64 46
      daemon/graphdriver/windows/windows.go
  2. 1 1
      vendor.conf
  3. 13 4
      vendor/github.com/Microsoft/go-winio/privilege.go

+ 64 - 46
daemon/graphdriver/windows/windows.go

@@ -45,12 +45,20 @@ var (
 		"UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG1": "bcd.log1.bak",
 		"UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG2": "bcd.log2.bak",
 	}
+	noreexec = false
 )
 
 // init registers the windows graph drivers to the register.
 func init() {
 	graphdriver.Register("windowsfilter", InitFilter)
-	reexec.Register("docker-windows-write-layer", writeLayer)
+	// DOCKER_WINDOWSFILTER_NOREEXEC allows for inline processing which makes
+	// debugging issues in the re-exec codepath significantly easier.
+	if os.Getenv("DOCKER_WINDOWSFILTER_NOREEXEC") != "" {
+		logrus.Warnf("WindowsGraphDriver is set to not re-exec. This is intended for debugging purposes only.")
+		noreexec = true
+	} else {
+		reexec.Register("docker-windows-write-layer", writeLayerReexec)
+	}
 }
 
 type checker struct {
@@ -658,63 +666,73 @@ func writeLayerFromTar(r io.Reader, w hcsshim.LayerWriter, root string) (int64,
 
 // importLayer adds a new layer to the tag and graph store based on the given data.
 func (d *Driver) importLayer(id string, layerData io.Reader, parentLayerPaths []string) (size int64, err error) {
-	cmd := reexec.Command(append([]string{"docker-windows-write-layer", d.info.HomeDir, id}, parentLayerPaths...)...)
-	output := bytes.NewBuffer(nil)
-	cmd.Stdin = layerData
-	cmd.Stdout = output
-	cmd.Stderr = output
+	if !noreexec {
+		cmd := reexec.Command(append([]string{"docker-windows-write-layer", d.info.HomeDir, id}, parentLayerPaths...)...)
+		output := bytes.NewBuffer(nil)
+		cmd.Stdin = layerData
+		cmd.Stdout = output
+		cmd.Stderr = output
 
-	if err = cmd.Start(); err != nil {
-		return
-	}
+		if err = cmd.Start(); err != nil {
+			return
+		}
 
-	if err = cmd.Wait(); err != nil {
-		return 0, fmt.Errorf("re-exec error: %v: output: %s", err, output)
-	}
+		if err = cmd.Wait(); err != nil {
+			return 0, fmt.Errorf("re-exec error: %v: output: %s", err, output)
+		}
 
-	return strconv.ParseInt(output.String(), 10, 64)
+		return strconv.ParseInt(output.String(), 10, 64)
+	}
+	return writeLayer(layerData, d.info.HomeDir, id, parentLayerPaths...)
 }
 
-// writeLayer is the re-exec entry point for writing a layer from a tar file
-func writeLayer() {
-	home := os.Args[1]
-	id := os.Args[2]
-	parentLayerPaths := os.Args[3:]
-
-	err := func() error {
-		err := winio.EnableProcessPrivileges([]string{winio.SeBackupPrivilege, winio.SeRestorePrivilege})
-		if err != nil {
-			return err
-		}
-
-		info := hcsshim.DriverInfo{
-			Flavour: filterDriver,
-			HomeDir: home,
-		}
+// writeLayerReexec is the re-exec entry point for writing a layer from a tar file
+func writeLayerReexec() {
+	size, err := writeLayer(os.Stdin, os.Args[1], os.Args[2], os.Args[3:]...)
+	if err != nil {
+		fmt.Fprint(os.Stderr, err)
+		os.Exit(1)
+	}
+	fmt.Fprint(os.Stdout, size)
+}
 
-		w, err := hcsshim.NewLayerWriter(info, id, parentLayerPaths)
-		if err != nil {
-			return err
-		}
+// writeLayer writes a layer from a tar file.
+func writeLayer(layerData io.Reader, home string, id string, parentLayerPaths ...string) (int64, error) {
+	err := winio.EnableProcessPrivileges([]string{winio.SeBackupPrivilege, winio.SeRestorePrivilege})
+	if err != nil {
+		return 0, err
+	}
+	if noreexec {
+		defer func() {
+			if err := winio.DisableProcessPrivileges([]string{winio.SeBackupPrivilege, winio.SeRestorePrivilege}); err != nil {
+				// This should never happen, but just in case when in debugging mode.
+				// See https://github.com/docker/docker/pull/28002#discussion_r86259241 for rationale.
+				panic("Failed to disabled process privileges while in non re-exec mode")
+			}
+		}()
+	}
 
-		size, err := writeLayerFromTar(os.Stdin, w, filepath.Join(home, id))
-		if err != nil {
-			return err
-		}
+	info := hcsshim.DriverInfo{
+		Flavour: filterDriver,
+		HomeDir: home,
+	}
 
-		err = w.Close()
-		if err != nil {
-			return err
-		}
+	w, err := hcsshim.NewLayerWriter(info, id, parentLayerPaths)
+	if err != nil {
+		return 0, err
+	}
 
-		fmt.Fprint(os.Stdout, size)
-		return nil
-	}()
+	size, err := writeLayerFromTar(layerData, w, filepath.Join(home, id))
+	if err != nil {
+		return 0, err
+	}
 
+	err = w.Close()
 	if err != nil {
-		fmt.Fprint(os.Stderr, err)
-		os.Exit(1)
+		return 0, err
 	}
+
+	return size, nil
 }
 
 // resolveID computes the layerID information based on the given id.

+ 1 - 1
vendor.conf

@@ -1,7 +1,7 @@
 # the following lines are in sorted order, FYI
 github.com/Azure/go-ansiterm 388960b655244e76e24c75f48631564eaefade62
 github.com/Microsoft/hcsshim v0.5.7
-github.com/Microsoft/go-winio v0.3.5
+github.com/Microsoft/go-winio v0.3.6
 github.com/Sirupsen/logrus f76d643702a30fbffecdfe50831e11881c96ceb3 https://github.com/aaronlehmann/logrus
 github.com/davecgh/go-spew 6d212800a42e8ab5c146b8ace3490ee17e5225f9
 github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a

+ 13 - 4
vendor/github.com/Microsoft/go-winio/privilege.go

@@ -83,7 +83,7 @@ func RunWithPrivileges(names []string, fn func() error) error {
 		return err
 	}
 	defer releaseThreadToken(token)
-	err = adjustPrivileges(token, privileges)
+	err = adjustPrivileges(token, privileges, SE_PRIVILEGE_ENABLED)
 	if err != nil {
 		return err
 	}
@@ -110,6 +110,15 @@ func mapPrivileges(names []string) ([]uint64, error) {
 
 // EnableProcessPrivileges enables privileges globally for the process.
 func EnableProcessPrivileges(names []string) error {
+	return enableDisableProcessPrivilege(names, SE_PRIVILEGE_ENABLED)
+}
+
+// DisableProcessPrivileges disables privileges globally for the process.
+func DisableProcessPrivileges(names []string) error {
+	return enableDisableProcessPrivilege(names, 0)
+}
+
+func enableDisableProcessPrivilege(names []string, action uint32) error {
 	privileges, err := mapPrivileges(names)
 	if err != nil {
 		return err
@@ -123,15 +132,15 @@ func EnableProcessPrivileges(names []string) error {
 	}
 
 	defer token.Close()
-	return adjustPrivileges(token, privileges)
+	return adjustPrivileges(token, privileges, action)
 }
 
-func adjustPrivileges(token windows.Token, privileges []uint64) error {
+func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) error {
 	var b bytes.Buffer
 	binary.Write(&b, binary.LittleEndian, uint32(len(privileges)))
 	for _, p := range privileges {
 		binary.Write(&b, binary.LittleEndian, p)
-		binary.Write(&b, binary.LittleEndian, uint32(SE_PRIVILEGE_ENABLED))
+		binary.Write(&b, binary.LittleEndian, action)
 	}
 	prevState := make([]byte, b.Len())
 	reqSize := uint32(0)