Skip to content

Commit a1b89e5

Browse files
committed
fix: use XDG_RUNTIME_DIR for default root
Mirror runc behavior: when running as non-root (or root inside a user namespace), honor $XDG_RUNTIME_DIR for the default runtime root so callers do not need to pass --root. Signed-off-by: sidneychang <2190206983@qq.com>
1 parent f8c1354 commit a1b89e5

File tree

3 files changed

+43
-0
lines changed

3 files changed

+43
-0
lines changed

.github/linters/urunc-dict.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ unikontainer
329329
unikontainers
330330
unikraft
331331
urandom
332+
userns
332333
urfave
333334
urunc
334335
urunc's

cmd/urunc/main.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,18 @@ func main() {
118118
// stateCommand,
119119
},
120120
Before: func(_ context.Context, cmd *cli.Command) (context.Context, error) {
121+
if !cmd.IsSet("root") {
122+
xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR")
123+
if xdgRuntimeDir != "" && ShouldHonorXDGRuntimeDir() {
124+
root := xdgRuntimeDir + "/urunc"
125+
if err := prepareXDGRuntimeDir(root); err != nil {
126+
return nil, err
127+
}
128+
if err := cmd.Set("root", root); err != nil {
129+
return nil, err
130+
}
131+
}
132+
}
121133
if err := reviseRootDir(cmd); err != nil {
122134
return nil, err
123135
}

cmd/urunc/utils.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"os/exec"
2323
"syscall"
2424

25+
"github.com/moby/sys/userns"
2526
"github.com/sirupsen/logrus"
2627
"github.com/urfave/cli/v3"
2728
"github.com/urunc-dev/urunc/pkg/unikontainers"
@@ -130,3 +131,32 @@ func fatalWithCode(err error, ret int) {
130131
}
131132
os.Exit(ret)
132133
}
134+
135+
// ShouldHonorXDGRuntimeDir reports whether the runtime should use XDG_RUNTIME_DIR
136+
// for the default root directory (e.g. /run/user/UID/urunc instead of /run/urunc).
137+
// It returns true for non-root processes and for root inside a user namespace
138+
// when not running as the "root" user (e.g. rootless Podman).
139+
func ShouldHonorXDGRuntimeDir() bool {
140+
if os.Geteuid() != 0 {
141+
return true
142+
}
143+
if !userns.RunningInUserNS() {
144+
// euid == 0 in the initial ns (real root): use /run/urunc for backward compatibility.
145+
return false
146+
}
147+
// euid == 0 inside a user namespace (rootless): honor XDG_RUNTIME_DIR unless USER=root.
148+
u, ok := os.LookupEnv("USER")
149+
return !ok || u != "root"
150+
}
151+
152+
// prepareXDGRuntimeDir prepares the XDG_RUNTIME_DIR directory according to the XDG specification.
153+
// It creates the directory with proper permissions and sets the sticky bit to prevent auto-pruning.
154+
func prepareXDGRuntimeDir(root string) error {
155+
if err := os.MkdirAll(root, 0o700); err != nil {
156+
return fmt.Errorf("the path in $XDG_RUNTIME_DIR must be writable by the user: %w", err)
157+
}
158+
if err := os.Chmod(root, os.FileMode(0o700)|os.ModeSticky); err != nil {
159+
return fmt.Errorf("you should check permission of the path in $XDG_RUNTIME_DIR: %w", err)
160+
}
161+
return nil
162+
}

0 commit comments

Comments
 (0)