← Back to team overview

duplicity-team team mailing list archive

Re: [Merge] lp:~jmwilson/duplicity/capabilities into lp:duplicity

 

I cannot find python-capng for Ubuntu 14.04, Python 2.7, so I'm guessing
it's a new critter.


On Mon, Apr 27, 2015 at 8:33 AM, edso <edgar.soldin@xxxxxx> wrote:

> looks like capng is difficult to retrieve. if so i would hesitate to make
> duplicity depend on it by default.
>
> does it work with older python? we officially support python 2.6+ still.
>
> ..ede/duply.net
>
> On 27.04.2015 15:15, Kenneth Loafman wrote:
> > If I understand this correctly, then new files will be created by
> > 'duplicity', but older files owned by root will not be deletable.
> > Correct?  I'm thinking a one-time 'chown -R duplicity:
> ~/cache/duplicity/*'
> > would fix that problem.
> >
> >
> > On Sun, Apr 26, 2015 at 7:31 PM, James Wilson <jmw@xxxxxxxxxxxx> wrote:
> >
> >> James Wilson has proposed merging lp:~jmwilson/duplicity/capabilities
> into
> >> lp:duplicity.
> >>
> >> Requested reviews:
> >>   duplicity-team (duplicity-team)
> >>
> >> For more details, see:
> >>
> https://code.launchpad.net/~jmwilson/duplicity/capabilities/+merge/257488
> >>
> >> Proposal is to add an unprivileged "duplicity" user during installation
> >> that is used to limit the capabilities when duplicity is run as root. To
> >> manage capabilities, I'm using the python bindings for libcap-ng (which
> >> needs its own updating since at least the current vivid package is empty
> >> for some reason, but is correct when built from source).
> >>
> >> I've been interested in using duplicity for system-wide backups, but one
> >> thing that is troubling is that it must be run as root. As an
> interpreted
> >> program that communicates on the network, this exposes the host to
> possible
> >> bugs in python or any other packages imported in duplicity.
> >>
> >> First, examining the code in bin/duplicity:
> >>     # if python is run setuid, it's only partway set,
> >>     # so make sure to run with euid/egid of root
> >>     if os.geteuid() == 0:
> >>         # make sure uid/gid match euid/egid
> >>         os.setuid(os.geteuid())
> >>         os.setgid(os.getegid())
> >>
> >> I'm not sure what this is for; if you're root (i.e., os.geteuid() == 0)
> >> then there's no need to switch the real uid. When the machination of
> >> "setuid(geteuid())" is used it is typically when the ruid=0 and we want
> to
> >> irrevocably drop privileges to a euid!=0 normal user. That's not the
> case
> >> here, so this doesn't help or harm us.
> >>
> >> Then there's the issue of running duplicity as root. Since it's an
> >> interpreted program, the normal ways of expanding privileges (SUID
> >> executable or setcap on the script) are unavailable, and the other
> options
> >> are to run it as root, or put SUID or file capabilities on the python
> >> interpreter.
> >>
> >> The only reason to run duplicity as root is get read access to the whole
> >> file system. We can safely drop all capabilities other than
> >> CAP_DAC_READ_SEARCH. Since we're still root, we'll get all capabilities
> >> back if we do execve, so we could also change the bounding set or lock
> the
> >> securebits to prevent the kernel from re-granting privileges on execve.
> >> Nonetheless, we're still root, and lots of important files are owned by
> and
> >> writable to root, so the best choice is to change uid to an unprivileged
> >> user who maintains only the ability to read the whole file system.
> >>
> >> It's hard to test the change directly, since it doesn't change the
> output
> >> or actions of duplicity. The following python script mimics what the
> code
> >> does and demonstrates the reduction of capabilities:
> >>
> >> #!/usr/bin/env python
> >>
> >> from __future__ import print_function
> >> from capng import *
> >> import fcntl
> >> import os
> >> import pwd
> >> import signal
> >> import sys
> >>
> >> if os.geteuid() != 0:
> >>     sys.exit()
> >>
> >> user = pwd.getpwnam("nobody")
> >> capng_clear(CAPNG_SELECT_CAPS)
> >> capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
> >> CAP_DAC_READ_SEARCH)
> >> capng_change_id(user.pw_uid, user.pw_gid, CAPNG_DROP_SUPP_GRP)
> >>
> >> print("getuid = {}, geteuid = {}".format(os.getuid(), os.geteuid()))
> >> print("After dropping capabilities:")
> >> capng_get_caps_process()
> >> capng_print_caps_numeric(CAPNG_PRINT_STDOUT, CAPNG_SELECT_BOTH)
> >> print()
> >>
> >> pread, pwrite = os.pipe()
> >> pid = os.fork()
> >> if pid == 0:
> >>     os.close(pread)
> >>     fcntl.fcntl(pwrite, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
> >>     os.execl('/usr/bin/tail', '-f', '/dev/null')
> >> else:
> >>     os.close(pwrite)
> >>     os.read(pread, 1)
> >>     capng_setpid(pid)
> >>     capng_get_caps_process()
> >>     print("getuid = {}, geteuid = {}".format(os.getuid(), os.geteuid()))
> >>     print("Capabilities after execve:")
> >>     caps = capng_print_caps_numeric(CAPNG_PRINT_STDOUT,
> CAPNG_SELECT_BOTH)
> >>     os.kill(pid, signal.SIGTERM)
> >>
> >> which when run as root (sudo python script.py) should produce this
> output:
> >> getuid = 65534, geteuid = 65534
> >> After dropping capabilities:
> >> Effective:    00000000, 00000004
> >> Permitted:    00000000, 00000004
> >> Inheritable:  00000000, 00000000
> >> Bounding Set: 0000003F, FFFFFFFF
> >>
> >> getuid = 65534, geteuid = 65534
> >> Capabilities after execve:
> >> Effective:    00000000, 00000000
> >> Permitted:    00000000, 00000000
> >> Inheritable:  00000000, 00000000
> >> Bounding Set: 0000003F, FFFFFFFF
> >>
> >> --
> >> Your team duplicity-team is requested to review the proposed merge of
> >> lp:~jmwilson/duplicity/capabilities into lp:duplicity.
> >>
> >> === modified file 'README'
> >> --- README      2014-10-18 19:44:29 +0000
> >> +++ README      2015-04-27 00:30:33 +0000
> >> @@ -23,6 +23,7 @@
> >>   * librsync v0.9.6 or later
> >>   * GnuPG v1.x for encryption
> >>   * python-lockfile for concurrency locking
> >> + * python-capng for managing capabilities when run as root
> >>   * for scp/sftp -- python-paramiko and python-pycryptopp
> >>   * for ftp -- lftp version 3.7.15 or later
> >>   * Boto 2.0 or later for single-processing S3 or GCS access (default)
> >>
> >> === modified file 'bin/duplicity'
> >> --- bin/duplicity       2015-03-09 18:50:58 +0000
> >> +++ bin/duplicity       2015-04-27 00:30:33 +0000
> >> @@ -38,6 +38,8 @@
> >>  import resource
> >>  import re
> >>  import threading
> >> +import capng
> >> +import pwd
> >>  from datetime import datetime
> >>  from lockfile import FileLock
> >>
> >> @@ -1340,12 +1342,18 @@
> >>  See https://bugs.launchpad.net/duplicity/+bug/931175
> >>  """), log.ErrorCode.pythonoptimize_set)
> >>
> >> -    # if python is run setuid, it's only partway set,
> >> -    # so make sure to run with euid/egid of root
> >> +    # if python is running as root, then drop all capabilities except
> >> +    # unrestricted read access and then change user to prevent
> regaining
> >> +    # capabilities via execve.
> >>      if os.geteuid() == 0:
> >> -        # make sure uid/gid match euid/egid
> >> -        os.setuid(os.geteuid())
> >> -        os.setgid(os.getegid())
> >> +        user = pwd.getpwnam("duplicity")
> >> +        capng.capng_clear(capng.CAPNG_SELECT_CAPS)
> >> +        if (capng.capng_update(capng.CAPNG_ADD,
> >> +                              capng.CAPNG_EFFECTIVE |
> >> capng.CAPNG_PERMITTED,
> >> +                              capng.CAP_DAC_READ_SEARCH)
> >> +            or capng.capng_change_id(user.pw_uid, user.pw_gid,
> >> +                                     capng.CAPNG_DROP_SUPP_GRP)):
> >> +            log.FatalError("Unable to drop root privileges.")
> >>
> >>      # set the current time strings (make it available for command line
> >> processing)
> >>      dup_time.setcurtime()
> >>
> >> === modified file 'debian/control'
> >> --- debian/control      2014-10-27 14:15:52 +0000
> >> +++ debian/control      2015-04-27 00:30:33 +0000
> >> @@ -27,6 +27,7 @@
> >>           gnupg,
> >>           python-lockfile,
> >>           python-pexpect,
> >> +         python-capng,
> >>  Suggests: ncftp,
> >>            python-boto,
> >>            python-paramiko,
> >>
> >> === added file 'debian/duplicity.postinst'
> >> --- debian/duplicity.postinst   1970-01-01 00:00:00 +0000
> >> +++ debian/duplicity.postinst   2015-04-27 00:30:33 +0000
> >> @@ -0,0 +1,7 @@
> >> +#!/bin/sh -e
> >> +
> >> +if [ "$1" = "configure" ]; then
> >> +  if ! getent passwd duplicity >/dev/null; then
> >> +    adduser --quiet --system --no-create-home --home /nonexistant
> --shell
> >> /usr/sbin/nologin duplicity
> >> +  fi
> >> +fi
> >>
> >>
> >> _______________________________________________
> >> Mailing list: https://launchpad.net/~duplicity-team
> >> Post to     : duplicity-team@xxxxxxxxxxxxxxxxxxx
> >> Unsubscribe : https://launchpad.net/~duplicity-team
> >> More help   : https://help.launchpad.net/ListHelp
> >>
> >>
> >
>
> --
> https://code.launchpad.net/~jmwilson/duplicity/capabilities/+merge/257488
> You are subscribed to branch lp:duplicity.
>

-- 
https://code.launchpad.net/~jmwilson/duplicity/capabilities/+merge/257488
Your team duplicity-team is requested to review the proposed merge of lp:~jmwilson/duplicity/capabilities into lp:duplicity.


References