The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/2818
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) ===
From 25a5b2be3790026273ddbc2cf13934d4cf63ef51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Tue, 24 Jan 2017 15:45:59 -0500 Subject: [PATCH 1/4] Don't attempt to read xattrs from symlinks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #2801 Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- lxd/container_lxc.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go index 6a9c7e0..a67dc16 100644 --- a/lxd/container_lxc.go +++ b/lxd/container_lxc.go @@ -4798,10 +4798,12 @@ func (c *containerLXC) tarStoreFile(linkmap map[uint64]string, offset int, tw *t } } - // Handle xattrs. - hdr.Xattrs, err = shared.GetAllXattr(path) - if err != nil { - return fmt.Errorf("failed to read xattr: %s", err) + // Handle xattrs (for real files only) + if link == "" { + hdr.Xattrs, err = shared.GetAllXattr(path) + if err != nil { + return fmt.Errorf("failed to read xattr: %s", err) + } } if err := tw.WriteHeader(hdr); err != nil { From faa53197550180b80090312bc951c3fe34887684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Tue, 24 Jan 2017 16:32:32 -0500 Subject: [PATCH 2/4] Remove GroupName function and add UserId one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- shared/util_linux.go | 46 ++++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/shared/util_linux.go b/shared/util_linux.go index 9ce2fb0..87b44d6 100644 --- a/shared/util_linux.go +++ b/shared/util_linux.go @@ -19,18 +19,19 @@ import ( // #cgo LDFLAGS: -lutil -lpthread /* #define _GNU_SOURCE -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <stdlib.h> -#include <grp.h> -#include <pty.h> #include <errno.h> #include <fcntl.h> +#include <grp.h> #include <limits.h> #include <poll.h> -#include <string.h> +#include <pty.h> +#include <pwd.h> #include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> #ifndef AT_SYMLINK_FOLLOW #define AT_SYMLINK_FOLLOW 0x400 @@ -277,36 +278,36 @@ func Pipe() (master *os.File, slave *os.File, err error) { return master, slave, nil } -// GroupName is an adaption from https://codereview.appspot.com/4589049. -func GroupName(gid int) (string, error) { - var grp C.struct_group - var result *C.struct_group +// UserId is an adaption from https://codereview.appspot.com/4589049. +func UserId(name string) (int, error) { + var pw C.struct_passwd + var result *C.struct_passwd - bufSize := C.size_t(C.sysconf(C._SC_GETGR_R_SIZE_MAX)) + bufSize := C.size_t(C.sysconf(C._SC_GETPW_R_SIZE_MAX)) buf := C.malloc(bufSize) if buf == nil { - return "", fmt.Errorf("allocation failed") + return -1, fmt.Errorf("allocation failed") } defer C.free(buf) - // mygetgrgid_r is a wrapper around getgrgid_r to - // to avoid using gid_t because C.gid_t(gid) for - // unknown reasons doesn't work on linux. - rv := C.mygetgrgid_r(C.int(gid), - &grp, + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + + rv := C.getpwnam_r(cname, + &pw, (*C.char)(buf), bufSize, &result) if rv != 0 { - return "", fmt.Errorf("failed group lookup: %s", syscall.Errno(rv)) + return -1, fmt.Errorf("failed user lookup: %s", syscall.Errno(rv)) } if result == nil { - return "", fmt.Errorf("unknown group %d", gid) + return -1, fmt.Errorf("unknown user %s", name) } - return C.GoString(result.gr_name), nil + return int(C.int(result.pw_uid)), nil } // GroupId is an adaption from https://codereview.appspot.com/4589049. @@ -321,9 +322,6 @@ func GroupId(name string) (int, error) { } defer C.free(buf) - // mygetgrgid_r is a wrapper around getgrgid_r to - // to avoid using gid_t because C.gid_t(gid) for - // unknown reasons doesn't work on linux. cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) From 7fd66ac74411afa108cdd70f01bdfd3fc24da9b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Tue, 24 Jan 2017 14:57:19 -0500 Subject: [PATCH 3/4] network: Update permissions of network directories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So that the unprivileged dnsmasq can read its config on reload. Closes #2804 Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- lxd/daemon.go | 3 +++ lxd/networks.go | 19 +++++++++++++++---- lxd/networks_utils.go | 2 +- lxd/patches.go | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/lxd/daemon.go b/lxd/daemon.go index c895e84..e0fc291 100644 --- a/lxd/daemon.go +++ b/lxd/daemon.go @@ -769,6 +769,9 @@ func (d *Daemon) Init() error { if err := os.MkdirAll(shared.VarPath("snapshots"), 0700); err != nil { return err } + if err := os.MkdirAll(shared.VarPath("networks"), 0711); err != nil { + return err + } /* Detect the filesystem */ d.BackingFs, err = filesystemDetect(d.lxcpath) diff --git a/lxd/networks.go b/lxd/networks.go index ce12c42..63a298c 100644 --- a/lxd/networks.go +++ b/lxd/networks.go @@ -525,7 +525,7 @@ func (n *network) Rename(name string) error { func (n *network) Start() error { // Create directory if !shared.PathExists(shared.VarPath("networks", n.name)) { - err := os.MkdirAll(shared.VarPath("networks", n.name), 0700) + err := os.MkdirAll(shared.VarPath("networks", n.name), 0711) if err != nil { return err } @@ -722,7 +722,7 @@ func (n *network) Start() error { } // Start building the dnsmasq command line - dnsmasqCmd := []string{"dnsmasq", "-u", "nobody", "--strict-order", "--bind-interfaces", + dnsmasqCmd := []string{"dnsmasq", "--strict-order", "--bind-interfaces", fmt.Sprintf("--pid-file=%s", shared.VarPath("networks", n.name, "dnsmasq.pid")), "--except-interface=lo", fmt.Sprintf("--interface=%s", n.name)} @@ -1125,12 +1125,12 @@ func (n *network) Start() error { // Configure dnsmasq if n.config["bridge.mode"] == "fan" || !shared.StringInSlice(n.config["ipv4.address"], []string{"", "none"}) || !shared.StringInSlice(n.config["ipv6.address"], []string{"", "none"}) { + // Setup the dnsmasq domain dnsDomain := n.config["dns.domain"] if dnsDomain == "" { dnsDomain = "lxd" } - // Setup the dnsmasq domain if n.config["dns.mode"] != "none" { dnsmasqCmd = append(dnsmasqCmd, []string{"-s", dnsDomain, "-S", fmt.Sprintf("/%s/", dnsDomain)}...) } @@ -1146,12 +1146,23 @@ func (n *network) Start() error { // Create DHCP hosts file if !shared.PathExists(shared.VarPath("networks", n.name, "dnsmasq.hosts")) { - err = ioutil.WriteFile(shared.VarPath("networks", n.name, "dnsmasq.hosts"), []byte(""), 0) + err = ioutil.WriteFile(shared.VarPath("networks", n.name, "dnsmasq.hosts"), []byte(""), 0644) if err != nil { return err } } + // Attempt to drop privileges + for _, user := range []string{"lxd", "nobody"} { + _, err := shared.UserId(user) + if err != nil { + continue + } + + dnsmasqCmd = append(dnsmasqCmd, []string{"-u", user}...) + break + } + // Start dnsmasq (occasionally races, try a few times) output, err := tryExec(dnsmasqCmd[0], dnsmasqCmd[1:]...) if err != nil { diff --git a/lxd/networks_utils.go b/lxd/networks_utils.go index 6122d9d..63bf295 100644 --- a/lxd/networks_utils.go +++ b/lxd/networks_utils.go @@ -749,7 +749,7 @@ func networkUpdateStatic(d *Daemon, name string) error { // Update the file if entries == nil { - err := ioutil.WriteFile(shared.VarPath("networks", network, "dnsmasq.hosts"), []byte(""), 0) + err := ioutil.WriteFile(shared.VarPath("networks", network, "dnsmasq.hosts"), []byte(""), 0644) if err != nil { return err } diff --git a/lxd/patches.go b/lxd/patches.go index ae1e258..f3dcc97 100644 --- a/lxd/patches.go +++ b/lxd/patches.go @@ -1,6 +1,7 @@ package main import ( + "os" "strings" "github.com/lxc/lxd/shared" @@ -28,6 +29,7 @@ import ( var patches = []patch{ {name: "invalid_profile_names", run: patchInvalidProfileNames}, {name: "leftover_profile_config", run: patchLeftoverProfileConfig}, + {name: "network_permissions", run: patchNetworkPermissions}, } type patch struct { @@ -105,3 +107,37 @@ func patchInvalidProfileNames(name string, d *Daemon) error { return nil } + +func patchNetworkPermissions(name string, d *Daemon) error { + // Get the list of networks + networks, err := dbNetworks(d.db) + if err != nil { + return err + } + + // Fix the permissions + err = os.Chmod(shared.VarPath("networks"), 0711) + if err != nil { + return err + } + + for _, network := range networks { + if !shared.PathExists(shared.VarPath("networks", network)) { + continue + } + + err = os.Chmod(shared.VarPath("networks", network), 0711) + if err != nil { + return err + } + + if shared.PathExists(shared.VarPath("networks", network, "dnsmasq.hosts")) { + err = os.Chmod(shared.VarPath("networks", network, "dnsmasq.hosts"), 0644) + if err != nil { + return err + } + } + } + + return nil +} From f4c1079ac1284652d62ef43d3b7e97ae5d5264b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Tue, 24 Jan 2017 17:30:25 -0500 Subject: [PATCH 4/4] network: Clean up leases for static assignments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is made a bit more difficult by the fact that dnsmasq won't reload its leases on SIGHUP... So we need to do a full dnsmasq restart to change the leases... Closes #2781 Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- lxd/container_lxc.go | 14 ++++++++++++- lxd/networks_utils.go | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go index a67dc16..1108e00 100644 --- a/lxd/container_lxc.go +++ b/lxd/container_lxc.go @@ -2649,8 +2649,20 @@ func (c *containerLXC) Delete() error { return err } - // Update lease files + // Update network files networkUpdateStatic(c.daemon, "") + for k, m := range c.expandedDevices { + if m["type"] != "nic" || m["nictype"] != "bridged" || (m["ipv4.address"] == "" && m["ipv6.address"] == "") { + continue + } + + m, err := c.fillNetworkDevice(k, m) + if err != nil { + continue + } + + networkClearLease(c.daemon, m["parent"], m["hwaddr"]) + } shared.LogInfo("Deleted container", ctxMap) diff --git a/lxd/networks_utils.go b/lxd/networks_utils.go index 63bf295..3418054 100644 --- a/lxd/networks_utils.go +++ b/lxd/networks_utils.go @@ -749,7 +749,7 @@ func networkUpdateStatic(d *Daemon, name string) error { // Update the file if entries == nil { - err := ioutil.WriteFile(shared.VarPath("networks", network, "dnsmasq.hosts"), []byte(""), 0644) + err := ioutil.WriteFile(shared.VarPath("networks", network, "dnsmasq.hosts"), []byte(""), 0) if err != nil { return err } @@ -810,3 +810,59 @@ func networkSysctl(path string, value string) error { return ioutil.WriteFile(fmt.Sprintf("/proc/sys/net/%s", path), []byte(value), 0) } + +func networkClearLease(d *Daemon, network string, hwaddr string) error { + leaseFile := shared.VarPath("networks", network, "dnsmasq.leases") + + // Check that we are in fact running a dnsmasq for the network + if !shared.PathExists(leaseFile) { + return nil + } + + // Restart the network when we're done here + n, err := networkLoadByName(d, network) + if err != nil { + return err + } + defer n.Start() + + // Stop dnsmasq + err = networkKillDnsmasq(network, false) + if err != nil { + return err + } + + // Mangle the lease file + leases, err := ioutil.ReadFile(leaseFile) + if err != nil { + return err + } + + fd, err := os.Create(leaseFile) + if err != nil { + return err + } + + for _, lease := range strings.Split(string(leases), "\n") { + if lease == "" { + continue + } + + fields := strings.Fields(lease) + if len(fields) > 2 && strings.ToLower(fields[1]) == strings.ToLower(hwaddr) { + continue + } + + _, err := fd.WriteString(fmt.Sprintf("%s\n", lease)) + if err != nil { + return err + } + } + + err = fd.Close() + if err != nil { + return err + } + + return nil +}
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel