Bug 1126886

Summary: Bad interaction between ptrace() and capabilities(7)
Product: [Fedora] Fedora Reporter: Bob Doolittle <bzrh.bobd>
Component: kernelAssignee: Kernel Maintainer List <kernel-maint>
Status: CLOSED NOTABUG QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: 20CC: gansalmon, itamar, jonathan, kernel-maint, madhu.chinakonda, mchehab, onestero
Target Milestone: ---   
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2014-08-19 13:23:37 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
Simple C program to bind to a port, can be used for reproducing problem none

Description Bob Doolittle 2014-08-05 14:05:58 UTC
Created attachment 924221 [details]
Simple C program to bind to a port, can be used for reproducing problem

Description of problem:

When a process is run under ptrace, the capabilities masks are not honored. There is no mention of such a restriction on the capabilties(7) man page, and it causes problems for services such as Upstart when attempting to trace a daemon that forks initially, to obtain the PID to wait for.

Version-Release number of selected component (if applicable):
kernel 3.15.7-200.fc20.x86_64

How reproducible:
100%

Steps to Reproduce:
The attached C program will bind to the port specified on the command line, and report success of failure. It will sleep for a while after the bind (if it succeeds) to allow process inspection.

1. Compile the program, and run it as non-root, passing a privileged port on the command line (e.g. 443), and observe that it fails as expected.

2. As root, run:
# setcap 'cap_net_bind_service+iep' PROGRAM

3. Run the program as non-root, and observe that it succeeds.

4. strace the program as non-root, and observe that it fails.

For steps 3 and 4, if you cat /proc/PID/status while the process is running (e.g. while it is sleeping after the bind), you'll notice that for step 3:
CapInh:	0000000000000000
CapPrm:	0000000000000400
CapEff:	0000000000000400

While for step 4:
CapInh:	0000000000000000
CapPrm:	0000000000000000
CapEff:	0000000000000000

This demonstrates that somehow ptrace has managed to clear the capabilities sets for Permitted and Effective. Note I do not understand why CapInh is zero in step 3. This does not match the behavior I expect from the man page.

Actual results:
Bind fails in step 4

Expected results:
Bind should succeed whether or not it is run under ptrace, if capability is set

Additional info:

Comment 1 Josh Boyer 2014-08-18 20:01:15 UTC
Oleg, any ideas on this one?

Off the top of my head, I would think the program being ptraced would inherit the capabilities of the parent that started it.  The strace program isn't going to have those capabilities set, so it would make sense the application it starts doesn't.  Otherwise it seems it would be a trivial thing to exploit to gain additional priviledges as a normal user.

Comment 2 Oleg Nesterov 2014-08-19 12:54:10 UTC
(In reply to Josh Boyer from comment #1)
>
> Oleg, any ideas on this one?

This looks correct.

Lets forget about capabilities for the moment. strace suid-binary won't
work, and for obvious reasons. The same is true for capabilities, it is
not safe to allow the unprivileged user to control the application which
runs with the raised privileges.

If /usr/bin/strace has CAP_SYS_PTRACE it should probably work, but I did
not verify and I never understood in details how capabilities work.

NOTABUG, I think.

Comment 3 Josh Boyer 2014-08-19 13:23:37 UTC
Thanks Oleg.