[lxc-devel] [PATCH] python3: Support unpriv containers

Serge Hallyn serge.hallyn at ubuntu.com
Wed Dec 11 22:01:20 UTC 2013


Quoting Stéphane Graber (stgraber at ubuntu.com):
> This removes any existing uid check in the python3 binding and tools,
> replacing those by .controllable where appropriate.
> 
> Extra checks are also added to make lxc-ls work as a user, returning as
> much information as can possibly be retrieved.
> 
> Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>

Acked-by: Serge E. Hallyn <serge.hallyn at ubuntu.com>

> ---
>  src/lxc/lxc-device             | 11 ++++-----
>  src/lxc/lxc-ls                 | 51 +++++++++++++++++++++++++++++-------------
>  src/lxc/lxc-start-ephemeral.in |  5 -----
>  src/python-lxc/lxc/__init__.py |  3 ---
>  4 files changed, 41 insertions(+), 29 deletions(-)
> 
> diff --git a/src/lxc/lxc-device b/src/lxc/lxc-device
> index 9d24248..78be6ab 100644
> --- a/src/lxc/lxc-device
> +++ b/src/lxc/lxc-device
> @@ -66,14 +66,10 @@ subparser_add.add_argument(dest="name", metavar="NAME", nargs="?",
>  args = parser.parse_args()
>  
>  # Some basic checks
> +## Check for valid action
>  if not hasattr(args, "action"):
>      parser.error(_("You must specify an action."))
>  
> -## The user needs to be uid 0
> -if not os.geteuid() == 0:
> -    parser.error(_("You must be root to run this script. Try running: sudo %s"
> -                   % (sys.argv[0])))
> -
>  ## Don't rename if no alternative name
>  if not args.name:
>      args.name = args.device
> @@ -81,6 +77,11 @@ if not args.name:
>  ## Check that the container is ready
>  container = lxc.Container(args.container, args.lxcpath)
>  
> +## Check that we have control over the container
> +if not container.controllable:
> +    parser.error("Insufficent privileges to control: %s" % container.name)
> +
> +## Check that the container is running
>  if not container.running:
>      parser.error("The container must be running.")
>  
> diff --git a/src/lxc/lxc-ls b/src/lxc/lxc-ls
> index 26c9684..b058bd0 100755
> --- a/src/lxc/lxc-ls
> +++ b/src/lxc/lxc-ls
> @@ -123,8 +123,7 @@ parser.add_argument("-P", "--lxcpath", dest="lxcpath", metavar="PATH",
>                      default=lxc.default_config_path)
>  
>  parser.add_argument("--active", action="store_true",
> -                    help=_("list only active containers "
> -                           "(same as --running --frozen)"))
> +                    help=_("list only active containers"))
>  
>  parser.add_argument("--frozen", dest="state", action="append_const",
>                      const="FROZEN", help=_("list only frozen containers"))
> @@ -153,7 +152,7 @@ args = parser.parse_args()
>  if args.active:
>      if not args.state:
>          args.state = []
> -    args.state += ["RUNNING", "FROZEN"]
> +    args.state += ["RUNNING", "FROZEN", "UNKNOWN"]
>  
>  # If the output is piped, default to --one
>  if not sys.stdout.isatty():
> @@ -166,25 +165,27 @@ lxcpath = os.environ.get('NESTED', args.lxcpath)
>  args.fancy_format = args.fancy_format.strip().split(",")
>  
>  # Basic checks
> -## The user needs to be uid 0
> -if not os.geteuid() == 0 and (args.fancy or args.state):
> -    parser.error(_("You must be root to access advanced container properties. "
> -                   "Try running: sudo %s"
> -                   % (sys.argv[0])))
> +## Check for setns
> +SUPPORT_SETNS = os.path.exists("/proc/self/ns")
> +SUPPORT_SETNS_NET = False
> +SUPPORT_SETNS_PID = False
> +if SUPPORT_SETNS:
> +    SUPPORT_SETNS_NET = os.path.exists("/proc/self/ns/net")
> +    SUPPORT_SETNS_PID = os.path.exists("/proc/self/ns/pid")
>  
>  ## Nesting requires setns to pid and net ns
>  if args.nesting:
> -    if not os.path.exists("/proc/self/ns/"):
> +    if not SUPPORT_SETNS:
>          parser.error(_("Showing nested containers requires setns support "
>                         "which your kernel doesn't support."))
>  
> -    if not "pid" in os.listdir("/proc/self/ns/"):
> +    if not SUPPORT_SETNS_NET:
>          parser.error(_("Showing nested containers requires setns to the "
> -                       "PID namespace which your kernel doesn't support."))
> +                       "network namespace which your kernel doesn't support."))
>  
> -    if not "net" in os.listdir("/proc/self/ns/"):
> +    if not SUPPORT_SETNS_PID:
>          parser.error(_("Showing nested containers requires setns to the "
> -                       "network namespace which your kernel doesn't support."))
> +                       "PID namespace which your kernel doesn't support."))
>  
>  # List of containers, stored as dictionaries
>  containers = []
> @@ -203,8 +204,13 @@ for container_name in lxc.list_containers(config_path=lxcpath):
>  
>      container = lxc.Container(container_name, args.lxcpath)
>  
> +    if container.controllable:
> +        state = container.state
> +    else:
> +        state = 'UNKNOWN'
> +
>      # Filter by status
> -    if args.state and container.state not in args.state:
> +    if args.state and state not in args.state:
>          continue
>  
>      # Nothing more is needed if we're not printing some fancy output
> @@ -214,17 +220,30 @@ for container_name in lxc.list_containers(config_path=lxcpath):
>  
>      # Some extra field we may want
>      if 'state' in args.fancy_format or args.nesting:
> -        entry['state'] = container.state
> +        entry['state'] = state
>  
>      if 'pid' in args.fancy_format or args.nesting:
>          entry['pid'] = "-"
> -        if container.init_pid != -1:
> +        if state == 'UNKNOWN':
> +            entry['pid'] = state
> +        elif container.init_pid != -1:
>              entry['pid'] = str(container.init_pid)
>  
>      # Get the IPs
>      for family, protocol in {'inet': 'ipv4', 'inet6': 'ipv6'}.items():
>          if protocol in args.fancy_format or args.nesting:
>              entry[protocol] = "-"
> +
> +            if state == 'UNKNOWN':
> +                entry[protocol] = state
> +                continue
> +
> +            # FIXME: We should get get_ips working as non-root
> +            if container.running and (not SUPPORT_SETNS_NET \
> +                    or os.geteuid() != 0):
> +                entry[protocol] = 'UNKNOWN'
> +                continue
> +
>              ips = container.get_ips(family=family)
>              if ips:
>                  entry[protocol] = ", ".join(ips)
> diff --git a/src/lxc/lxc-start-ephemeral.in b/src/lxc/lxc-start-ephemeral.in
> index 0f0c398..118b1b5 100644
> --- a/src/lxc/lxc-start-ephemeral.in
> +++ b/src/lxc/lxc-start-ephemeral.in
> @@ -118,11 +118,6 @@ if not args.storage_type:
>  if args.keep_data and args.storage_type == "tmpfs":
>      parser.error(_("You can't use -k with the tmpfs storage type."))
>  
> -## The user needs to be uid 0
> -if not os.geteuid() == 0:
> -    parser.error(_("You must be root to run this script. Try running: sudo %s"
> -                   % (sys.argv[0])))
> -
>  # Load the orig container
>  orig = lxc.Container(args.orig, args.lxcpath)
>  if not orig.defined:
> diff --git a/src/python-lxc/lxc/__init__.py b/src/python-lxc/lxc/__init__.py
> index c3d840c..e708781 100644
> --- a/src/python-lxc/lxc/__init__.py
> +++ b/src/python-lxc/lxc/__init__.py
> @@ -150,9 +150,6 @@ class Container(_lxc.Container):
>              Creates a new Container instance.
>          """
>  
> -        if os.geteuid() != 0:
> -            raise Exception("Running as non-root.")
> -
>          if config_path:
>              _lxc.Container.__init__(self, name, config_path)
>          else:
> -- 
> 1.8.5.1
> 
> _______________________________________________
> lxc-devel mailing list
> lxc-devel at lists.linuxcontainers.org
> http://lists.linuxcontainers.org/listinfo/lxc-devel


More information about the lxc-devel mailing list