Skip to content

Commit

Permalink
Check filecaps on newuidmap and newgidmap on failure
Browse files Browse the repository at this point in the history
A fairly common failure is newuidmap and newgidmap not being setuid and
setgid. If these commands fail, check the permissions on the binaries in
order to give the user better information on why they failed.

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
  • Loading branch information
rhatdan committed Apr 5, 2022
1 parent bb2843d commit 9e1f721
Showing 1 changed file with 61 additions and 7 deletions.
68 changes: 61 additions & 7 deletions pkg/unshare/unshare_linux.go
@@ -1,3 +1,4 @@
//go:build linux
// +build linux

package unshare
Expand Down Expand Up @@ -76,6 +77,36 @@ func getRootlessGID() int {
return os.Getegid()
}

type idtype int64

const (
uid idtype = 0
gid = 1
)

func isSetID(id idtype, path string) (bool, error) {
modeid := os.ModeSetuid
capid := capability.CAP_SETUID
if id == gid {
modeid = os.ModeSetgid
capid = capability.CAP_SETGID
}
info, err := os.Stat(path)
if err != nil {
return false, err
}

mode := info.Mode()
if mode&modeid == modeid {
return true, nil
}
cap, err := capability.NewFile(path)
if err != nil {
return false, err
}
return cap.Get(capability.EFFECTIVE, capid), nil
}

func (c *Cmd) Start() error {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
Expand Down Expand Up @@ -215,15 +246,26 @@ func (c *Cmd) Start() error {
gidmapSet := false
// Set the GID map.
if c.UseNewgidmap {
cmd := exec.Command("newgidmap", append([]string{pidString}, strings.Fields(strings.Replace(g.String(), "\n", " ", -1))...)...)
path, err := exec.LookPath("newgidmap")
if err != nil {
return errors.Wrapf(err, "error finding newgidmap")
}
cmd := exec.Command(path, append([]string{pidString}, strings.Fields(strings.Replace(g.String(), "\n", " ", -1))...)...)
g.Reset()
cmd.Stdout = g
cmd.Stderr = g
err := cmd.Run()
if err == nil {
if err := cmd.Run(); err == nil {
gidmapSet = true
} else {
logrus.Warnf("Error running newgidmap: %v: %s", err, g.String())
isSetgid, err := isSetID(gid, path)
if err != nil {
logrus.Warnf("Failed to check for setgid on %s: %v", path, err)
} else {
if !isSetgid {
logrus.Warnf("%s should be setgid or have filecaps setgid", path)
}
}
logrus.Warnf("Falling back to single mapping")
g.Reset()
g.Write([]byte(fmt.Sprintf("0 %d 1\n", os.Getegid())))
Expand Down Expand Up @@ -262,17 +304,29 @@ func (c *Cmd) Start() error {
fmt.Fprintf(u, "%d %d %d\n", m.ContainerID, m.HostID, m.Size)
}
uidmapSet := false
// Set the GID map.
// Set the UID map.
if c.UseNewuidmap {
cmd := exec.Command("newuidmap", append([]string{pidString}, strings.Fields(strings.Replace(u.String(), "\n", " ", -1))...)...)
path, err := exec.LookPath("newuidmap")
if err != nil {
return errors.Wrapf(err, "error finding newuidmap")
}
cmd := exec.Command(path, append([]string{pidString}, strings.Fields(strings.Replace(u.String(), "\n", " ", -1))...)...)
u.Reset()
cmd.Stdout = u
cmd.Stderr = u
err := cmd.Run()
if err == nil {
if err := cmd.Run(); err == nil {
uidmapSet = true
} else {
logrus.Warnf("Error running newuidmap: %v: %s", err, u.String())
isSetuid, err := isSetID(uid, path)
if err != nil {
logrus.Warnf("Failed to check for setuid on %s: %v", path, err)
} else {
if !isSetuid {
logrus.Warnf("%s should be setuid or have filecaps setuid", path)
}
}

logrus.Warnf("Falling back to single mapping")
u.Reset()
u.Write([]byte(fmt.Sprintf("0 %d 1\n", os.Geteuid())))
Expand Down

0 comments on commit 9e1f721

Please sign in to comment.