Quoting Christian Brauner (christian.brau...@mailbox.org):
> 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>

Acked-by: Serge E. Hallyn <serge.hal...@ubuntu.com>

> ---
>  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