[lxc-devel] [PATCH 8/5] unprivileged cgroup start: don't bother with devices special case

2013-07-25 Thread Serge Hallyn
Signed-off-by: Serge Hallyn 
---
 src/lxc/start.c | 10 ++
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/src/lxc/start.c b/src/lxc/start.c
index 9099fd6..514819b 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -713,14 +713,8 @@ int lxc_spawn(struct lxc_handler *handler)
goto out_delete_net;
 
if (setup_cgroup_devices(handler->cgroup, &handler->conf->cgroup, 
handler->conf)) {
-   /* an unfortunate special case: startup hooks may have already
-* setup the cgroup.  If a setting fails, and this is the 
devices
-* subsystem, *and* we are already in a subset of the cgroup,
-* then ignore the failure */
-   if (!is_in_subcgroup(handler->pid, "devices", handler->cgroup)) 
{
-   ERROR("failed to setup the devices cgroup for '%s'", 
name);
-   goto out_delete_net;
-   }
+   ERROR("failed to setup the devices cgroup for '%s'", name);
+   goto out_delete_net;
}
 
/* Tell the child to complete its initialization and wait for
-- 
1.8.3.2


--
See everything from the browser to the database with AppDynamics
Get end-to-end visibility with application monitoring from AppDynamics
Isolate bottlenecks and diagnose root cause in seconds.
Start your free trial of AppDynamics Pro today!
http://pubads.g.doubleclick.net/gampad/clk?id=48808831&iu=/4140/ostg.clktrk
___
Lxc-devel mailing list
Lxc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lxc-devel


[lxc-devel] [PATCH 7/5] lxc-destroy: support unprivileged use

2013-07-25 Thread Serge Hallyn
Signed-off-by: Serge Hallyn 
---
 src/lxc/conf.c | 24 
 src/lxc/conf.h |  1 +
 src/lxc/lxc_destroy.c  |  7 ---
 src/lxc/lxccontainer.c | 15 ---
 4 files changed, 37 insertions(+), 10 deletions(-)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index a47d4bd..a84c2ad 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -2825,6 +2825,30 @@ int chown_mapped_root(char *path, struct lxc_conf *conf)
return wait_for_pid(pid);
 }
 
+int do_mapped_rmdir(char *path, struct lxc_conf *conf)
+{
+   char buf[4096], *p = buf;
+   int hostuid = geteuid(), nsuid = find_unmapped_nsuid(conf);
+   struct lxc_list *it;
+
+   /* lxc-usernsexec -m b:$nsuid:$hostuid <... all container mappings>  \
+* rm -rf --one-file-system path */
+   p += snprintf(buf, 4095, "lxc-usernsexec -m u:%d:%d:1", nsuid, hostuid);
+
+   lxc_list_for_each(it, &conf->id_map) {
+   struct id_map *map = it->elem;
+   p += snprintf(p, p-buf, " -m %c:%d:%d:%d",
+ map->idtype == ID_TYPE_UID ? 'u' : 'g',
+ (int)map->nsid, (int)map->hostid, 
(int)map->range);
+   }
+   p += snprintf(p, p-buf, " -- rm -rf --one-file-system %s", path);
+   if (p - buf >= 4096) {
+   ERROR("lxc-usernsexec directory removal command too long");
+   return -1;
+   }
+   return system(buf);
+}
+
 int ttys_shift_ids(struct lxc_conf *c)
 {
int i;
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index c285950..e3565bd 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -336,5 +336,6 @@ extern uid_t get_mapped_rootid(struct lxc_conf *conf);
 extern int find_unmapped_nsuid(struct lxc_conf *conf);
 extern bool hostid_is_mapped(int id, struct lxc_conf *conf);
 extern int chown_mapped_root(char *path, struct lxc_conf *conf);
+extern int do_mapped_rmdir(char *path, struct lxc_conf *conf);
 extern int ttys_shift_ids(struct lxc_conf *c);
 #endif
diff --git a/src/lxc/lxc_destroy.c b/src/lxc/lxc_destroy.c
index 9a1b11f..114c911 100644
--- a/src/lxc/lxc_destroy.c
+++ b/src/lxc/lxc_destroy.c
@@ -64,13 +64,6 @@ int main(int argc, char *argv[])
 {
struct lxc_container *c;
 
-   /* this is a short term test.  We'll probably want to check for
-* write access to lxcpath instead */
-   if (geteuid()) {
-   fprintf(stderr, "%s must be run as root\n", argv[0]);
-   exit(1);
-   }
-
if (lxc_arguments_parse(&my_args, argc, argv))
exit(1);
 
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index ee0b1ff..3dae2b8 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -1467,6 +1467,9 @@ static bool lxcapi_destroy(struct lxc_container *c)
 {
struct bdev *r = NULL;
bool ret = false;
+   const char *p1 = lxcapi_get_config_path(c);
+   char *path = alloca(strlen(p1) + strlen(c->name) + 2);
+   sprintf(path, "%s/%s", p1, c->name);
 
if (!c || !lxcapi_is_defined(c))
return false;
@@ -1480,6 +1483,15 @@ static bool lxcapi_destroy(struct lxc_container *c)
goto out;
}
 
+   if (geteuid() != 0) {
+   /*
+* container is one big dir, and we have to shell out
+* to have permission to remove it.  So do it in one
+* big shot
+*/
+   return do_mapped_rmdir(path, c->lxc_conf) == 0;
+   }
+
if (c->lxc_conf && c->lxc_conf->rootfs.path && 
c->lxc_conf->rootfs.mount)
r = bdev_init(c->lxc_conf->rootfs.path, 
c->lxc_conf->rootfs.mount, NULL);
if (r) {
@@ -1489,9 +1501,6 @@ static bool lxcapi_destroy(struct lxc_container *c)
}
}
 
-   const char *p1 = lxcapi_get_config_path(c);
-   char *path = alloca(strlen(p1) + strlen(c->name) + 2);
-   sprintf(path, "%s/%s", p1, c->name);
if (lxc_rmdir_onedev(path) < 0) {
ERROR("Error destroying container directory for %s", c->name);
goto out;
-- 
1.8.3.2


--
See everything from the browser to the database with AppDynamics
Get end-to-end visibility with application monitoring from AppDynamics
Isolate bottlenecks and diagnose root cause in seconds.
Start your free trial of AppDynamics Pro today!
http://pubads.g.doubleclick.net/gampad/clk?id=48808831&iu=/4140/ostg.clktrk
___
Lxc-devel mailing list
Lxc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lxc-devel


[lxc-devel] [PATCH 9/5] cgroup: special-case the cgroups used for unprivileged containers

2013-07-25 Thread Serge Hallyn
When creating an unprivileged container, you must have a cgroup
fs mounted named lxc.  For instance

mkdir /sys/fs/cgroup/lxc
mount -t cgroup -o none,name=lxc none /sys/fs/cgroup/lxc
mkdir /sys/fs/cgroup/lxc/$USER
chown -R $USER /sys/fs/cgroup/lxc/$USER

You could also compose the freezer subsystem with the lxc one to
not lose freezer support.  When I tested that I was able to do
unprivileged lxc-freeze and lxc-unfreeze of my own containers.

Unprivileged containers will ONLY enter a per-container cgroup for
the lxc cgroup.  If you wish to set other limits, you need privilege
to do so anyway, so you can do so out of band with a separate
(privileged) set of utilities.  For instance you can confine the
whole user to a cpuset with pam_cgroup, or allow the user to
create and enter cgroups of certain subsystems if it makes sense.

(For reference, this is done in response to upstream cgroup kernel
maintainer specifically recmomending against delegating cgroup
administration to users.  It is safe for some but not all cgroups,
and it does not fit in with the future plans)

Signed-off-by: Serge Hallyn 
---
 src/lxc/cgroup.c | 58 
 1 file changed, 37 insertions(+), 21 deletions(-)

diff --git a/src/lxc/cgroup.c b/src/lxc/cgroup.c
index 654e55a..ff3a090 100644
--- a/src/lxc/cgroup.c
+++ b/src/lxc/cgroup.c
@@ -579,6 +579,24 @@ static int record_visited(char *opts, char **visitedp, 
char *allcgroups)
return 0;
 }
 
+static inline bool filter_cgroup_mntent(struct mntent *m)
+{
+   if (strcmp(m->mnt_type, "cgroup") != 0)
+   return false;
+   /*
+* if we are unprivileged, then only use one named 'lxc'
+* otherwise, use all the ones which have subsystems
+*/
+   if (geteuid() == 0) {
+   if (!mount_has_subsystem(m))
+   return false;
+   } else {
+   if (!hasmntopt(m, "name=lxc"))
+   return false;
+   }
+   return true;
+}
+
 /*
  * Make sure the 'cgroup group' exists, so that we don't have to worry about
  * that later.
@@ -605,10 +623,7 @@ static int create_lxcgroups(const char *lxcgroup)
}
 
while ((getmntent_r(file, &mntent_r, buf, sizeof(buf {
-
-   if (strcmp(mntent_r.mnt_type, "cgroup"))
-   continue;
-   if (!mount_has_subsystem(&mntent_r))
+   if (!filter_cgroup_mntent(&mntent_r))
continue;
 
/*
@@ -698,9 +713,7 @@ again:
 
while ((getmntent_r(file, &mntent_r, buf, sizeof(buf {
 
-   if (strcmp(mntent_r.mnt_type, "cgroup"))
-   continue;
-   if (!mount_has_subsystem(&mntent_r))
+   if (!filter_cgroup_mntent(&mntent_r))
continue;
 
/* make sure we haven't checked this subsystem already */
@@ -771,10 +784,9 @@ int lxc_cgroup_enter(const char *cgpath, pid_t pid)
}
 
while ((getmntent_r(file, &mntent_r, buf, sizeof(buf {
-   if (strcmp(mntent_r.mnt_type, "cgroup"))
-   continue;
-   if (!mount_has_subsystem(&mntent_r))
+   if (!filter_cgroup_mntent(&mntent_r))
continue;
+
ret = snprintf(path, MAXPATHLEN, "%s/%s/tasks",
   mntent_r.mnt_dir, cgpath);
if (ret < 0 || ret >= MAXPATHLEN) {
@@ -881,9 +893,7 @@ int lxc_cgroup_destroy(const char *cgpath)
}
 
while ((getmntent_r(file, &mntent_r, buf, sizeof(buf {
-   if (strcmp(mntent_r.mnt_type, "cgroup"))
-   continue;
-   if (!mount_has_subsystem(&mntent_r))
+   if (!filter_cgroup_mntent(&mntent_r))
continue;
 
err = lxc_one_cgroup_destroy(&mntent_r, cgpath);
@@ -951,14 +961,13 @@ bool is_in_subcgroup(int pid, const char *subsystem, 
const char *cgpath)
 
 /*
  * Return cgroup of current task.
- * This assumes that task is in the same cgroup for each controller.  This
- * may or may not *always* be a reasonable assumption - it generally is,
- * and handling or at least checking for this condition is a TODO.
+ * If we are root, then return the 'devices' cgroup.
+ * If we are not, then return the 'name=lxc' cgroup.
  */
 int lxc_curcgroup(char *cgroup, int inlen)
 {
FILE *f;
-   char *line = NULL, *p, *p2;
+   char *line = NULL, *p, *p2, *needle;
int ret = 0;
size_t len;
 
@@ -967,12 +976,19 @@ int lxc_curcgroup(char *cgroup, int inlen)
return -1;
 
while (getline(&line, &len, f) != -1) {
-   if (strstr(line, ":freezer:") == NULL && strstr(line, 
":devices:") == NULL)
-   continue;
-   p = rindex(line, ':');
+   p = index(line, ':');
if (!p)