[lxc-devel] [lxd/master] Apparmor, /dev/net/tun and bugfixes

stgraber on Github lxc-bot at linuxcontainers.org
Tue Jul 5 14:31:07 UTC 2016


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 359 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20160705/ce3b8d7c/attachment.bin>
-------------- next part --------------
From 0054f26edc5085f2973216b3634ac83a284ca441 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 30 Jun 2016 16:02:35 -0400
Subject: [PATCH 01/10] apparmor: Don't depend on the LXC apparmor profile
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Rather than depending on the LXC apparmor profile, just generate a
complete profile for each container.

This will allow some flexibility, for example, having completely
different profiles for privileged and unprivileged containers, or have
profiles vary based on kernel version.

Related to #1942

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/apparmor.go | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 228 insertions(+), 11 deletions(-)

diff --git a/lxd/apparmor.go b/lxd/apparmor.go
index ce25c50..d9a3d8a 100644
--- a/lxd/apparmor.go
+++ b/lxd/apparmor.go
@@ -50,17 +50,234 @@ const NESTING_AA_PROFILE = `
 const DEFAULT_AA_PROFILE = `
 #include <tunables/global>
 profile "%s" flags=(attach_disconnected,mediate_deleted) {
-    #include <abstractions/lxc/container-base>
-
-    # Special exception for cgroup namespaces
-    %s
-
-    # user input raw.apparmor below here
-    %s
-
-    # nesting support goes here if needed
-    %s
-    change_profile -> "%s",
+  network,
+  capability,
+  file,
+  umount,
+
+  # dbus, signal, ptrace and unix are only supported by recent apparmor
+  # versions. Comment them if the apparmor parser doesn't recognize them.
+
+  # This also needs additional rules to reach outside of the container via
+  # DBus, so just let all of DBus within the container.
+  dbus,
+
+  # Allow us to receive signals from anywhere. Note: if per-container profiles
+  # are supported, for container isolation this should be changed to something
+  # like:
+  #   signal (receive) peer=unconfined,
+  #   signal (receive) peer=/usr/bin/lxc-start,
+  signal (receive),
+
+  # Allow us to send signals to ourselves
+  signal peer=@{profile_name},
+
+  # Allow other processes to read our /proc entries, futexes, perf tracing and
+  # kcmp for now (they will need 'read' in the first place). Administrators can
+  # override with:
+  #   deny ptrace (readby) ...
+  ptrace (readby),
+
+  # Allow other processes to trace us by default (they will need 'trace' in
+  # the first place). Administrators can override with:
+  #   deny ptrace (tracedby) ...
+  ptrace (tracedby),
+
+  # Allow us to ptrace ourselves
+  ptrace peer=@{profile_name},
+
+  # Allow receive via unix sockets from anywhere. Note: if per-container
+  # profiles are supported, for container isolation this should be changed to
+  # something like:
+  #   unix (receive) peer=(label=unconfined),
+  unix (receive),
+
+  # Allow all unix in the container
+  unix peer=(label=@{profile_name}),
+
+  # ignore DENIED message on / remount
+  deny mount options=(ro, remount) -> /,
+  deny mount options=(ro, remount, silent) -> /,
+
+  # allow tmpfs mounts everywhere
+  mount fstype=tmpfs,
+
+  # allow hugetlbfs mounts everywhere
+  mount fstype=hugetlbfs,
+
+  # allow mqueue mounts everywhere
+  mount fstype=mqueue,
+
+  # allow fuse mounts everywhere
+  mount fstype=fuse,
+  mount fstype=fuse.*,
+
+  # deny access under /proc/bus to avoid e.g. messing with pci devices directly
+  deny @{PROC}/bus/** wklx,
+
+  # deny writes in /proc/sys/fs but allow binfmt_misc to be mounted
+  mount fstype=binfmt_misc -> /proc/sys/fs/binfmt_misc/,
+  deny @{PROC}/sys/fs/** wklx,
+
+  # allow efivars to be mounted, writing to it will be blocked though
+  mount fstype=efivarfs -> /sys/firmware/efi/efivars/,
+
+  # block some other dangerous paths
+  deny @{PROC}/kcore rwklx,
+  deny @{PROC}/kmem rwklx,
+  deny @{PROC}/mem rwklx,
+  deny @{PROC}/sysrq-trigger rwklx,
+
+  # deny writes in /sys except for /sys/fs/cgroup, also allow
+  # fusectl, securityfs and debugfs to be mounted there (read-only)
+  mount fstype=fusectl -> /sys/fs/fuse/connections/,
+  mount fstype=securityfs -> /sys/kernel/security/,
+  mount fstype=debugfs -> /sys/kernel/debug/,
+  deny mount fstype=debugfs -> /var/lib/ureadahead/debugfs/,
+  mount fstype=proc -> /proc/,
+  mount fstype=sysfs -> /sys/,
+  mount options=(rw, nosuid, nodev, noexec, remount) -> /sys/,
+  deny /sys/firmware/efi/efivars/** rwklx,
+  deny /sys/kernel/security/** rwklx,
+  mount options=(move) /sys/fs/cgroup/cgmanager/ -> /sys/fs/cgroup/cgmanager.lower/,
+  mount options=(ro, nosuid, nodev, noexec, remount, strictatime) -> /sys/fs/cgroup/,
+
+  # deny reads from debugfs
+  deny /sys/kernel/debug/{,**} rwklx,
+
+  # allow paths to be made slave, shared, private or unbindable
+  # FIXME: This currently doesn't work due to the apparmor parser treating those as allowing all mounts.
+#  mount options=(rw,make-slave) -> **,
+#  mount options=(rw,make-rslave) -> **,
+#  mount options=(rw,make-shared) -> **,
+#  mount options=(rw,make-rshared) -> **,
+#  mount options=(rw,make-private) -> **,
+#  mount options=(rw,make-rprivate) -> **,
+#  mount options=(rw,make-unbindable) -> **,
+#  mount options=(rw,make-runbindable) -> **,
+
+  # allow bind-mounts of anything except /proc, /sys and /dev
+  mount options=(rw,bind) /[^spd]*{,/**},
+  mount options=(rw,bind) /d[^e]*{,/**},
+  mount options=(rw,bind) /de[^v]*{,/**},
+  mount options=(rw,bind) /dev/.[^l]*{,/**},
+  mount options=(rw,bind) /dev/.l[^x]*{,/**},
+  mount options=(rw,bind) /dev/.lx[^c]*{,/**},
+  mount options=(rw,bind) /dev/.lxc?*{,/**},
+  mount options=(rw,bind) /dev/[^.]*{,/**},
+  mount options=(rw,bind) /dev?*{,/**},
+  mount options=(rw,bind) /p[^r]*{,/**},
+  mount options=(rw,bind) /pr[^o]*{,/**},
+  mount options=(rw,bind) /pro[^c]*{,/**},
+  mount options=(rw,bind) /proc?*{,/**},
+  mount options=(rw,bind) /s[^y]*{,/**},
+  mount options=(rw,bind) /sy[^s]*{,/**},
+  mount options=(rw,bind) /sys?*{,/**},
+
+  # allow moving mounts except for /proc, /sys and /dev
+  mount options=(rw,move) /[^spd]*{,/**},
+  mount options=(rw,move) /d[^e]*{,/**},
+  mount options=(rw,move) /de[^v]*{,/**},
+  mount options=(rw,move) /dev/.[^l]*{,/**},
+  mount options=(rw,move) /dev/.l[^x]*{,/**},
+  mount options=(rw,move) /dev/.lx[^c]*{,/**},
+  mount options=(rw,move) /dev/.lxc?*{,/**},
+  mount options=(rw,move) /dev/[^.]*{,/**},
+  mount options=(rw,move) /dev?*{,/**},
+  mount options=(rw,move) /p[^r]*{,/**},
+  mount options=(rw,move) /pr[^o]*{,/**},
+  mount options=(rw,move) /pro[^c]*{,/**},
+  mount options=(rw,move) /proc?*{,/**},
+  mount options=(rw,move) /s[^y]*{,/**},
+  mount options=(rw,move) /sy[^s]*{,/**},
+  mount options=(rw,move) /sys?*{,/**},
+
+  # generated by: lxc-generate-aa-rules.py container-rules.base
+  deny /proc/sys/[^kn]*{,/**} wklx,
+  deny /proc/sys/k[^e]*{,/**} wklx,
+  deny /proc/sys/ke[^r]*{,/**} wklx,
+  deny /proc/sys/ker[^n]*{,/**} wklx,
+  deny /proc/sys/kern[^e]*{,/**} wklx,
+  deny /proc/sys/kerne[^l]*{,/**} wklx,
+  deny /proc/sys/kernel/[^smhd]*{,/**} wklx,
+  deny /proc/sys/kernel/d[^o]*{,/**} wklx,
+  deny /proc/sys/kernel/do[^m]*{,/**} wklx,
+  deny /proc/sys/kernel/dom[^a]*{,/**} wklx,
+  deny /proc/sys/kernel/doma[^i]*{,/**} wklx,
+  deny /proc/sys/kernel/domai[^n]*{,/**} wklx,
+  deny /proc/sys/kernel/domain[^n]*{,/**} wklx,
+  deny /proc/sys/kernel/domainn[^a]*{,/**} wklx,
+  deny /proc/sys/kernel/domainna[^m]*{,/**} wklx,
+  deny /proc/sys/kernel/domainnam[^e]*{,/**} wklx,
+  deny /proc/sys/kernel/domainname?*{,/**} wklx,
+  deny /proc/sys/kernel/h[^o]*{,/**} wklx,
+  deny /proc/sys/kernel/ho[^s]*{,/**} wklx,
+  deny /proc/sys/kernel/hos[^t]*{,/**} wklx,
+  deny /proc/sys/kernel/host[^n]*{,/**} wklx,
+  deny /proc/sys/kernel/hostn[^a]*{,/**} wklx,
+  deny /proc/sys/kernel/hostna[^m]*{,/**} wklx,
+  deny /proc/sys/kernel/hostnam[^e]*{,/**} wklx,
+  deny /proc/sys/kernel/hostname?*{,/**} wklx,
+  deny /proc/sys/kernel/m[^s]*{,/**} wklx,
+  deny /proc/sys/kernel/ms[^g]*{,/**} wklx,
+  deny /proc/sys/kernel/msg*/** wklx,
+  deny /proc/sys/kernel/s[^he]*{,/**} wklx,
+  deny /proc/sys/kernel/se[^m]*{,/**} wklx,
+  deny /proc/sys/kernel/sem*/** wklx,
+  deny /proc/sys/kernel/sh[^m]*{,/**} wklx,
+  deny /proc/sys/kernel/shm*/** wklx,
+  deny /proc/sys/kernel?*{,/**} wklx,
+  deny /proc/sys/n[^e]*{,/**} wklx,
+  deny /proc/sys/ne[^t]*{,/**} wklx,
+  deny /proc/sys/net?*{,/**} wklx,
+  deny /sys/[^fdc]*{,/**} wklx,
+  deny /sys/c[^l]*{,/**} wklx,
+  deny /sys/cl[^a]*{,/**} wklx,
+  deny /sys/cla[^s]*{,/**} wklx,
+  deny /sys/clas[^s]*{,/**} wklx,
+  deny /sys/class/[^n]*{,/**} wklx,
+  deny /sys/class/n[^e]*{,/**} wklx,
+  deny /sys/class/ne[^t]*{,/**} wklx,
+  deny /sys/class/net?*{,/**} wklx,
+  deny /sys/class?*{,/**} wklx,
+  deny /sys/d[^e]*{,/**} wklx,
+  deny /sys/de[^v]*{,/**} wklx,
+  deny /sys/dev[^i]*{,/**} wklx,
+  deny /sys/devi[^c]*{,/**} wklx,
+  deny /sys/devic[^e]*{,/**} wklx,
+  deny /sys/device[^s]*{,/**} wklx,
+  deny /sys/devices/[^v]*{,/**} wklx,
+  deny /sys/devices/v[^i]*{,/**} wklx,
+  deny /sys/devices/vi[^r]*{,/**} wklx,
+  deny /sys/devices/vir[^t]*{,/**} wklx,
+  deny /sys/devices/virt[^u]*{,/**} wklx,
+  deny /sys/devices/virtu[^a]*{,/**} wklx,
+  deny /sys/devices/virtua[^l]*{,/**} wklx,
+  deny /sys/devices/virtual/[^n]*{,/**} wklx,
+  deny /sys/devices/virtual/n[^e]*{,/**} wklx,
+  deny /sys/devices/virtual/ne[^t]*{,/**} wklx,
+  deny /sys/devices/virtual/net?*{,/**} wklx,
+  deny /sys/devices/virtual?*{,/**} wklx,
+  deny /sys/devices?*{,/**} wklx,
+  deny /sys/f[^s]*{,/**} wklx,
+  deny /sys/fs/[^c]*{,/**} wklx,
+  deny /sys/fs/c[^g]*{,/**} wklx,
+  deny /sys/fs/cg[^r]*{,/**} wklx,
+  deny /sys/fs/cgr[^o]*{,/**} wklx,
+  deny /sys/fs/cgro[^u]*{,/**} wklx,
+  deny /sys/fs/cgrou[^p]*{,/**} wklx,
+  deny /sys/fs/cgroup?*{,/**} wklx,
+  deny /sys/fs?*{,/**} wklx,
+
+  # Special exception for cgroup namespaces
+%s
+
+  # user input raw.apparmor below here
+  %s
+
+  # nesting support goes here if needed
+%s
+  change_profile -> "%s",
 }`
 
 func AAProfileFull(c container) string {

From 927fc2ab8a907315c0def976b4c79b2389553dfd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 30 Jun 2016 18:34:50 -0400
Subject: [PATCH 02/10] apparmor: Setup a more modular apparmor profile
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Related to #1942

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/apparmor.go | 51 +++++++++++++++++++++++++--------------------------
 1 file changed, 25 insertions(+), 26 deletions(-)

diff --git a/lxd/apparmor.go b/lxd/apparmor.go
index d9a3d8a..8ed85d3 100644
--- a/lxd/apparmor.go
+++ b/lxd/apparmor.go
@@ -48,8 +48,6 @@ const NESTING_AA_PROFILE = `
 `
 
 const DEFAULT_AA_PROFILE = `
-#include <tunables/global>
-profile "%s" flags=(attach_disconnected,mediate_deleted) {
   network,
   capability,
   file,
@@ -268,17 +266,7 @@ profile "%s" flags=(attach_disconnected,mediate_deleted) {
   deny /sys/fs/cgrou[^p]*{,/**} wklx,
   deny /sys/fs/cgroup?*{,/**} wklx,
   deny /sys/fs?*{,/**} wklx,
-
-  # Special exception for cgroup namespaces
-%s
-
-  # user input raw.apparmor below here
-  %s
-
-  # nesting support goes here if needed
-%s
-  change_profile -> "%s",
-}`
+`
 
 func AAProfileFull(c container) string {
 	lxddir := shared.VarPath("")
@@ -295,28 +283,39 @@ func AAProfileShort(c container) string {
 	return fmt.Sprintf("lxd-%s", c.Name())
 }
 
-func AAProfileCgns() string {
-	if shared.PathExists("/proc/self/ns/cgroup") {
-		return "  mount fstype=cgroup -> /sys/fs/cgroup/**,"
-	}
-	return ""
-}
-
 // getProfileContent generates the apparmor profile template from the given
 // container. This includes the stock lxc includes as well as stuff from
 // raw.apparmor.
 func getAAProfileContent(c container) string {
-	rawApparmor, ok := c.ExpandedConfig()["raw.apparmor"]
-	if !ok {
-		rawApparmor = ""
+	profile := strings.TrimLeft(DEFAULT_AA_PROFILE, "\n")
+
+	// Apply cgns bits
+	if shared.PathExists("/proc/self/ns/cgroup") {
+		profile += "\n  # Cgroup namespace support\n"
+		profile += "  mount fstype=cgroup -> /sys/fs/cgroup/**,\n"
 	}
 
-	nesting := ""
+	// Apply nesting bits
 	if c.IsNesting() {
-		nesting = NESTING_AA_PROFILE
+		profile += "\n  # Container nesting support\n"
+		profile += strings.TrimLeft(NESTING_AA_PROFILE, "\n")
+		profile += fmt.Sprintf("  change_profile -> \"%s\",\n", AAProfileFull(c))
 	}
 
-	return fmt.Sprintf(DEFAULT_AA_PROFILE, AAProfileFull(c), AAProfileCgns(), rawApparmor, nesting, AAProfileFull(c))
+	// Append raw.apparmor
+	rawApparmor, ok := c.ExpandedConfig()["raw.apparmor"]
+	if ok {
+		profile += "\n  # User input (raw.apparmor)\n"
+		for _, line := range strings.Split(strings.Trim(rawApparmor, "\n"), "\n") {
+			profile += fmt.Sprintf("  %s\n", line)
+		}
+	}
+
+	return fmt.Sprintf(`#include <tunables/global>
+profile "%s" flags=(attach_disconnected,mediate_deleted) {
+%s
+}
+`, AAProfileFull(c), strings.Trim(profile, "\n"))
 }
 
 func runApparmor(command string, c container) error {

From 14807b20ec6882dd122712e6fca6541a8b31ee0c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 30 Jun 2016 18:41:50 -0400
Subject: [PATCH 03/10] apparmor: Rename main two chunks of rules
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Related to #1942

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/apparmor.go | 54 +++++++++++++++++++++++++++---------------------------
 1 file changed, 27 insertions(+), 27 deletions(-)

diff --git a/lxd/apparmor.go b/lxd/apparmor.go
index 8ed85d3..49cb671 100644
--- a/lxd/apparmor.go
+++ b/lxd/apparmor.go
@@ -23,31 +23,7 @@ const (
 
 var aaPath = shared.VarPath("security", "apparmor")
 
-const NESTING_AA_PROFILE = `
-  pivot_root,
-  mount /var/lib/lxd/shmounts/ -> /var/lib/lxd/shmounts/,
-  mount none -> /var/lib/lxd/shmounts/,
-  mount fstype=proc -> /usr/lib/*/lxc/**,
-  mount fstype=sysfs -> /usr/lib/*/lxc/**,
-  mount options=(rw,bind),
-  mount options=(rw,rbind),
-  deny /dev/.lxd/proc/** rw,
-  deny /dev/.lxd/sys/** rw,
-  mount options=(rw,make-rshared),
-
-  # there doesn't seem to be a way to ask for:
-  # mount options=(ro,nosuid,nodev,noexec,remount,bind),
-  # as we always get mount to $cdir/proc/sys with those flags denied
-  # So allow all mounts until that is straightened out:
-  mount,
-  mount options=bind /var/lib/lxd/shmounts/** -> /var/lib/lxd/**,
-  # lxc-container-default-with-nesting also inherited these
-  # from start-container, and seems to need them.
-  ptrace,
-  signal,
-`
-
-const DEFAULT_AA_PROFILE = `
+const AA_PROFILE_BASE = `
   network,
   capability,
   file,
@@ -268,6 +244,30 @@ const DEFAULT_AA_PROFILE = `
   deny /sys/fs?*{,/**} wklx,
 `
 
+const AA_PROFILE_NESTING = `
+  pivot_root,
+  mount /var/lib/lxd/shmounts/ -> /var/lib/lxd/shmounts/,
+  mount none -> /var/lib/lxd/shmounts/,
+  mount fstype=proc -> /usr/lib/*/lxc/**,
+  mount fstype=sysfs -> /usr/lib/*/lxc/**,
+  mount options=(rw,bind),
+  mount options=(rw,rbind),
+  deny /dev/.lxd/proc/** rw,
+  deny /dev/.lxd/sys/** rw,
+  mount options=(rw,make-rshared),
+
+  # there doesn't seem to be a way to ask for:
+  # mount options=(ro,nosuid,nodev,noexec,remount,bind),
+  # as we always get mount to $cdir/proc/sys with those flags denied
+  # So allow all mounts until that is straightened out:
+  mount,
+  mount options=bind /var/lib/lxd/shmounts/** -> /var/lib/lxd/**,
+  # lxc-container-default-with-nesting also inherited these
+  # from start-container, and seems to need them.
+  ptrace,
+  signal,
+`
+
 func AAProfileFull(c container) string {
 	lxddir := shared.VarPath("")
 	if len(c.Name())+len(lxddir)+7 >= 253 {
@@ -287,7 +287,7 @@ func AAProfileShort(c container) string {
 // container. This includes the stock lxc includes as well as stuff from
 // raw.apparmor.
 func getAAProfileContent(c container) string {
-	profile := strings.TrimLeft(DEFAULT_AA_PROFILE, "\n")
+	profile := strings.TrimLeft(AA_PROFILE_BASE, "\n")
 
 	// Apply cgns bits
 	if shared.PathExists("/proc/self/ns/cgroup") {
@@ -298,7 +298,7 @@ func getAAProfileContent(c container) string {
 	// Apply nesting bits
 	if c.IsNesting() {
 		profile += "\n  # Container nesting support\n"
-		profile += strings.TrimLeft(NESTING_AA_PROFILE, "\n")
+		profile += strings.TrimLeft(AA_PROFILE_NESTING, "\n")
 		profile += fmt.Sprintf("  change_profile -> \"%s\",\n", AAProfileFull(c))
 	}
 

From 1bb13903fa249c6255ae6dfc02f4cb8459819b5e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 5 Jul 2016 11:08:57 +0100
Subject: [PATCH 04/10] Make lxc-to-lxd work inside virtualenv
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #2175

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 scripts/lxc-to-lxd | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/lxc-to-lxd b/scripts/lxc-to-lxd
index 8574e45..df8fbf5 100755
--- a/scripts/lxc-to-lxd
+++ b/scripts/lxc-to-lxd
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 
 import argparse
 import json

From 9fb7ebb4745864b3b3469df1a55153acc87a5159 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 5 Jul 2016 11:11:26 +0100
Subject: [PATCH 05/10] Allow /dev/net/tun by default
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

It's perfectly safe inside both privileged and unprivileged containers
so there's no reason to have people jump through hoops for that.

Related to #2172

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/container_lxc.go | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 3ae3e94..8761e3e 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -329,6 +329,7 @@ func (c *containerLXC) initLXC() error {
 
 	bindMounts := []string{
 		"/dev/fuse",
+		"/dev/net/tun",
 		"/proc/sys/fs/binfmt_misc",
 		"/sys/firmware/efi/efivars",
 		"/sys/fs/fuse/connections",
@@ -396,6 +397,7 @@ func (c *containerLXC) initLXC() error {
 			"c 5:1 rwm",    // /dev/console
 			"c 5:2 rwm",    // /dev/ptmx
 			"c 10:229 rwm", // /dev/fuse
+			"c 10:200 rwm", // /dev/net/tun
 		}
 
 		for _, dev := range devices {

From 9beac2774f0e37df1e105b99e5f4ab81f9491330 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 5 Jul 2016 11:59:24 +0100
Subject: [PATCH 06/10] lxd-bridge-proxy: Remove unused code
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-bridge/lxd-bridge-proxy/main.go | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/lxd-bridge/lxd-bridge-proxy/main.go b/lxd-bridge/lxd-bridge-proxy/main.go
index 48b3a0b..a28a4c3 100644
--- a/lxd-bridge/lxd-bridge-proxy/main.go
+++ b/lxd-bridge/lxd-bridge-proxy/main.go
@@ -2,19 +2,16 @@ package main
 
 import (
 	"flag"
-	"fmt"
 	"log"
 	"net/http"
-	"net/http/httputil"
 )
 
-func NewProxy() *httputil.ReverseProxy {
+func NewProxy() *ReverseProxy {
 	director := func(req *http.Request) {
-		if req.Method == "CONNECT" {
-			fmt.Printf("CONNECT: %s\n", req.Host)
-		}
+		req.Proto = "HTTP/1.0"
+		req.ProtoMinor = 0
 	}
-	return &httputil.ReverseProxy{Director: director}
+	return &ReverseProxy{Director: director}
 }
 
 func main() {

From b2071971e122043284780792b48b66202592bcd7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 5 Jul 2016 12:07:44 +0100
Subject: [PATCH 07/10] Don't unfreeze a container on stop
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #2164

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxc/action.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxc/action.go b/lxc/action.go
index dfb3044..6858bc9 100644
--- a/lxc/action.go
+++ b/lxc/action.go
@@ -64,7 +64,7 @@ func (c *actionCmd) run(config *lxd.Config, args []string) error {
 			return fmt.Errorf(i18n.G("Must supply container name for: ")+"\"%s\"", nameArg)
 		}
 
-		if c.action == shared.Start || c.action == shared.Stop {
+		if c.action == shared.Start {
 			current, err := d.ContainerInfo(name)
 			if err != nil {
 				return err

From cdc84cc6a45ba54e7ffe53de1e7f6c1c53ff781f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 5 Jul 2016 12:12:07 +0100
Subject: [PATCH 08/10] Unfreeze frozen container on shutdown
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #2164

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/container_state.go | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/lxd/container_state.go b/lxd/container_state.go
index c8baa39..fb0f815 100644
--- a/lxd/container_state.go
+++ b/lxd/container_state.go
@@ -88,6 +88,13 @@ func containerStatePut(d *Daemon, r *http.Request) Response {
 			}
 		} else {
 			do = func(op *operation) error {
+				if c.IsFrozen() {
+					err := c.Unfreeze()
+					if err != nil {
+						return err
+					}
+				}
+
 				err = c.Shutdown(time.Duration(raw.Timeout) * time.Second)
 				if err != nil {
 					return err

From da13c820710b87360745ccd9d69475b908fdd6e9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 5 Jul 2016 14:03:59 +0100
Subject: [PATCH 09/10] Fix ZFS volume size on 32bit architectures
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Lets just use int64 everywhere in the init code.

Closes #2158

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/main.go | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/lxd/main.go b/lxd/main.go
index ec20ed2..9da7563 100644
--- a/lxd/main.go
+++ b/lxd/main.go
@@ -35,11 +35,11 @@ var argHelp = gnuflag.Bool("help", false, "")
 var argLogfile = gnuflag.String("logfile", "", "")
 var argMemProfile = gnuflag.String("memprofile", "", "")
 var argNetworkAddress = gnuflag.String("network-address", "", "")
-var argNetworkPort = gnuflag.Int("network-port", -1, "")
+var argNetworkPort = gnuflag.Int64("network-port", -1, "")
 var argPrintGoroutinesEvery = gnuflag.Int("print-goroutines-every", -1, "")
 var argStorageBackend = gnuflag.String("storage-backend", "", "")
 var argStorageCreateDevice = gnuflag.String("storage-create-device", "", "")
-var argStorageCreateLoop = gnuflag.Int("storage-create-loop", -1, "")
+var argStorageCreateLoop = gnuflag.Int64("storage-create-loop", -1, "")
 var argStoragePool = gnuflag.String("storage-pool", "", "")
 var argSyslog = gnuflag.Bool("syslog", false, "")
 var argTimeout = gnuflag.Int("timeout", -1, "")
@@ -590,11 +590,11 @@ func cmdInit() error {
 	var defaultPrivileged int // controls whether we set security.privileged=true
 	var storageBackend string // dir or zfs
 	var storageMode string    // existing, loop or device
-	var storageLoopSize int   // Size in GB
+	var storageLoopSize int64 // Size in GB
 	var storageDevice string  // Path
 	var storagePool string    // pool name
 	var networkAddress string // Address
-	var networkPort int       // Port
+	var networkPort int64     // Port
 	var trustPassword string  // Trust password
 
 	// Detect userns
@@ -645,12 +645,12 @@ func cmdInit() error {
 		}
 	}
 
-	askInt := func(question string, min int, max int) int {
+	askInt := func(question string, min int64, max int64) int64 {
 		for {
 			fmt.Printf(question)
 			input, _ := reader.ReadString('\n')
 			input = strings.TrimSuffix(input, "\n")
-			intInput, err := strconv.Atoi(input)
+			intInput, err := strconv.ParseInt(input, 10, 64)
 
 			if err == nil && (min == -1 || intInput >= min) && (max == -1 || intInput <= max) {
 				return intInput

From a3cd4fefc69f33055bee11927b34e4020f00bced Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 5 Jul 2016 15:07:48 +0100
Subject: [PATCH 10/10] zfs: Only delete copy- snapshots on delete
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #2127

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/storage_zfs.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/storage_zfs.go b/lxd/storage_zfs.go
index 9290dca..cd6ae52 100644
--- a/lxd/storage_zfs.go
+++ b/lxd/storage_zfs.go
@@ -854,7 +854,7 @@ func (s *storageZfs) zfsCleanup(path string) error {
 
 			return nil
 		}
-	} else if strings.HasPrefix(path, "containers") {
+	} else if strings.HasPrefix(path, "containers") && strings.Contains(path, "@copy-") {
 		// Just remove the copy- snapshot for copies of active containers
 		err := s.zfsDestroy(path)
 		if err != nil {


More information about the lxc-devel mailing list