diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/chrootuser/user.go | 6 | ||||
-rw-r--r-- | pkg/chrootuser/user_linux.go | 4 | ||||
-rw-r--r-- | pkg/rootless/rootless.go | 104 | ||||
-rw-r--r-- | pkg/rootless/rootless_linux.go | 117 | ||||
-rw-r--r-- | pkg/rootless/rootless_unsupported.go | 18 | ||||
-rw-r--r-- | pkg/spec/config_linux.go | 84 | ||||
-rw-r--r-- | pkg/spec/config_unsupported.go | 12 | ||||
-rw-r--r-- | pkg/spec/createconfig.go | 17 | ||||
-rw-r--r-- | pkg/spec/parse.go | 15 | ||||
-rw-r--r-- | pkg/spec/spec.go | 43 |
10 files changed, 243 insertions, 177 deletions
diff --git a/pkg/chrootuser/user.go b/pkg/chrootuser/user.go index 1fbb5566e..3de138b86 100644 --- a/pkg/chrootuser/user.go +++ b/pkg/chrootuser/user.go @@ -8,6 +8,12 @@ import ( "github.com/pkg/errors" ) +var ( + // ErrNoSuchUser indicates that the user provided by the caller does not + // exist in /etc/passws + ErrNoSuchUser = errors.New("user does not exist in /etc/passwd") +) + // GetUser will return the uid, gid of the user specified in the userspec // it will use the /etc/passwd and /etc/group files inside of the rootdir // to return this information. diff --git a/pkg/chrootuser/user_linux.go b/pkg/chrootuser/user_linux.go index d48a1c7c2..acd0af822 100644 --- a/pkg/chrootuser/user_linux.go +++ b/pkg/chrootuser/user_linux.go @@ -4,7 +4,6 @@ package chrootuser import ( "bufio" - "errors" "flag" "fmt" "io" @@ -79,9 +78,6 @@ func openChrootedFile(rootdir, filename string) (*exec.Cmd, io.ReadCloser, error var ( lookupUser, lookupGroup sync.Mutex - // ErrNoSuchUser indicates that the user provided by the caller does not - // exist in /etc/passws - ErrNoSuchUser = errors.New("user does not exist in /etc/passwd") ) type lookupPasswdEntry struct { diff --git a/pkg/rootless/rootless.go b/pkg/rootless/rootless.go index 737fc91c7..ca851f9bc 100644 --- a/pkg/rootless/rootless.go +++ b/pkg/rootless/rootless.go @@ -2,16 +2,9 @@ package rootless import ( "fmt" - "io/ioutil" + "github.com/containers/storage/pkg/idtools" "os" "os/exec" - gosignal "os/signal" - "runtime" - "syscall" - - "github.com/containers/storage/pkg/idtools" - "github.com/docker/docker/pkg/signal" - "github.com/pkg/errors" ) /* @@ -25,11 +18,6 @@ func runInUser() error { return nil } -// IsRootless tells us if we are running in rootless mode -func IsRootless() bool { - return os.Getuid() != 0 || os.Getenv("_LIBPOD_USERNS_CONFIGURED") != "" -} - func tryMappingTool(tool string, pid int, hostID int, mappings []idtools.IDMap) error { path, err := exec.LookPath(tool) if err != nil { @@ -53,93 +41,3 @@ func tryMappingTool(tool string, pid int, hostID int, mappings []idtools.IDMap) } return cmd.Run() } - -// BecomeRootInUserNS re-exec podman in a new userNS -func BecomeRootInUserNS() (bool, error) { - - if os.Getuid() == 0 || os.Getenv("_LIBPOD_USERNS_CONFIGURED") != "" { - if os.Getenv("_LIBPOD_USERNS_CONFIGURED") == "init" { - return false, runInUser() - } - return false, nil - } - - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - r, w, err := os.Pipe() - if err != nil { - return false, err - } - defer r.Close() - defer w.Close() - - pidC := C.reexec_in_user_namespace(C.int(r.Fd())) - pid := int(pidC) - if pid < 0 { - return false, errors.Errorf("cannot re-exec process") - } - - setgroups := fmt.Sprintf("/proc/%d/setgroups", pid) - err = ioutil.WriteFile(setgroups, []byte("deny\n"), 0666) - if err != nil { - return false, errors.Wrapf(err, "cannot write setgroups file") - } - - var uids, gids []idtools.IDMap - username := os.Getenv("USER") - mappings, err := idtools.NewIDMappings(username, username) - if err == nil { - uids = mappings.UIDs() - gids = mappings.GIDs() - } - - uidsMapped := false - if mappings != nil && uids != nil { - uidsMapped = tryMappingTool("newuidmap", pid, os.Getuid(), uids) == nil - } - if !uidsMapped { - uidMap := fmt.Sprintf("/proc/%d/uid_map", pid) - err = ioutil.WriteFile(uidMap, []byte(fmt.Sprintf("%d %d 1\n", 0, os.Getuid())), 0666) - if err != nil { - return false, errors.Wrapf(err, "cannot write uid_map") - } - } - - gidsMapped := false - if mappings != nil && gids != nil { - gidsMapped = tryMappingTool("newgidmap", pid, os.Getgid(), gids) == nil - } - if !gidsMapped { - gidMap := fmt.Sprintf("/proc/%d/gid_map", pid) - err = ioutil.WriteFile(gidMap, []byte(fmt.Sprintf("%d %d 1\n", 0, os.Getgid())), 0666) - if err != nil { - return false, errors.Wrapf(err, "cannot write gid_map") - } - } - - _, err = w.Write([]byte("1")) - if err != nil { - return false, errors.Wrapf(err, "write to sync pipe") - } - - c := make(chan os.Signal, 1) - - gosignal.Notify(c) - defer gosignal.Reset() - go func() { - for s := range c { - if s == signal.SIGCHLD || s == signal.SIGPIPE { - continue - } - - syscall.Kill(int(pidC), s.(syscall.Signal)) - } - }() - - if C.reexec_in_user_namespace_wait(pidC) < 0 { - return false, errors.Wrapf(err, "error waiting for the re-exec process") - } - - return true, nil -} diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go new file mode 100644 index 000000000..5b4094bf2 --- /dev/null +++ b/pkg/rootless/rootless_linux.go @@ -0,0 +1,117 @@ +// build +linux + +package rootless + +import ( + "fmt" + "io/ioutil" + "os" + gosignal "os/signal" + "runtime" + "syscall" + + "github.com/containers/storage/pkg/idtools" + "github.com/docker/docker/pkg/signal" + "github.com/pkg/errors" +) + +/* +extern int reexec_in_user_namespace(int ready); +extern int reexec_in_user_namespace_wait(int pid); +*/ +import "C" + +// IsRootless tells us if we are running in rootless mode +func IsRootless() bool { + return os.Getuid() != 0 || os.Getenv("_LIBPOD_USERNS_CONFIGURED") != "" +} + +// BecomeRootInUserNS re-exec podman in a new userNS +func BecomeRootInUserNS() (bool, error) { + + if os.Getuid() == 0 || os.Getenv("_LIBPOD_USERNS_CONFIGURED") != "" { + if os.Getenv("_LIBPOD_USERNS_CONFIGURED") == "init" { + return false, runInUser() + } + return false, nil + } + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + r, w, err := os.Pipe() + if err != nil { + return false, err + } + defer r.Close() + defer w.Close() + + pidC := C.reexec_in_user_namespace(C.int(r.Fd())) + pid := int(pidC) + if pid < 0 { + return false, errors.Errorf("cannot re-exec process") + } + + setgroups := fmt.Sprintf("/proc/%d/setgroups", pid) + err = ioutil.WriteFile(setgroups, []byte("deny\n"), 0666) + if err != nil { + return false, errors.Wrapf(err, "cannot write setgroups file") + } + + var uids, gids []idtools.IDMap + username := os.Getenv("USER") + mappings, err := idtools.NewIDMappings(username, username) + if err == nil { + uids = mappings.UIDs() + gids = mappings.GIDs() + } + + uidsMapped := false + if mappings != nil && uids != nil { + uidsMapped = tryMappingTool("newuidmap", pid, os.Getuid(), uids) == nil + } + if !uidsMapped { + uidMap := fmt.Sprintf("/proc/%d/uid_map", pid) + err = ioutil.WriteFile(uidMap, []byte(fmt.Sprintf("%d %d 1\n", 0, os.Getuid())), 0666) + if err != nil { + return false, errors.Wrapf(err, "cannot write uid_map") + } + } + + gidsMapped := false + if mappings != nil && gids != nil { + gidsMapped = tryMappingTool("newgidmap", pid, os.Getgid(), gids) == nil + } + if !gidsMapped { + gidMap := fmt.Sprintf("/proc/%d/gid_map", pid) + err = ioutil.WriteFile(gidMap, []byte(fmt.Sprintf("%d %d 1\n", 0, os.Getgid())), 0666) + if err != nil { + return false, errors.Wrapf(err, "cannot write gid_map") + } + } + + _, err = w.Write([]byte("1")) + if err != nil { + return false, errors.Wrapf(err, "write to sync pipe") + } + + c := make(chan os.Signal, 1) + + gosignal.Notify(c) + defer gosignal.Reset() + go func() { + for s := range c { + if s == signal.SIGCHLD || s == signal.SIGPIPE { + continue + } + + syscall.Kill(int(pidC), s.(syscall.Signal)) + } + }() + + if C.reexec_in_user_namespace_wait(pidC) < 0 { + return false, errors.Wrapf(err, "error waiting for the re-exec process") + } + + return true, nil +} diff --git a/pkg/rootless/rootless_unsupported.go b/pkg/rootless/rootless_unsupported.go new file mode 100644 index 000000000..e4067a764 --- /dev/null +++ b/pkg/rootless/rootless_unsupported.go @@ -0,0 +1,18 @@ +// +build !linux + +package rootless + +import ( + "github.com/pkg/errors" +) + +// IsRootless returns false on all non-linux platforms +func IsRootless() bool { + return false +} + +// BecomeRootInUserNS is a stub function that always returns false and an +// error on unsupported OS's +func BecomeRootInUserNS() (bool, error) { + return false, errors.New("this function is not supported on this os") +} diff --git a/pkg/spec/config_linux.go b/pkg/spec/config_linux.go new file mode 100644 index 000000000..69b99232f --- /dev/null +++ b/pkg/spec/config_linux.go @@ -0,0 +1,84 @@ +// +build linux + +package createconfig + +import ( + "io/ioutil" + + "github.com/docker/docker/profiles/seccomp" + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/devices" + spec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/runtime-tools/generate" + "github.com/pkg/errors" +) + +// Device transforms a libcontainer configs.Device to a specs.LinuxDevice object. +func Device(d *configs.Device) spec.LinuxDevice { + return spec.LinuxDevice{ + Type: string(d.Type), + Path: d.Path, + Major: d.Major, + Minor: d.Minor, + FileMode: fmPtr(int64(d.FileMode)), + UID: u32Ptr(int64(d.Uid)), + GID: u32Ptr(int64(d.Gid)), + } +} + +func addDevice(g *generate.Generator, device string) error { + dev, err := devices.DeviceFromPath(device, "rwm") + if err != nil { + return errors.Wrapf(err, "%s is not a valid device", device) + } + linuxdev := spec.LinuxDevice{ + Path: dev.Path, + Type: string(dev.Type), + Major: dev.Major, + Minor: dev.Minor, + FileMode: &dev.FileMode, + UID: &dev.Uid, + GID: &dev.Gid, + } + g.AddDevice(linuxdev) + g.AddLinuxResourcesDevice(true, string(dev.Type), &dev.Major, &dev.Minor, dev.Permissions) + return nil +} + +// AddPrivilegedDevices iterates through host devices and adds all +// host devices to the spec +func (c *CreateConfig) AddPrivilegedDevices(g *generate.Generator) error { + hostDevices, err := devices.HostDevices() + if err != nil { + return err + } + g.ClearLinuxDevices() + for _, d := range hostDevices { + g.AddDevice(Device(d)) + } + g.AddLinuxResourcesDevice(true, "", nil, nil, "rwm") + return nil +} + +func getSeccompConfig(config *CreateConfig, configSpec *spec.Spec) (*spec.LinuxSeccomp, error) { + var seccompConfig *spec.LinuxSeccomp + var err error + + if config.SeccompProfilePath != "" { + seccompProfile, err := ioutil.ReadFile(config.SeccompProfilePath) + if err != nil { + return nil, errors.Wrapf(err, "opening seccomp profile (%s) failed", config.SeccompProfilePath) + } + seccompConfig, err = seccomp.LoadProfile(string(seccompProfile), configSpec) + if err != nil { + return nil, errors.Wrapf(err, "loading seccomp profile (%s) failed", config.SeccompProfilePath) + } + } else { + seccompConfig, err = seccomp.GetDefaultProfile(configSpec) + if err != nil { + return nil, errors.Wrapf(err, "loading seccomp profile (%s) failed", config.SeccompProfilePath) + } + } + + return seccompConfig, nil +} diff --git a/pkg/spec/config_unsupported.go b/pkg/spec/config_unsupported.go new file mode 100644 index 000000000..b3b05acea --- /dev/null +++ b/pkg/spec/config_unsupported.go @@ -0,0 +1,12 @@ +// +build !linux + +package createconfig + +import ( + spec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" +) + +func getSeccompConfig(config *CreateConfig, configSpec *spec.Spec) (*spec.LinuxSeccomp, error) { + return nil, errors.New("function not supported on non-linux OS's") +} diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go index 27df0c395..451c09eb3 100644 --- a/pkg/spec/createconfig.go +++ b/pkg/spec/createconfig.go @@ -10,9 +10,7 @@ import ( "github.com/cri-o/ocicni/pkg/ocicni" "github.com/docker/docker/api/types/container" "github.com/docker/go-connections/nat" - "github.com/opencontainers/runc/libcontainer/devices" spec "github.com/opencontainers/runtime-spec/specs-go" - "github.com/opencontainers/runtime-tools/generate" "github.com/opencontainers/selinux/go-selinux/label" "github.com/pkg/errors" "github.com/projectatomic/libpod/libpod" @@ -488,21 +486,6 @@ func (c *CreateConfig) CreatePortBindings() ([]ocicni.PortMapping, error) { return portBindings, nil } -// AddPrivilegedDevices iterates through host devices and adds all -// host devices to the spec -func (c *CreateConfig) AddPrivilegedDevices(g *generate.Generator) error { - hostDevices, err := devices.HostDevices() - if err != nil { - return err - } - g.ClearLinuxDevices() - for _, d := range hostDevices { - g.AddDevice(Device(d)) - } - g.AddLinuxResourcesDevice(true, "", nil, nil, "rwm") - return nil -} - func getStatFromPath(path string) (unix.Stat_t, error) { s := unix.Stat_t{} err := unix.Stat(path, &s) diff --git a/pkg/spec/parse.go b/pkg/spec/parse.go index 920674b10..82ca92dff 100644 --- a/pkg/spec/parse.go +++ b/pkg/spec/parse.go @@ -6,8 +6,6 @@ import ( "strings" "github.com/docker/go-units" - "github.com/opencontainers/runc/libcontainer/configs" - spec "github.com/opencontainers/runtime-spec/specs-go" ) // weightDevice is a structure that holds device:weight pair @@ -113,16 +111,3 @@ func getLoggingPath(opts []string) string { } return "" } - -// Device transforms a libcontainer configs.Device to a specs.LinuxDevice object. -func Device(d *configs.Device) spec.LinuxDevice { - return spec.LinuxDevice{ - Type: string(d.Type), - Path: d.Path, - Major: d.Major, - Minor: d.Minor, - FileMode: fmPtr(int64(d.FileMode)), - UID: u32Ptr(int64(d.Uid)), - GID: u32Ptr(int64(d.Gid)), - } -} diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go index 2faa3c2cd..f9c60fdfa 100644 --- a/pkg/spec/spec.go +++ b/pkg/spec/spec.go @@ -6,14 +6,11 @@ import ( "github.com/docker/docker/daemon/caps" "github.com/docker/docker/pkg/mount" "github.com/docker/go-units" - "github.com/opencontainers/runc/libcontainer/devices" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-tools/generate" "github.com/pkg/errors" "github.com/projectatomic/libpod/pkg/rootless" - seccomp "github.com/seccomp/containers-golang" "github.com/sirupsen/logrus" - "io/ioutil" ) const cpuPeriod = 100000 @@ -236,24 +233,13 @@ func CreateConfigToOCISpec(config *CreateConfig) (*spec.Spec, error) { //nolint } // HANDLE SECCOMP + if config.SeccompProfilePath != "unconfined" { - if config.SeccompProfilePath != "" { - seccompProfile, err := ioutil.ReadFile(config.SeccompProfilePath) - if err != nil { - return nil, errors.Wrapf(err, "opening seccomp profile (%s) failed", config.SeccompProfilePath) - } - seccompConfig, err := seccomp.LoadProfile(string(seccompProfile), configSpec) - if err != nil { - return nil, errors.Wrapf(err, "loading seccomp profile (%s) failed", config.SeccompProfilePath) - } - configSpec.Linux.Seccomp = seccompConfig - } else { - seccompConfig, err := seccomp.GetDefaultProfile(configSpec) - if err != nil { - return nil, errors.Wrapf(err, "loading seccomp profile (%s) failed", config.SeccompProfilePath) - } - configSpec.Linux.Seccomp = seccompConfig + seccompConfig, err := getSeccompConfig(config, configSpec) + if err != nil { + return nil, err } + configSpec.Linux.Seccomp = seccompConfig } // Clear default Seccomp profile from Generator for privileged containers @@ -429,22 +415,3 @@ func setupCapabilities(config *CreateConfig, configSpec *spec.Spec) error { configSpec.Process.Capabilities.Bounding = caplist return nil } - -func addDevice(g *generate.Generator, device string) error { - dev, err := devices.DeviceFromPath(device, "rwm") - if err != nil { - return errors.Wrapf(err, "%s is not a valid device", device) - } - linuxdev := spec.LinuxDevice{ - Path: dev.Path, - Type: string(dev.Type), - Major: dev.Major, - Minor: dev.Minor, - FileMode: &dev.FileMode, - UID: &dev.Uid, - GID: &dev.Gid, - } - g.AddDevice(linuxdev) - g.AddLinuxResourcesDevice(true, string(dev.Type), &dev.Major, &dev.Minor, dev.Permissions) - return nil -} |