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 <[email protected]> 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 : [email protected] >> Unsubscribe : https://launchpad.net/~duplicity-team >> More help : https://help.launchpad.net/ListHelp >> >> > -- 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. _______________________________________________ Mailing list: https://launchpad.net/~duplicity-team Post to : [email protected] Unsubscribe : https://launchpad.net/~duplicity-team More help : https://help.launchpad.net/ListHelp

