[lxc-devel] [lxd/master] Reduce privileges and confine forkdns
stgraber on Github
lxc-bot at linuxcontainers.org
Mon Aug 10 21:39:25 UTC 2020
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 974 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200810/0e214d5c/attachment.bin>
-------------- next part --------------
From dd4e97f3bb84cd4919b48e207dc5796abc68dc14 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 10 Aug 2020 17:34:35 -0400
Subject: [PATCH 01/10] shared/usbid: Don't auto-load
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
shared/usbid/load.go | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/shared/usbid/load.go b/shared/usbid/load.go
index 39f6c4d831..65ef8f067f 100644
--- a/shared/usbid/load.go
+++ b/shared/usbid/load.go
@@ -28,7 +28,8 @@ var (
Classes map[ClassCode]*Class
)
-func init() {
+// Load reads the USB database from disk.
+func Load() {
usbids, err := os.Open("/usr/share/misc/usb.ids")
if err != nil {
if !os.IsNotExist(err) {
From 3699560ddca30d453d9950225fa25e5a0550cb77 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 10 Aug 2020 17:34:44 -0400
Subject: [PATCH 02/10] lxd/resources: Load USB database
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/resources/usb.go | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lxd/resources/usb.go b/lxd/resources/usb.go
index b848711a3c..6479d252fc 100644
--- a/lxd/resources/usb.go
+++ b/lxd/resources/usb.go
@@ -17,6 +17,9 @@ var sysBusUSB = "/sys/bus/usb/devices"
// GetUSB returns a filled api.ResourcesUSB struct ready for use by LXD
func GetUSB() (*api.ResourcesUSB, error) {
+ // Load the USB database.
+ usbid.Load()
+
usb := api.ResourcesUSB{}
if !sysfsExists(sysBusUSB) {
From 50dc6c718a586555d852deee7104c539ca43fcab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 10 Aug 2020 15:46:44 -0400
Subject: [PATCH 03/10] lxd/apparmor: Move dnsmasq functions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/apparmor/network.go | 57 -------------------------------
lxd/apparmor/network_dnsmasq.go | 59 +++++++++++++++++++++++++++++++++
2 files changed, 59 insertions(+), 57 deletions(-)
diff --git a/lxd/apparmor/network.go b/lxd/apparmor/network.go
index e3615c6812..15094083b1 100644
--- a/lxd/apparmor/network.go
+++ b/lxd/apparmor/network.go
@@ -1,16 +1,11 @@
package apparmor
import (
- "crypto/sha256"
- "fmt"
- "io"
"io/ioutil"
"os"
"path/filepath"
- "strings"
"github.com/lxc/lxd/lxd/state"
- "github.com/lxc/lxd/shared"
)
// Internal copy of the network interface.
@@ -18,35 +13,6 @@ type network interface {
Name() string
}
-// DnsmasqProfileName returns the AppArmor profile name.
-func DnsmasqProfileName(n network) string {
- path := shared.VarPath("")
- name := fmt.Sprintf("%s_<%s>", n.Name(), path)
-
- // Max length in AppArmor is 253 chars.
- if len(name)+12 >= 253 {
- hash := sha256.New()
- io.WriteString(hash, name)
- name = fmt.Sprintf("%x", hash.Sum(nil))
- }
-
- return fmt.Sprintf("lxd_dnsmasq-%s", name)
-}
-
-// dnsmasqProfileFilename returns the name of the on-disk profile name.
-func dnsmasqProfileFilename(n network) string {
- name := n.Name()
-
- // Max length in AppArmor is 253 chars.
- if len(name)+12 >= 253 {
- hash := sha256.New()
- io.WriteString(hash, name)
- name = fmt.Sprintf("%x", hash.Sum(nil))
- }
-
- return fmt.Sprintf("lxd_dnsmasq-%s", name)
-}
-
// NetworkLoad ensures that the network's profiles are loaded into the kernel.
func NetworkLoad(state *state.State, n network) error {
/* In order to avoid forcing a profile parse (potentially slow) on
@@ -101,26 +67,3 @@ func NetworkUnload(state *state.State, n network) error {
func NetworkDelete(state *state.State, n network) error {
return deleteProfile(state, dnsmasqProfileFilename(n))
}
-
-// dnsmasqProfile generates the AppArmor profile template from the given network.
-func dnsmasqProfile(state *state.State, n network) (string, error) {
- rootPath := ""
- if shared.InSnap() {
- rootPath = "/var/lib/snapd/hostfs"
- }
-
- // Render the profile.
- var sb *strings.Builder = &strings.Builder{}
- err := dnsmasqProfileTpl.Execute(sb, map[string]interface{}{
- "name": DnsmasqProfileName(n),
- "networkName": n.Name(),
- "varPath": shared.VarPath(""),
- "rootPath": rootPath,
- "snap": shared.InSnap(),
- })
- if err != nil {
- return "", err
- }
-
- return sb.String(), nil
-}
diff --git a/lxd/apparmor/network_dnsmasq.go b/lxd/apparmor/network_dnsmasq.go
index ea37daf863..0b63dc6048 100644
--- a/lxd/apparmor/network_dnsmasq.go
+++ b/lxd/apparmor/network_dnsmasq.go
@@ -1,7 +1,14 @@
package apparmor
import (
+ "crypto/sha256"
+ "fmt"
+ "io"
+ "strings"
"text/template"
+
+ "github.com/lxc/lxd/lxd/state"
+ "github.com/lxc/lxd/shared"
)
var dnsmasqProfileTpl = template.Must(template.New("dnsmasqProfile").Parse(`#include <tunables/global>
@@ -59,3 +66,55 @@ profile "{{ .name }}" flags=(attach_disconnected,mediate_deleted) {
{{- end }}
}
`))
+
+// dnsmasqProfile generates the AppArmor profile template from the given network.
+func dnsmasqProfile(state *state.State, n network) (string, error) {
+ rootPath := ""
+ if shared.InSnap() {
+ rootPath = "/var/lib/snapd/hostfs"
+ }
+
+ // Render the profile.
+ var sb *strings.Builder = &strings.Builder{}
+ err := dnsmasqProfileTpl.Execute(sb, map[string]interface{}{
+ "name": DnsmasqProfileName(n),
+ "networkName": n.Name(),
+ "varPath": shared.VarPath(""),
+ "rootPath": rootPath,
+ "snap": shared.InSnap(),
+ })
+ if err != nil {
+ return "", err
+ }
+
+ return sb.String(), nil
+}
+
+// DnsmasqProfileName returns the AppArmor profile name.
+func DnsmasqProfileName(n network) string {
+ path := shared.VarPath("")
+ name := fmt.Sprintf("%s_<%s>", n.Name(), path)
+
+ // Max length in AppArmor is 253 chars.
+ if len(name)+12 >= 253 {
+ hash := sha256.New()
+ io.WriteString(hash, name)
+ name = fmt.Sprintf("%x", hash.Sum(nil))
+ }
+
+ return fmt.Sprintf("lxd_dnsmasq-%s", name)
+}
+
+// dnsmasqProfileFilename returns the name of the on-disk profile name.
+func dnsmasqProfileFilename(n network) string {
+ name := n.Name()
+
+ // Max length in AppArmor is 253 chars.
+ if len(name)+12 >= 253 {
+ hash := sha256.New()
+ io.WriteString(hash, name)
+ name = fmt.Sprintf("%x", hash.Sum(nil))
+ }
+
+ return fmt.Sprintf("lxd_dnsmasq-%s", name)
+}
From 6488290da7a97b62925e7f73fbe86a8a0621c10c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 10 Aug 2020 15:47:41 -0400
Subject: [PATCH 04/10] lxd/apparmor: forkdns profile
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/apparmor/network.go | 52 +++++++++++++++-
lxd/apparmor/network_forkdns.go | 101 ++++++++++++++++++++++++++++++++
2 files changed, 152 insertions(+), 1 deletion(-)
create mode 100644 lxd/apparmor/network_forkdns.go
diff --git a/lxd/apparmor/network.go b/lxd/apparmor/network.go
index 15094083b1..f3efe516e5 100644
--- a/lxd/apparmor/network.go
+++ b/lxd/apparmor/network.go
@@ -10,6 +10,7 @@ import (
// Internal copy of the network interface.
type network interface {
+ Config() map[string]string
Name() string
}
@@ -26,6 +27,8 @@ func NetworkLoad(state *state.State, n network) error {
* version out so that the new changes are reflected and we definitely
* force a recompile.
*/
+
+ // dnsmasq
profile := filepath.Join(aaPath, "profiles", dnsmasqProfileFilename(n))
content, err := ioutil.ReadFile(profile)
if err != nil && !os.IsNotExist(err) {
@@ -49,21 +52,68 @@ func NetworkLoad(state *state.State, n network) error {
return err
}
+ // forkdns
+ if n.Config()["bridge.mode"] == "fan" {
+ profile := filepath.Join(aaPath, "profiles", forkdnsProfileFilename(n))
+ content, err := ioutil.ReadFile(profile)
+ if err != nil && !os.IsNotExist(err) {
+ return err
+ }
+
+ updated, err := forkdnsProfile(state, n)
+ if err != nil {
+ return err
+ }
+
+ if string(content) != string(updated) {
+ err = ioutil.WriteFile(profile, []byte(updated), 0600)
+ if err != nil {
+ return err
+ }
+ }
+
+ err = loadProfile(state, forkdnsProfileFilename(n))
+ if err != nil {
+ return err
+ }
+ }
+
return nil
}
// NetworkUnload ensures that the network's profiles are unloaded to free kernel memory.
// This does not delete the policy from disk or cache.
func NetworkUnload(state *state.State, n network) error {
+ // dnsmasq
err := unloadProfile(state, dnsmasqProfileFilename(n))
if err != nil {
return err
}
+ // forkdns
+ if n.Config()["bridge.mode"] == "fan" {
+ err := unloadProfile(state, forkdnsProfileFilename(n))
+ if err != nil {
+ return err
+ }
+ }
+
return nil
}
// NetworkDelete removes the profiles from cache/disk.
func NetworkDelete(state *state.State, n network) error {
- return deleteProfile(state, dnsmasqProfileFilename(n))
+ err := deleteProfile(state, dnsmasqProfileFilename(n))
+ if err != nil {
+ return err
+ }
+
+ if n.Config()["bridge.mode"] == "fan" {
+ err := deleteProfile(state, forkdnsProfileFilename(n))
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
}
diff --git a/lxd/apparmor/network_forkdns.go b/lxd/apparmor/network_forkdns.go
new file mode 100644
index 0000000000..396e87be67
--- /dev/null
+++ b/lxd/apparmor/network_forkdns.go
@@ -0,0 +1,101 @@
+package apparmor
+
+import (
+ "crypto/sha256"
+ "fmt"
+ "io"
+ "strings"
+ "text/template"
+
+ "github.com/lxc/lxd/lxd/state"
+ "github.com/lxc/lxd/shared"
+)
+
+var forkdnsProfileTpl = template.Must(template.New("forkdnsProfile").Parse(`#include <tunables/global>
+profile "{{ .name }}" flags=(attach_disconnected,mediate_deleted) {
+ #include <abstractions/base>
+
+ # Capabilities
+ capability net_bind_service,
+
+ # Network access
+ network inet dgram,
+ network inet6 dgram,
+
+ # Network-specific paths
+ {{ .varPath }}/networks/{{ .networkName }}/dnsmasq.leases r,
+ {{ .varPath }}/networks/{{ .networkName }}/forkdns.servers/servers.conf r,
+
+ # Needed for lxd fork commands
+ @{PROC}/@{pid}/cmdline r,
+ {{ .rootPath }}/{etc,lib,usr/lib}/os-release r,
+
+ # Things that we definitely don't need
+ deny @{PROC}/@{pid}/cgroup r,
+ deny /sys/module/apparmor/parameters/enabled r,
+ deny /sys/kernel/mm/transparent_hugepage/hpage_pmd_size r,
+
+{{- if .snap }}
+ # The binary itself (for nesting)
+ /var/snap/lxd/common/lxd.debug mr,
+ /snap/lxd/current/bin/lxd mr,
+ /snap/lxd/*/bin/lxd mr,
+
+ # Snap-specific libraries
+ /snap/lxd/current/lib/**.so* mr,
+ /snap/lxd/*/lib/**.so* mr,
+{{- end }}
+}
+`))
+
+// forkdnsProfile generates the AppArmor profile template from the given network.
+func forkdnsProfile(state *state.State, n network) (string, error) {
+ rootPath := ""
+ if shared.InSnap() {
+ rootPath = "/var/lib/snapd/hostfs"
+ }
+
+ // Render the profile.
+ var sb *strings.Builder = &strings.Builder{}
+ err := forkdnsProfileTpl.Execute(sb, map[string]interface{}{
+ "name": ForkdnsProfileName(n),
+ "networkName": n.Name(),
+ "varPath": shared.VarPath(""),
+ "rootPath": rootPath,
+ "snap": shared.InSnap(),
+ })
+ if err != nil {
+ return "", err
+ }
+
+ return sb.String(), nil
+}
+
+// ForkdnsProfileName returns the AppArmor profile name.
+func ForkdnsProfileName(n network) string {
+ path := shared.VarPath("")
+ name := fmt.Sprintf("%s_<%s>", n.Name(), path)
+
+ // Max length in AppArmor is 253 chars.
+ if len(name)+12 >= 253 {
+ hash := sha256.New()
+ io.WriteString(hash, name)
+ name = fmt.Sprintf("%x", hash.Sum(nil))
+ }
+
+ return fmt.Sprintf("lxd_forkdns-%s", name)
+}
+
+// forkdnsProfileFilename returns the name of the on-disk profile name.
+func forkdnsProfileFilename(n network) string {
+ name := n.Name()
+
+ // Max length in AppArmor is 253 chars.
+ if len(name)+12 >= 253 {
+ hash := sha256.New()
+ io.WriteString(hash, name)
+ name = fmt.Sprintf("%x", hash.Sum(nil))
+ }
+
+ return fmt.Sprintf("lxd_forkdns-%s", name)
+}
From 47b47dae003c1e72bd959710f2d585c481944749 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 10 Aug 2020 16:02:04 -0400
Subject: [PATCH 05/10] lxd/sys: Add unpriv uid/group
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/sys/os.go | 23 +++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/lxd/sys/os.go b/lxd/sys/os.go
index e18d917ed1..5dc6d1df61 100644
--- a/lxd/sys/os.go
+++ b/lxd/sys/os.go
@@ -49,8 +49,12 @@ type OS struct {
MockMode bool // If true some APIs will be mocked (for testing)
Nodev bool
RunningInUserNS bool
- UnprivUser string
- UnprivUID int
+
+ // Privilege dropping
+ UnprivUser string
+ UnprivUID uint32
+ UnprivGroup string
+ UnprivGID uint32
// Apparmor features
AppArmorAdmin bool
@@ -109,7 +113,7 @@ func (s *OS) Init() error {
logger.Error("Error detecting backing fs", log.Ctx{"err": err})
}
- // Detect if it is possible to run daemons as an unprivileged user.
+ // Detect if it is possible to run daemons as an unprivileged user and group.
for _, user := range []string{"lxd", "nobody"} {
uid, err := shared.UserId(user)
if err != nil {
@@ -117,7 +121,18 @@ func (s *OS) Init() error {
}
s.UnprivUser = user
- s.UnprivUID = uid
+ s.UnprivUID = uint32(uid)
+ break
+ }
+
+ for _, group := range []string{"lxd", "nogroup"} {
+ gid, err := shared.GroupId(group)
+ if err != nil {
+ continue
+ }
+
+ s.UnprivGroup = group
+ s.UnprivGID = uint32(gid)
break
}
From e38968777992e09519345aa51b3ca3bc6db6ae2a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 10 Aug 2020 16:16:26 -0400
Subject: [PATCH 06/10] lxd/instances: Update for OS type change
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/instance/drivers/driver_qemu.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lxd/instance/drivers/driver_qemu.go b/lxd/instance/drivers/driver_qemu.go
index cc12ed6d14..793d3668a3 100644
--- a/lxd/instance/drivers/driver_qemu.go
+++ b/lxd/instance/drivers/driver_qemu.go
@@ -766,7 +766,7 @@ func (vm *qemu) Start(stateful bool) error {
return err
}
- err = os.Chown(path, vm.state.OS.UnprivUID, -1)
+ err = os.Chown(path, int(vm.state.OS.UnprivUID), -1)
if err != nil {
op.Done(err)
return err
From ea00a24332dfb01836cd49007db5cc8bb0811ae2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 10 Aug 2020 16:17:44 -0400
Subject: [PATCH 07/10] shared/subprocess: s/Pid/PID/
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
shared/subprocess/proc.go | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/shared/subprocess/proc.go b/shared/subprocess/proc.go
index 45a02cddf3..9dc70abf56 100644
--- a/shared/subprocess/proc.go
+++ b/shared/subprocess/proc.go
@@ -25,7 +25,7 @@ type Process struct {
Name string `yaml:"name"`
Args []string `yaml:"args,flow"`
Apparmor string `yaml:"apparmor"`
- Pid int64 `yaml:"pid"`
+ PID int64 `yaml:"pid"`
Stdout string `yaml:"stdout"`
Stderr string `yaml:"stderr"`
}
@@ -45,10 +45,10 @@ func (p *Process) hasApparmor() bool {
// GetPid returns the pid for the given process object
func (p *Process) GetPid() (int64, error) {
- pr, _ := os.FindProcess(int(p.Pid))
+ pr, _ := os.FindProcess(int(p.PID))
err := pr.Signal(syscall.Signal(0))
if err == nil {
- return p.Pid, nil
+ return p.PID, nil
}
return 0, ErrNotRunning
@@ -61,7 +61,7 @@ func (p *Process) SetApparmor(profile string) {
// Stop will stop the given process object
func (p *Process) Stop() error {
- pr, _ := os.FindProcess(int(p.Pid))
+ pr, _ := os.FindProcess(int(p.PID))
// Check if process exists.
err := pr.Signal(syscall.Signal(0))
@@ -128,7 +128,7 @@ func (p *Process) Start() error {
return errors.Wrapf(err, "Unable to start process")
}
- p.Pid = int64(cmd.Process.Pid)
+ p.PID = int64(cmd.Process.Pid)
// Reset exitCode/exitErr
p.exitCode = 0
@@ -171,7 +171,7 @@ func (p *Process) Restart() error {
// Reload sends the SIGHUP signal to the given process object
func (p *Process) Reload() error {
- pr, _ := os.FindProcess(int(p.Pid))
+ pr, _ := os.FindProcess(int(p.PID))
err := pr.Signal(syscall.Signal(0))
if err == nil {
err = pr.Signal(syscall.SIGHUP)
@@ -203,7 +203,7 @@ func (p *Process) Save(path string) error {
// Signal will send a signal to the given process object given a signal value
func (p *Process) Signal(signal int64) error {
- pr, _ := os.FindProcess(int(p.Pid))
+ pr, _ := os.FindProcess(int(p.PID))
err := pr.Signal(syscall.Signal(0))
if err == nil {
err = pr.Signal(syscall.Signal(signal))
From 6a0cd60068ef6472df22d73000de518d9d1c7eaf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 10 Aug 2020 16:18:57 -0400
Subject: [PATCH 08/10] shared/subprocess: Add credentials
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
shared/subprocess/proc.go | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/shared/subprocess/proc.go b/shared/subprocess/proc.go
index 9dc70abf56..060637e681 100644
--- a/shared/subprocess/proc.go
+++ b/shared/subprocess/proc.go
@@ -28,6 +28,10 @@ type Process struct {
PID int64 `yaml:"pid"`
Stdout string `yaml:"stdout"`
Stderr string `yaml:"stderr"`
+
+ UID uint32 `yaml:"uid"`
+ GID uint32 `yaml:"gid"`
+ SetGroups bool `yaml:"set_groups"`
}
func (p *Process) hasApparmor() bool {
@@ -59,6 +63,12 @@ func (p *Process) SetApparmor(profile string) {
p.Apparmor = profile
}
+// SetCreds allows setting process credentials.
+func (p *Process) SetCreds(uid uint32, gid uint32) {
+ p.UID = uid
+ p.GID = gid
+}
+
// Stop will stop the given process object
func (p *Process) Stop() error {
pr, _ := os.FindProcess(int(p.PID))
@@ -101,6 +111,12 @@ func (p *Process) Start() error {
cmd.SysProcAttr = &syscall.SysProcAttr{}
cmd.SysProcAttr.Setsid = true
+ if p.UID != 0 || p.GID != 0 {
+ cmd.SysProcAttr.Credential = &syscall.Credential{}
+ cmd.SysProcAttr.Credential.Uid = p.UID
+ cmd.SysProcAttr.Credential.Gid = p.GID
+ }
+
// Setup output capture.
if p.Stdout != "" {
out, err := os.Create(p.Stdout)
From 7d13669ca6abb80c791c617dceaadca7e289e3d3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 10 Aug 2020 16:19:14 -0400
Subject: [PATCH 09/10] lxd/network: forkdns and creds drop for forkdns
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/network/driver_bridge.go | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/lxd/network/driver_bridge.go b/lxd/network/driver_bridge.go
index cb098e4b88..99542a2580 100644
--- a/lxd/network/driver_bridge.go
+++ b/lxd/network/driver_bridge.go
@@ -1544,6 +1544,12 @@ func (n *bridge) spawnForkDNS(listenAddress string) error {
return fmt.Errorf("Failed to create subprocess: %s", err)
}
+ // Drop privileges.
+ p.SetCreds(n.state.OS.UnprivUID, n.state.OS.UnprivGID)
+
+ // Apply AppArmor profile.
+ p.SetApparmor(apparmor.ForkdnsProfileName(n))
+
err = p.Start()
if err != nil {
return fmt.Errorf("Failed to run: %s %s: %v", command, strings.Join(forkdnsargs, " "), err)
From e008641ea17315147f1c3585dc1b23c58479a1ac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 10 Aug 2020 16:26:54 -0400
Subject: [PATCH 10/10] lxd/network: Run dnsmasq as unpriv group
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/network/driver_bridge.go | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lxd/network/driver_bridge.go b/lxd/network/driver_bridge.go
index 99542a2580..6891af0033 100644
--- a/lxd/network/driver_bridge.go
+++ b/lxd/network/driver_bridge.go
@@ -1269,6 +1269,9 @@ func (n *bridge) setup(oldConfig map[string]string) error {
if n.state.OS.UnprivUser != "" {
dnsmasqCmd = append(dnsmasqCmd, []string{"-u", n.state.OS.UnprivUser}...)
}
+ if n.state.OS.UnprivGroup != "" {
+ dnsmasqCmd = append(dnsmasqCmd, []string{"-g", n.state.OS.UnprivGroup}...)
+ }
// Create DHCP hosts directory.
if !shared.PathExists(shared.VarPath("networks", n.name, "dnsmasq.hosts")) {
More information about the lxc-devel
mailing list