Skip to content

Commit dd377ba

Browse files
committed
Fix detach-netns permission error on Ubuntu 25.04
On Ubuntu 25.04, `unshare` is subject to `/etc/apparmor.d/unshare-userns-restrict` that disables mounting. ``` $ rootlesskit --detach-netns bash [rootlesskit:child ] error: failed to create a detached netns on "/tmp/rootlesskit2294453251/netns": failed to execute [unshare -n mount --bind /proc/self/ns/net /tmp/rootlesskit2294453251/netns]: exit status 32 (out="mount: /tmp/rootlesskit2294453251/netns: permission denied.\n dmesg(1) may have more information after failed mount system call.\n") ``` Fix issue 494 Alternative to PR 495 Signed-off-by: Akihiro Suda <[email protected]>
1 parent 3fcb258 commit dd377ba

File tree

3 files changed

+70
-0
lines changed

3 files changed

+70
-0
lines changed

cmd/rootlesskit/main.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/sirupsen/logrus"
1616
"github.com/urfave/cli/v2"
1717

18+
"github.com/rootless-containers/rootlesskit/v2/cmd/rootlesskit/unshare"
1819
"github.com/rootless-containers/rootlesskit/v2/pkg/child"
1920
"github.com/rootless-containers/rootlesskit/v2/pkg/common"
2021
"github.com/rootless-containers/rootlesskit/v2/pkg/copyup/tmpfssymlink"
@@ -41,6 +42,10 @@ const (
4142
)
4243

4344
func main() {
45+
if checkUnshareHelper() {
46+
unshare.Main()
47+
return
48+
}
4449
iAmActivationHelper := checkActivationHelper()
4550
iAmChild := os.Getenv(pipeFDEnvKey) != ""
4651
id := "parent"
@@ -701,3 +706,7 @@ func createActivationOpts(clicontext *cli.Context) (activation.Opt, error) {
701706
}
702707
return opt, nil
703708
}
709+
710+
func checkUnshareHelper() bool {
711+
return filepath.Base(os.Args[0]) == "unshare"
712+
}

cmd/rootlesskit/unshare/unshare.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package unshare
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"os"
7+
"os/exec"
8+
"syscall"
9+
10+
"github.com/rootless-containers/rootlesskit/v2/pkg/common"
11+
"github.com/rootless-containers/rootlesskit/v2/pkg/version"
12+
"github.com/urfave/cli/v2"
13+
)
14+
15+
func Main() {
16+
app := cli.NewApp()
17+
app.Name = "unshare"
18+
app.HideHelpCommand = true
19+
app.Version = version.Version
20+
app.Usage = "Reimplementation of unshare(1)"
21+
app.UsageText = "unshare [global options] [arguments...]"
22+
app.Flags = append(app.Flags, &cli.BoolFlag{
23+
Name: "n,net",
24+
Usage: "unshare network namespace",
25+
})
26+
app.Action = action
27+
if err := app.Run(os.Args); err != nil {
28+
fmt.Fprintf(os.Stderr, "[rootlesskit:unshare] error: %v\n", err)
29+
// propagate the exit code
30+
code, ok := common.GetExecExitStatus(err)
31+
if !ok {
32+
code = 1
33+
}
34+
os.Exit(code)
35+
}
36+
}
37+
38+
func action(clicontext *cli.Context) error {
39+
ctx := clicontext.Context
40+
if clicontext.NArg() < 1 {
41+
return errors.New("no command specified")
42+
}
43+
cmdFlags := clicontext.Args().Slice()
44+
cmd := exec.CommandContext(ctx, cmdFlags[0], cmdFlags[1:]...)
45+
cmd.Stdin = os.Stdin
46+
cmd.Stdout = os.Stdout
47+
cmd.Stderr = os.Stderr
48+
cmd.SysProcAttr = &syscall.SysProcAttr{}
49+
if clicontext.Bool("n") {
50+
cmd.SysProcAttr.Cloneflags |= syscall.CLONE_NEWNET
51+
}
52+
return cmd.Run()
53+
}

pkg/child/child.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,8 +583,16 @@ func NewNetNsWithPathWithoutEnter(p string) error {
583583
if err := os.WriteFile(p, nil, 0400); err != nil {
584584
return err
585585
}
586+
selfExe, err := os.Executable()
587+
if err != nil {
588+
return err
589+
}
586590
// this is hard (not impossible though) to reimplement in Go: https://github.com/cloudflare/slirpnetstack/commit/d7766a8a77f0093d3cb7a94bd0ccbe3f67d411ba
587591
cmd := exec.Command("unshare", "-n", "mount", "--bind", "/proc/self/ns/net", p)
592+
// Use our own implementation of unshare that is embedded in RootlessKit, so as to
593+
// avoid /etc/apparmor.d/unshare-userns-restrict on Ubuntu 25.04.
594+
// https://github.com/rootless-containers/rootlesskit/issues/494
595+
cmd.Path = selfExe
588596
out, err := cmd.CombinedOutput()
589597
if err != nil {
590598
return fmt.Errorf("failed to execute %v: %w (out=%q)", cmd.Args, err, string(out))

0 commit comments

Comments
 (0)