The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/6246
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) === - Also fixes static analysis check for ucred package.
From 2cae61a4b7740004663ec3b9045699b85986a201 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Thu, 26 Sep 2019 17:42:12 +0100 Subject: [PATCH 1/6] lxd/seccomp: Adds seccomp package - Cleans up existing seccomp code to pass go lint Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/{ => seccomp}/seccomp.go | 256 +++++++++++++++++++++-------------- 1 file changed, 158 insertions(+), 98 deletions(-) rename lxd/{ => seccomp}/seccomp.go (78%) diff --git a/lxd/seccomp.go b/lxd/seccomp/seccomp.go similarity index 78% rename from lxd/seccomp.go rename to lxd/seccomp/seccomp.go index a314e52cfc..aea64d36fa 100644 --- a/lxd/seccomp.go +++ b/lxd/seccomp/seccomp.go @@ -1,7 +1,7 @@ // +build linux // +build cgo -package main +package seccomp import ( "fmt" @@ -17,11 +17,14 @@ import ( "unsafe" "golang.org/x/sys/unix" + lxc "gopkg.in/lxc/go-lxc.v2" "github.com/lxc/lxd/lxd/device/config" + "github.com/lxc/lxd/lxd/state" "github.com/lxc/lxd/lxd/ucred" "github.com/lxc/lxd/lxd/util" "github.com/lxc/lxd/shared" + "github.com/lxc/lxd/shared/idmap" log "github.com/lxc/lxd/shared/log15" "github.com/lxc/lxd/shared/logger" "github.com/lxc/lxd/shared/netutils" @@ -273,14 +276,14 @@ static void prepare_seccomp_iovec(struct iovec *iov, // #cgo CFLAGS: -std=gnu11 -Wvla import "C" -const LxdSeccompNotifyMknod = C.LXD_SECCOMP_NOTIFY_MKNOD -const LxdSeccompNotifyMknodat = C.LXD_SECCOMP_NOTIFY_MKNODAT -const LxdSeccompNotifySetxattr = C.LXD_SECCOMP_NOTIFY_SETXATTR +const lxdSeccompNotifyMknod = C.LXD_SECCOMP_NOTIFY_MKNOD +const lxdSeccompNotifyMknodat = C.LXD_SECCOMP_NOTIFY_MKNODAT +const lxdSeccompNotifySetxattr = C.LXD_SECCOMP_NOTIFY_SETXATTR -const SECCOMP_HEADER = `2 +const seccompHeader = `2 ` -const DEFAULT_SECCOMP_POLICY = `reject_force_umount # comment this to allow umount -f; not recommended +const defaultSeccompPolicy = `reject_force_umount # comment this to allow umount -f; not recommended [all] kexec_load errno 38 open_by_handle_at errno 38 @@ -289,15 +292,15 @@ finit_module errno 38 delete_module errno 38 ` -const SECCOMP_NOTIFY_MKNOD = `mknod notify [1,8192,SCMP_CMP_MASKED_EQ,61440] +const seccompNotifyMknod = `mknod notify [1,8192,SCMP_CMP_MASKED_EQ,61440] mknod notify [1,24576,SCMP_CMP_MASKED_EQ,61440] mknodat notify [2,8192,SCMP_CMP_MASKED_EQ,61440] mknodat notify [2,24576,SCMP_CMP_MASKED_EQ,61440] ` -const SECCOMP_NOTIFY_SETXATTR = `setxattr notify [3,1,SCMP_CMP_EQ] +const seccompNotifySetxattr = `setxattr notify [3,1,SCMP_CMP_EQ] ` -const COMPAT_BLOCKING_POLICY = `[%s] +const compatBlockingPolicy = `[%s] compat_sys_rt_sigaction errno 38 stub_x32_rt_sigreturn errno 38 compat_sys_ioctl errno 38 @@ -334,13 +337,28 @@ compat_sys_io_submit errno 38 stub_x32_execveat errno 38 ` +// Instance is a seccomp specific instance interface. +type Instance interface { + Name() string + Project() string + ExpandedConfig() map[string]string + IsPrivileged() bool + DaemonState() *state.State + Architecture() int + RootfsPath() string + CurrentIdmap() (*idmap.IdmapSet, error) + InsertSeccompUnixDevice(prefix string, m config.Device, pid int) error +} + var seccompPath = shared.VarPath("security", "seccomp") -func SeccompProfilePath(c container) string { +// ProfilePath returns the seccomp path for the instance. +func ProfilePath(c Instance) string { return path.Join(seccompPath, c.Name()) } -func seccompContainerNeedsPolicy(c container) bool { +// InstanceNeedsPolicy returns whether the instance needs a policy or not. +func InstanceNeedsPolicy(c Instance) bool { config := c.ExpandedConfig() // Check for text keys @@ -385,7 +403,8 @@ func seccompContainerNeedsPolicy(c container) bool { return false } -func seccompContainerNeedsIntercept(c container) (bool, error) { +// InstanceNeedsIntercept returns whether instance needs intercept. +func InstanceNeedsIntercept(c Instance) (bool, error) { // No need if privileged if c.IsPrivileged() { return false, nil @@ -420,7 +439,7 @@ func seccompContainerNeedsIntercept(c container) (bool, error) { return needed, nil } -func seccompGetPolicyContent(c container) (string, error) { +func seccompGetPolicyContent(c Instance) (string, error) { config := c.ExpandedConfig() // Full policy override @@ -430,7 +449,7 @@ func seccompGetPolicyContent(c container) (string, error) { } // Policy header - policy := SECCOMP_HEADER + policy := seccompHeader whitelist := config["security.syscalls.whitelist"] if whitelist != "" { policy += "whitelist\n[all]\n" @@ -438,25 +457,25 @@ func seccompGetPolicyContent(c container) (string, error) { } else { policy += "blacklist\n" - default_, ok := config["security.syscalls.blacklist_default"] - if !ok || shared.IsTrue(default_) { - policy += DEFAULT_SECCOMP_POLICY + defaultFlag, ok := config["security.syscalls.blacklist_default"] + if !ok || shared.IsTrue(defaultFlag) { + policy += defaultSeccompPolicy } } // Syscall interception - ok, err := seccompContainerNeedsIntercept(c) + ok, err := InstanceNeedsIntercept(c) if err != nil { return "", err } if ok { if shared.IsTrue(config["security.syscalls.intercept.mknod"]) { - policy += SECCOMP_NOTIFY_MKNOD + policy += seccompNotifyMknod } if shared.IsTrue(config["security.syscalls.intercept.setxattr"]) { - policy += SECCOMP_NOTIFY_SETXATTR + policy += seccompNotifySetxattr } } @@ -471,7 +490,7 @@ func seccompGetPolicyContent(c container) (string, error) { if err != nil { return "", err } - policy += fmt.Sprintf(COMPAT_BLOCKING_POLICY, arch) + policy += fmt.Sprintf(compatBlockingPolicy, arch) } blacklist := config["security.syscalls.blacklist"] @@ -482,14 +501,15 @@ func seccompGetPolicyContent(c container) (string, error) { return policy, nil } -func SeccompCreateProfile(c container) error { +// CreateProfile creates a seccomp profile. +func CreateProfile(c Instance) error { /* Unlike apparmor, there is no way to "cache" profiles, and profiles * are automatically unloaded when a task dies. Thus, we don't need to * unload them when a container stops, and we don't have to worry about * the mtime on the file for any compiler purpose, so let's just write * out the profile. */ - if !seccompContainerNeedsPolicy(c) { + if !InstanceNeedsPolicy(c) { return nil } @@ -502,23 +522,26 @@ func SeccompCreateProfile(c container) error { return err } - return ioutil.WriteFile(SeccompProfilePath(c), []byte(profile), 0600) + return ioutil.WriteFile(ProfilePath(c), []byte(profile), 0600) } -func SeccompDeleteProfile(c container) { +// DeleteProfile removes a seccomp profile. +func DeleteProfile(c Instance) { /* similar to AppArmor, if we've never started this container, the * delete can fail and that's ok. */ - os.Remove(SeccompProfilePath(c)) + os.Remove(ProfilePath(c)) } -type SeccompServer struct { - d *Daemon +// Server defines a seccomp server. +type Server struct { + s *state.State path string l net.Listener } -type SeccompIovec struct { +// Iovec defines an iovec to move data between kernel and userspace. +type Iovec struct { ucred *ucred.UCred memFd int procFd int @@ -529,30 +552,31 @@ type SeccompIovec struct { iov *C.struct_iovec } -func NewSeccompIovec(ucred *ucred.UCred) *SeccompIovec { - msg_ptr := C.malloc(C.sizeof_struct_seccomp_notify_proxy_msg) - msg := (*C.struct_seccomp_notify_proxy_msg)(msg_ptr) - C.memset(msg_ptr, 0, C.sizeof_struct_seccomp_notify_proxy_msg) +// NewSeccompIovec creates a new seccomp iovec. +func NewSeccompIovec(ucred *ucred.UCred) *Iovec { + msgPtr := C.malloc(C.sizeof_struct_seccomp_notify_proxy_msg) + msg := (*C.struct_seccomp_notify_proxy_msg)(msgPtr) + C.memset(msgPtr, 0, C.sizeof_struct_seccomp_notify_proxy_msg) - req_ptr := C.malloc(C.sizeof_struct_seccomp_notif) - req := (*C.struct_seccomp_notif)(req_ptr) - C.memset(req_ptr, 0, C.sizeof_struct_seccomp_notif) + regPtr := C.malloc(C.sizeof_struct_seccomp_notif) + req := (*C.struct_seccomp_notif)(regPtr) + C.memset(regPtr, 0, C.sizeof_struct_seccomp_notif) - resp_ptr := C.malloc(C.sizeof_struct_seccomp_notif_resp) - resp := (*C.struct_seccomp_notif_resp)(resp_ptr) - C.memset(resp_ptr, 0, C.sizeof_struct_seccomp_notif_resp) + respPtr := C.malloc(C.sizeof_struct_seccomp_notif_resp) + resp := (*C.struct_seccomp_notif_resp)(respPtr) + C.memset(respPtr, 0, C.sizeof_struct_seccomp_notif_resp) - cookie_ptr := C.malloc(64 * C.sizeof_char) - cookie := (*C.char)(cookie_ptr) - C.memset(cookie_ptr, 0, 64*C.sizeof_char) + cookiePtr := C.malloc(64 * C.sizeof_char) + cookie := (*C.char)(cookiePtr) + C.memset(cookiePtr, 0, 64*C.sizeof_char) - iov_unsafe_ptr := C.malloc(4 * C.sizeof_struct_iovec) - iov := (*C.struct_iovec)(iov_unsafe_ptr) - C.memset(iov_unsafe_ptr, 0, 4*C.sizeof_struct_iovec) + iovUnsafePtr := C.malloc(4 * C.sizeof_struct_iovec) + iov := (*C.struct_iovec)(iovUnsafePtr) + C.memset(iovUnsafePtr, 0, 4*C.sizeof_struct_iovec) C.prepare_seccomp_iovec(iov, msg, req, resp, cookie) - return &SeccompIovec{ + return &Iovec{ memFd: -1, procFd: -1, msg: msg, @@ -564,7 +588,8 @@ func NewSeccompIovec(ucred *ucred.UCred) *SeccompIovec { } } -func (siov *SeccompIovec) PutSeccompIovec() { +// PutSeccompIovec puts a seccomp iovec. +func (siov *Iovec) PutSeccompIovec() { if siov.memFd >= 0 { unix.Close(siov.memFd) } @@ -578,7 +603,8 @@ func (siov *SeccompIovec) PutSeccompIovec() { C.free(unsafe.Pointer(siov.iov)) } -func (siov *SeccompIovec) ReceiveSeccompIovec(fd int) (uint64, error) { +// ReceiveSeccompIovec recieves a seccomp iovec. +func (siov *Iovec) ReceiveSeccompIovec(fd int) (uint64, error) { bytes, fds, err := netutils.AbstractUnixReceiveFdData(fd, 2, unsafe.Pointer(siov.iov), 4) if err != nil || err == io.EOF { return 0, err @@ -594,7 +620,8 @@ func (siov *SeccompIovec) ReceiveSeccompIovec(fd int) (uint64, error) { return bytes, nil } -func (siov *SeccompIovec) IsValidSeccompIovec(size uint64) bool { +// IsValidSeccompIovec checks whether a seccomp iovec is valid. +func (siov *Iovec) IsValidSeccompIovec(size uint64) bool { if size < uint64(C.SECCOMP_MSG_SIZE_MIN) { logger.Warnf("Disconnected from seccomp socket after incomplete receive") return false @@ -626,7 +653,8 @@ func (siov *SeccompIovec) IsValidSeccompIovec(size uint64) bool { return true } -func (siov *SeccompIovec) SendSeccompIovec(fd int, errno int) error { +// SendSeccompIovec sends seccomp iovec. +func (siov *Iovec) SendSeccompIovec(fd int, errno int) error { C.seccomp_notify_update_response(siov.resp, C.int(errno)) msghdr := C.struct_msghdr{} @@ -651,7 +679,8 @@ retry: return nil } -func NewSeccompServer(d *Daemon, path string) (*SeccompServer, error) { +// NewSeccompServer creates a new seccomp server. +func NewSeccompServer(s *state.State, path string, findPID func(pid int32, state *state.State) (Instance, error)) (*Server, error) { ret := C.seccomp_notify_get_sizes(&C.expected_sizes) if ret < 0 { return nil, fmt.Errorf("Failed to query kernel for seccomp notifier sizes") @@ -678,8 +707,8 @@ func NewSeccompServer(d *Daemon, path string) (*SeccompServer, error) { } // Start the server - s := SeccompServer{ - d: d, + server := Server{ + s: s, path: path, l: l, } @@ -715,101 +744,103 @@ func NewSeccompServer(d *Daemon, path string) (*SeccompServer, error) { } if siov.IsValidSeccompIovec(bytes) { - go s.Handler(int(unixFile.Fd()), siov) + go server.handler(int(unixFile.Fd()), siov, findPID) } else { - go s.InvalidHandler(int(unixFile.Fd()), siov) + go server.InvalidHandler(int(unixFile.Fd()), siov) } } }() } }() - return &s, nil + return &server, nil } -func taskIds(pid int) (error, int64, int64, int64, int64) { +// TaskIDs returns the task IDs for a process. +func TaskIDs(pid int) (int64, int64, int64, int64, error) { status, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/status", pid)) if err != nil { - return err, -1, -1, -1, -1 + return -1, -1, -1, -1, err } - reUid := regexp.MustCompile("Uid:\\s*([0-9]*)\\s*([0-9]*)\\s*([0-9]*)\\s*([0-9]*)") - reGid := regexp.MustCompile("Gid:\\s*([0-9]*)\\s*([0-9]*)\\s*([0-9]*)\\s*([0-9]*)") - var gid int64 = -1 - var uid int64 = -1 - var fsgid int64 = -1 - var fsuid int64 = -1 - uidFound := false - gidFound := false + reUID := regexp.MustCompile("Uid:\\s*([0-9]*)\\s*([0-9]*)\\s*([0-9]*)\\s*([0-9]*)") + reGID := regexp.MustCompile("Gid:\\s*([0-9]*)\\s*([0-9]*)\\s*([0-9]*)\\s*([0-9]*)") + var UID int64 = -1 + var GID int64 = -1 + var fsUID int64 = -1 + var fsGID int64 = -1 + UIDFound := false + GIDFound := false for _, line := range strings.Split(string(status), "\n") { - if uidFound && gidFound { + if UIDFound && GIDFound { break } - if !uidFound { - m := reUid.FindStringSubmatch(line) + if !UIDFound { + m := reUID.FindStringSubmatch(line) if m != nil && len(m) > 2 { // effective uid result, err := strconv.ParseInt(m[2], 10, 64) if err != nil { - return err, -1, -1, -1, -1 + return -1, -1, -1, -1, err } - uid = result - uidFound = true + UID = result + UIDFound = true } if m != nil && len(m) > 4 { // fsuid result, err := strconv.ParseInt(m[4], 10, 64) if err != nil { - return err, -1, -1, -1, -1 + return -1, -1, -1, -1, err } - fsuid = result + fsUID = result } continue } - if !gidFound { - m := reGid.FindStringSubmatch(line) + if !GIDFound { + m := reGID.FindStringSubmatch(line) if m != nil && len(m) > 2 { // effective gid result, err := strconv.ParseInt(m[2], 10, 64) if err != nil { - return err, -1, -1, -1, -1 + return -1, -1, -1, -1, err } - gid = result - gidFound = true + GID = result + GIDFound = true } if m != nil && len(m) > 4 { // fsgid result, err := strconv.ParseInt(m[4], 10, 64) if err != nil { - return err, -1, -1, -1, -1 + return -1, -1, -1, -1, err } - fsgid = result + fsGID = result } continue } } - return nil, uid, gid, fsuid, fsgid + return UID, GID, fsUID, fsGID, nil } -func CallForkmknod(c container, dev config.Device, requestPID int) int { +// CallForkmknod executes fork mknod. +func CallForkmknod(c Instance, dev config.Device, requestPID int) int { rootLink := fmt.Sprintf("/proc/%d/root", requestPID) rootPath, err := os.Readlink(rootLink) if err != nil { return int(-C.EPERM) } - err, uid, gid, fsuid, fsgid := taskIds(requestPID) + uid, gid, fsuid, fsgid, err := TaskIDs(requestPID) if err != nil { return int(-C.EPERM) } @@ -846,12 +877,13 @@ func CallForkmknod(c container, dev config.Device, requestPID int) int { // InvalidHandler sends a dummy message to LXC. LXC will notice the short write // and send a default message to the kernel thereby avoiding a 30s hang. -func (s *SeccompServer) InvalidHandler(fd int, siov *SeccompIovec) { +func (s *Server) InvalidHandler(fd int, siov *Iovec) { msghdr := C.struct_msghdr{} C.sendmsg(C.int(fd), &msghdr, C.MSG_NOSIGNAL) siov.PutSeccompIovec() } +// MknodArgs arguments for mknod. type MknodArgs struct { cMode C.mode_t cDev C.dev_t @@ -859,7 +891,7 @@ type MknodArgs struct { path string } -func (s *SeccompServer) doDeviceSyscall(c container, args *MknodArgs, siov *SeccompIovec) int { +func (s *Server) doDeviceSyscall(c Instance, args *MknodArgs, siov *Iovec) int { dev := config.Device{} dev["type"] = "unix-char" dev["mode"] = fmt.Sprintf("%#o", args.cMode) @@ -883,7 +915,8 @@ func (s *SeccompServer) doDeviceSyscall(c container, args *MknodArgs, siov *Secc return 0 } -func (s *SeccompServer) HandleMknodSyscall(c container, siov *SeccompIovec) int { +// HandleMknodSyscall handles a mknod syscall. +func (s *Server) HandleMknodSyscall(c Instance, siov *Iovec) int { logger.Debug("Handling mknod syscall", log.Ctx{"container": c.Name(), "project": c.Project(), @@ -916,7 +949,8 @@ func (s *SeccompServer) HandleMknodSyscall(c container, siov *SeccompIovec) int return s.doDeviceSyscall(c, &args, siov) } -func (s *SeccompServer) HandleMknodatSyscall(c container, siov *SeccompIovec) int { +// HandleMknodatSyscall handles a mknodat syscall. +func (s *Server) HandleMknodatSyscall(c Instance, siov *Iovec) int { logger.Debug("Handling mknodat syscall", log.Ctx{"container": c.Name(), "project": c.Project(), @@ -956,6 +990,7 @@ func (s *SeccompServer) HandleMknodatSyscall(c container, siov *SeccompIovec) in return s.doDeviceSyscall(c, &args, siov) } +// SetxattrArgs arguments for setxattr. type SetxattrArgs struct { nsuid int64 nsgid int64 @@ -969,7 +1004,8 @@ type SetxattrArgs struct { flags C.int } -func (s *SeccompServer) HandleSetxattrSyscall(c container, siov *SeccompIovec) int { +// HandleSetxattrSyscall handles setxattr syscalls. +func (s *Server) HandleSetxattrSyscall(c Instance, siov *Iovec) int { logger.Debug("Handling setxattr syscall", log.Ctx{"container": c.Name(), "project": c.Project(), @@ -982,7 +1018,7 @@ func (s *SeccompServer) HandleSetxattrSyscall(c container, siov *SeccompIovec) i args := SetxattrArgs{} args.pid = int(siov.req.pid) - err, uid, gid, fsuid, fsgid := taskIds(args.pid) + uid, gid, fsuid, fsgid, err := TaskIDs(args.pid) if err != nil { return int(-C.EPERM) } @@ -1057,30 +1093,30 @@ func (s *SeccompServer) HandleSetxattrSyscall(c container, siov *SeccompIovec) i return 0 } -func (s *SeccompServer) HandleSyscall(c container, siov *SeccompIovec) int { +func (s *Server) handleSyscall(c Instance, siov *Iovec) int { switch int(C.seccomp_notify_get_syscall(siov.req, siov.resp)) { - case LxdSeccompNotifyMknod: + case lxdSeccompNotifyMknod: return s.HandleMknodSyscall(c, siov) - case LxdSeccompNotifyMknodat: + case lxdSeccompNotifyMknodat: return s.HandleMknodatSyscall(c, siov) - case LxdSeccompNotifySetxattr: + case lxdSeccompNotifySetxattr: return s.HandleSetxattrSyscall(c, siov) } return int(-C.EINVAL) } -func (s *SeccompServer) Handler(fd int, siov *SeccompIovec) error { +func (s *Server) handler(fd int, siov *Iovec, findPID func(pid int32, state *state.State) (Instance, error)) error { defer siov.PutSeccompIovec() - c, err := findContainerForPid(int32(siov.msg.monitor_pid), s.d) + c, err := findPID(int32(siov.msg.monitor_pid), s.s) if err != nil { siov.SendSeccompIovec(fd, int(-C.EPERM)) logger.Errorf("Failed to find container for monitor %d", siov.msg.monitor_pid) return err } - errno := s.HandleSyscall(c, siov) + errno := s.handleSyscall(c, siov) err = siov.SendSeccompIovec(fd, errno) if err != nil { @@ -1090,7 +1126,31 @@ func (s *SeccompServer) Handler(fd int, siov *SeccompIovec) error { return nil } -func (s *SeccompServer) Stop() error { +// Stop stops a seccomp server. +func (s *Server) Stop() error { os.Remove(s.path) return s.l.Close() } + +func lxcSupportSeccompNotify(state *state.State) bool { + if !state.OS.SeccompListener { + return false + } + + if !state.OS.LXCFeatures["seccomp_notify"] { + return false + } + + c, err := lxc.NewContainer("test-seccomp", state.OS.LxcPath) + if err != nil { + return false + } + + err = c.SetConfigItem("lxc.seccomp.notify.proxy", fmt.Sprintf("unix:%s", shared.VarPath("seccomp.socket"))) + if err != nil { + return false + } + + c.Release() + return true +} From 762451d536e436bbe7b7238125cf1ac37b51a9ea Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Thu, 26 Sep 2019 17:43:32 +0100 Subject: [PATCH 2/6] lxd/daemon: Updates to use seccomp package - Updates to use seccomp package. - Uses workaround to expose findContainerForPid to seccomp package. - Adds call to seccomp server Stop() on LXD shutdown. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/daemon.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lxd/daemon.go b/lxd/daemon.go index 2d2d433ee5..9203e8c0fd 100644 --- a/lxd/daemon.go +++ b/lxd/daemon.go @@ -36,6 +36,7 @@ import ( "github.com/lxc/lxd/lxd/maas" "github.com/lxc/lxd/lxd/node" "github.com/lxc/lxd/lxd/rbac" + "github.com/lxc/lxd/lxd/seccomp" "github.com/lxc/lxd/lxd/state" "github.com/lxc/lxd/lxd/sys" "github.com/lxc/lxd/lxd/task" @@ -72,7 +73,7 @@ type Daemon struct { config *DaemonConfig endpoints *endpoints.Endpoints gateway *cluster.Gateway - seccomp *SeccompServer + seccomp *seccomp.Server proxy func(req *http.Request) (*url.URL, error) @@ -876,7 +877,9 @@ func (d *Daemon) init() error { // Setup seccomp handler if d.os.SeccompListener { - seccompServer, err := NewSeccompServer(d, shared.VarPath("seccomp.socket")) + seccompServer, err := seccomp.NewSeccompServer(d.State(), shared.VarPath("seccomp.socket"), func(pid int32, state *state.State) (seccomp.Instance, error) { + return findContainerForPid(pid, state) + }) if err != nil { return err } @@ -1090,6 +1093,10 @@ func (d *Daemon) Stop() error { "Not unmounting temporary filesystems (containers are still running)") } + if d.seccomp != nil { + trackError(d.seccomp.Stop()) + } + var err error if n := len(errs); n > 0 { format := "%v" From dd7a4f4c18de76e21776432b9e3e394e6bc10d95 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Thu, 26 Sep 2019 17:44:52 +0100 Subject: [PATCH 3/6] lxd/container/lxc: Removes lxcSupportSeccompNotify - This has moved to seccomp package. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/container_lxc.go | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go index 0f8fb885a3..a82fafd239 100644 --- a/lxd/container_lxc.go +++ b/lxd/container_lxc.go @@ -206,29 +206,6 @@ func lxcParseRawLXC(line string) (string, string, error) { return key, val, nil } -func lxcSupportSeccompNotify(state *state.State) bool { - if !state.OS.SeccompListener { - return false - } - - if !state.OS.LXCFeatures["seccomp_notify"] { - return false - } - - c, err := lxc.NewContainer("test-seccomp", state.OS.LxcPath) - if err != nil { - return false - } - - err = c.SetConfigItem("lxc.seccomp.notify.proxy", fmt.Sprintf("unix:%s", shared.VarPath("seccomp.socket"))) - if err != nil { - return false - } - - c.Release() - return true -} - func lxcValidConfig(rawLxc string) error { for _, line := range strings.Split(rawLxc, "\n") { key, _, err := lxcParseRawLXC(line) From 90c29b01d1db4afc23d2d2c5a47ed66080266852 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Thu, 26 Sep 2019 17:45:20 +0100 Subject: [PATCH 4/6] lxd: Updates to use seccomp package Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/container_lxc.go | 13 +++++++------ lxd/devlxd.go | 9 +++++---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go index a82fafd239..cc83a3a7cb 100644 --- a/lxd/container_lxc.go +++ b/lxd/container_lxc.go @@ -34,6 +34,7 @@ import ( "github.com/lxc/lxd/lxd/instance/instancetype" "github.com/lxc/lxd/lxd/maas" "github.com/lxc/lxd/lxd/project" + "github.com/lxc/lxd/lxd/seccomp" "github.com/lxc/lxd/lxd/state" driver "github.com/lxc/lxd/lxd/storage" "github.com/lxc/lxd/lxd/template" @@ -1257,15 +1258,15 @@ func (c *containerLXC) initLXC(config bool) error { } // Setup Seccomp if necessary - if seccompContainerNeedsPolicy(c) { - err = lxcSetConfigItem(cc, "lxc.seccomp.profile", SeccompProfilePath(c)) + if seccomp.InstanceNeedsPolicy(c) { + err = lxcSetConfigItem(cc, "lxc.seccomp.profile", seccomp.ProfilePath(c)) if err != nil { return err } // Setup notification socket // System requirement errors are handled during policy generation instead of here - ok, err := seccompContainerNeedsIntercept(c) + ok, err := seccomp.InstanceNeedsIntercept(c) if err == nil && ok { err = lxcSetConfigItem(cc, "lxc.seccomp.notify.proxy", fmt.Sprintf("unix:%s", shared.VarPath("seccomp.socket"))) if err != nil { @@ -2260,7 +2261,7 @@ func (c *containerLXC) startCommon() (string, []func() error, error) { } // Generate the Seccomp profile - if err := SeccompCreateProfile(c); err != nil { + if err := seccomp.CreateProfile(c); err != nil { return "", postStartHooks, err } @@ -3606,7 +3607,7 @@ func (c *containerLXC) cleanup() { // Remove the security profiles AADeleteProfile(c) - SeccompDeleteProfile(c) + seccomp.DeleteProfile(c) // Remove the devices path os.Remove(c.DevicesPath()) @@ -6360,7 +6361,7 @@ func (c *containerLXC) InsertSeccompUnixDevice(prefix string, m config.Device, p return err } - err, uid, gid, _, _ := taskIds(pid) + uid, gid, _, _, err := seccomp.TaskIDs(pid) if err != nil { return err } diff --git a/lxd/devlxd.go b/lxd/devlxd.go index 060eafef4e..f5f2baab2d 100644 --- a/lxd/devlxd.go +++ b/lxd/devlxd.go @@ -20,6 +20,7 @@ import ( "github.com/lxc/lxd/lxd/events" "github.com/lxc/lxd/lxd/instance/instancetype" + "github.com/lxc/lxd/lxd/state" "github.com/lxc/lxd/lxd/ucred" "github.com/lxc/lxd/lxd/util" "github.com/lxc/lxd/shared" @@ -217,7 +218,7 @@ func hoistReq(f func(*Daemon, container, http.ResponseWriter, *http.Request) *de return } - c, err := findContainerForPid(cred.PID, d) + c, err := findContainerForPid(cred.PID, d.State()) if err != nil { http.Error(w, err.Error(), 500) return @@ -352,7 +353,7 @@ func extractUnderlyingConn(w http.ResponseWriter) *net.UnixConn { var pidNotInContainerErr = fmt.Errorf("pid not in container?") -func findContainerForPid(pid int32, d *Daemon) (container, error) { +func findContainerForPid(pid int32, s *state.State) (container, error) { /* * Try and figure out which container a pid is in. There is probably a * better way to do this. Based on rharper's initial performance @@ -390,7 +391,7 @@ func findContainerForPid(pid int32, d *Daemon) (container, error) { name = fields[1] } - inst, err := instanceLoadByProjectAndName(d.State(), project, name) + inst, err := instanceLoadByProjectAndName(s, project, name) if err != nil { return nil, err } @@ -428,7 +429,7 @@ func findContainerForPid(pid int32, d *Daemon) (container, error) { return nil, err } - instances, err := instanceLoadNodeAll(d.State()) + instances, err := instanceLoadNodeAll(s) if err != nil { return nil, err } From 5f9af0685303c2729f36d07c24cf4d30ea415d4c Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Thu, 26 Sep 2019 17:46:24 +0100 Subject: [PATCH 5/6] test: Adds seccomp package to static analysis Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- test/suites/static_analysis.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/test/suites/static_analysis.sh b/test/suites/static_analysis.sh index 835634c79a..4533126afc 100644 --- a/test/suites/static_analysis.sh +++ b/test/suites/static_analysis.sh @@ -93,6 +93,7 @@ test_static_analysis() { golint -set_exit_status lxd/iptables/... golint -set_exit_status lxd/instance/... golint -set_exit_status lxd/unixcred/... + golint -set_exit_status lxd/seccomp/... golint -set_exit_status shared/api/ golint -set_exit_status shared/cancel/ From a42b6203fe39ac1784e46e453318ae56e214447b Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Thu, 26 Sep 2019 17:47:51 +0100 Subject: [PATCH 6/6] test: Fixes static analysis for ucred package Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- test/suites/static_analysis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/suites/static_analysis.sh b/test/suites/static_analysis.sh index 4533126afc..d335b7e67b 100644 --- a/test/suites/static_analysis.sh +++ b/test/suites/static_analysis.sh @@ -92,7 +92,7 @@ test_static_analysis() { golint -set_exit_status lxd/dnsmasq/... golint -set_exit_status lxd/iptables/... golint -set_exit_status lxd/instance/... - golint -set_exit_status lxd/unixcred/... + golint -set_exit_status lxd/ucred/... golint -set_exit_status lxd/seccomp/... golint -set_exit_status shared/api/
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel