Skip to content
This repository was archived by the owner on Jan 2, 2026. It is now read-only.

Commit 60e1d20

Browse files
committed
fix: chown recursively in mkdirAllAndChown
1 parent 4a9efea commit 60e1d20

File tree

2 files changed

+59
-11
lines changed

2 files changed

+59
-11
lines changed

core/jailer/jaildir.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,11 @@ func (j *jailDir) pathInRoot(p string) string {
5656
}
5757

5858
func (j *jailDir) MkdirAll(dir string) error {
59-
return mkdirAllAndChown(j.pathInRoot(dir), j.uid, j.gid, 0700)
59+
return mkdirAllAndChown(j.pathInRoot(dir), 0700, j.uid, j.gid)
6060
}
6161

6262
func (j *jailDir) Mkdir(dir string) error {
63-
return mkdirAllAndChown(j.pathInRoot(dir), j.uid, j.gid, 0700)
63+
return mkdirAllAndChown(j.pathInRoot(dir), 0700, j.uid, j.gid)
6464
}
6565

6666
func (j *jailDir) MknodAndOwn(device string, mode uint32, dev uint64) error {

core/jailer/util.go

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package jailer
22

33
import (
44
"os"
5+
"path/filepath"
6+
"syscall"
57

68
"golang.org/x/sys/unix"
79
)
@@ -20,25 +22,71 @@ func mkdirAndChown(path string, uid, gid int, perm os.FileMode) error {
2022
return nil
2123
}
2224

23-
func mkdirAllAndChown(path string, uid, gid int, perm os.FileMode) error {
24-
err := os.MkdirAll(path, perm)
25+
func mkFifo(path string, uid, gid int, mode uint32) error {
26+
err := unix.Mkfifo(path, mode)
2527
if err != nil {
2628
return err
2729
}
2830

29-
err = os.Chown(path, uid, gid)
31+
return os.Chown(path, uid, gid)
32+
}
33+
34+
// Copyright 2017 The Go Authors. All rights reserved.
35+
// Use of this source code is governed by a BSD-style
36+
// license that can be found in the https://cs.opensource.google/go/go LICENSE file.
37+
//
38+
// Extracted from os.MkdirAll
39+
func mkdirAllAndChown(path string, perm os.FileMode, uid, gid int) error {
40+
// Fast path: if we can tell whether path is a directory or file, stop with success or error.
41+
dir, err := os.Stat(path)
42+
if err == nil {
43+
if dir.IsDir() {
44+
return nil
45+
}
46+
return &os.PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR}
47+
}
48+
49+
// Slow path: make sure parent exists and then call Mkdir for path.
50+
51+
// Extract the parent folder from path by first removing any trailing
52+
// path separator and then scanning backward until finding a path
53+
// separator or reaching the beginning of the string.
54+
i := len(path) - 1
55+
for i >= 0 && os.IsPathSeparator(path[i]) {
56+
i--
57+
}
58+
for i >= 0 && !os.IsPathSeparator(path[i]) {
59+
i--
60+
}
61+
if i < 0 {
62+
i = 0
63+
}
64+
65+
// If there is a parent directory, and it is not the volume name,
66+
// recurse to ensure parent directory exists.
67+
if parent := path[:i]; len(parent) > len(filepath.VolumeName(path)) {
68+
err = mkdirAllAndChown(parent, perm, uid, gid)
69+
if err != nil {
70+
return err
71+
}
72+
}
73+
74+
// Parent now exists; invoke Mkdir and use its result.
75+
err = os.Mkdir(path, perm)
3076
if err != nil {
77+
// Handle arguments like "foo/." by
78+
// double-checking that directory doesn't exist.
79+
dir, err1 := os.Lstat(path)
80+
if err1 == nil && dir.IsDir() {
81+
return nil
82+
}
3183
return err
3284
}
3385

34-
return nil
35-
}
36-
37-
func mkFifo(path string, uid, gid int, mode uint32) error {
38-
err := unix.Mkfifo(path, mode)
86+
err = os.Chown(path, uid, gid)
3987
if err != nil {
4088
return err
4189
}
4290

43-
return os.Chown(path, uid, gid)
91+
return nil
4492
}

0 commit comments

Comments
 (0)