As ls_get() is non-tail recursive we face the inherent danger of blowing up the
stack at some level of nesting. To have at least some security we define
MAX_NESTLVL to be 5. That should be sufficient for most users. The argument lvl
to ls_get() can be used to keep track of the level of nesting we are at. If lvl
is greater than the allowed default level return (without error) and unwind the
stack.

--nesting gains an optional numeric argument. This allows the user to specify
the maximum level of nesting she/he wants to see. Fair warning: If your nesting
level is really deep and/or you have a lot of containers your might run into
trouble.

Signed-off-by: Christian Brauner <christian.brau...@mailbox.org>
---
 src/lxc/arguments.h |  2 +-
 src/lxc/lxc_ls.c    | 37 ++++++++++++++++++++++++++++++++++---
 2 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/src/lxc/arguments.h b/src/lxc/arguments.h
index 898a9ce..a3d2932 100644
--- a/src/lxc/arguments.h
+++ b/src/lxc/arguments.h
@@ -124,11 +124,11 @@ struct lxc_arguments {
        char *ls_fancy_format;
        char *ls_groups;
        char *ls_regex;
+       unsigned int ls_nesting; /* maximum allowed nesting level */
        bool ls_active;
        bool ls_fancy;
        bool ls_frozen;
        bool ls_line;
-       bool ls_nesting;
        bool ls_running;
        bool ls_stopped;
 
diff --git a/src/lxc/lxc_ls.c b/src/lxc/lxc_ls.c
index 3a7fa15..a4ab9b6 100644
--- a/src/lxc/lxc_ls.c
+++ b/src/lxc/lxc_ls.c
@@ -40,6 +40,10 @@
 lxc_log_define(lxc_ls, lxc);
 
 #define LINELEN 1024
+/* Per default we only allow five levels of recursion to protect the stack at
+ * least a little bit. */
+#define MAX_NESTLVL 5
+
 #define LS_FROZEN 1
 #define LS_STOPPED 2
 #define LS_ACTIVE 3
@@ -154,7 +158,7 @@ static const struct option my_longopts[] = {
        {"running", no_argument, 0, LS_RUNNING},
        {"frozen", no_argument, 0, LS_FROZEN},
        {"stopped", no_argument, 0, LS_STOPPED},
-       {"nesting", no_argument, 0, LS_NESTING},
+       {"nesting", optional_argument, 0, LS_NESTING},
        {"groups", required_argument, 0, 'g'},
        {"regex", required_argument, 0, 'r'},
        LXC_COMMON_OPTIONS
@@ -177,11 +181,12 @@ Options :\n\
   --running          list only running containers\n\
   --frozen           list only frozen containers\n\
   --stopped          list only stopped containers\n\
-  --nesting          list nested containers\n\
+  --nesting=NUM      list nested containers up to NUM (default is 5) levels of 
nesting\n\
   -r --regex         filter container names by regular expression\n\
   -g --groups        comma separated list of groups a container must have to 
be displayed\n",
        .options = my_longopts,
        .parser = my_parser,
+       .ls_nesting = MAX_NESTLVL,
 };
 
 int main(int argc, char *argv[])
@@ -300,6 +305,16 @@ static int ls_get(struct ls **m, size_t *size, const 
struct lxc_arguments *args,
                struct lengths *lht, const char *basepath, const char *parent,
                unsigned int lvl)
 {
+       /* As ls_get() is non-tail recursive we face the inherent danger of
+        * blowing up the stack at some level of nesting. To have at least some
+        * security we define MAX_NESTLVL to be 5. That should be sufficient for
+        * most users. The argument lvl can be used to keep track of the level
+        * of nesting we are at. If lvl is greater than the allowed default
+        * level or the level the user specified on the command line we return
+        * and unwind the stack. */
+       if (lvl > args->ls_nesting)
+               return 0;
+
        int num = 0, ret = -1;
        char **containers = NULL;
        /* If we, at some level of nesting, encounter a stopped container but
@@ -855,6 +870,8 @@ static void ls_print_table(struct ls *l, struct lengths 
*lht,
 
 static int my_parser(struct lxc_arguments *args, int c, char *arg)
 {
+       char *invalid;
+       unsigned long int m, n = MAX_NESTLVL;
        switch (c) {
        case '1':
                args->ls_line = true;
@@ -875,7 +892,21 @@ static int my_parser(struct lxc_arguments *args, int c, 
char *arg)
                args->ls_stopped = true;
                break;
        case LS_NESTING:
-               args->ls_nesting = true;
+               /* In case strtoul() receives a string that represents a
+                * negative number it will return ULONG_MAX - the number that
+                * string represents if the number the string represents is <
+                * ULONG_MAX and ULONG_MAX otherwise. But it will consider this
+                * valid input and not set errno. So we check manually if the
+                * first character of num_string == '-'. Otherwise the default
+                * level remains set. */
+               if (arg && !(*arg == '-')) {
+                       errno = 0;
+                       m = strtoul(arg, &invalid, 0);
+                       /* ls_nesting has type unsigned int. */
+                       if (!errno && (*invalid == '\0') && (m <= UINT_MAX))
+                               n = m;
+               }
+               args->ls_nesting = n;
                break;
        case 'g':
                args->groups = arg;
-- 
2.7.0

_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to