Merge lp:~jmwilson/duplicity/capabilities into lp:~duplicity-team/duplicity/0.7-series
Status: | Superseded |
---|---|
Proposed branch: | lp:~jmwilson/duplicity/capabilities |
Merge into: | lp:~duplicity-team/duplicity/0.7-series |
Diff against target: |
72 lines (+22/-5) 4 files modified
README (+1/-0) bin/duplicity (+13/-5) debian/control (+1/-0) debian/duplicity.postinst (+7/-0) |
To merge this branch: | bzr merge lp:~jmwilson/duplicity/capabilities |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
duplicity-team | Pending | ||
Review via email: mp+257488@code.launchpad.net |
This proposal has been superseded by a proposal from 2015-08-03.
Description of the change
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
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_
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(
capng_clear(
capng_update(
capng_change_
print("getuid = {}, geteuid = {}".format(
print("After dropping capabilities:")
capng_get_
capng_print_
print()
pread, pwrite = os.pipe()
pid = os.fork()
if pid == 0:
os.close(pread)
fcntl.
os.
else:
os.
os.read(pread, 1)
capng_
capng_
print("getuid = {}, geteuid = {}".format(
print(
caps = capng_print_
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
Unmerged revisions
- 1089. By James Wilson
-
Drop capabilities and change user when duplicity is run as root.
If I understand this correctly, then new files will be created by duplicity/ *'
'duplicity', but older files owned by root will not be deletable.
Correct? I'm thinking a one-time 'chown -R duplicity: ~/cache/
would fix that problem.
On Sun, Apr 26, 2015 at 7:31 PM, James Wilson <email address hidden> wrote:
> James Wilson has proposed merging lp:~jmwilson/duplicity/capabilities into /code.launchpad .net/~jmwilson/ duplicity/ capabilities/ +merge/ 257488 os.geteuid( )) os.getegid( )) READ_SEARCH. Since we're still root, we'll get all capabilities "nobody" )
> lp:duplicity.
>
> Requested reviews:
> duplicity-team (duplicity-team)
>
> For more details, see:
> https:/
>
> 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.setgid(
>
> 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_
> 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(
> capng_clear...