[systemd-devel] Running a systemd service in capability-only environment as non-root user

Michal Witanowski m.witanowski at samsung.com
Wed May 28 03:37:25 PDT 2014


On 05/28/2014 12:07 AM, Serge Hallyn wrote:
> Quoting Mantas Mikulėnas (grawity at gmail.com):
>> On Tue, May 27, 2014 at 4:31 PM, Michal Witanowski
>> <m.witanowski at samsung.com> wrote:
>>> Hi,
>>>
>>> first of all I'd like to mark that I'm not sure if I'm writing in the right
>>> place.
>>>
>>> I have a problem with running a systemd service in "capability-only
>>> environment": I want to run a process with some caps (cap_sys_admin
>>> cap_dac_override cap_mac_override) as a regular user (UID != 0).
>>> My service config file looks something like this:
>>>
>>> User=test
>>> CapabilityBoundingSet=cap_sys_admin cap_dac_override cap_mac_override
>>> Capabilities=cap_sys_admin,cap_dac_override,cap_mac_override=eip
>>> SecureBits=keep-caps
>>>
>>> Unfortunately, the process does not gain any permissive capabilities:
>>>
>>> CapInh: 0000000100200002
>>> CapPrm: 0000000000000000
>>> CapEff: 0000000000000000
>>> CapBnd: 0000000100200002
>>>
>>> However, when I run the service as root (by removing "User=test") the
>>> process does own required caps:
>>>
>>> CapInh: 0000000100200002
>>> CapPrm: 0000000100200002
>>> CapEff: 0000000100200002
>>> CapBnd: 0000000100200002
>> Does the executable file itself have these capabilities set as "=ei"?
>>
>> According to the same manual page, each capability must be set as
>> inheritable for both the process and the file, to receive them _at
>> all_...
>>
>> "P'(permitted) = (P(inheritable) & F(inheritable)) | (F(permitted) & cap_bset)"
>>
>> ...and as effective on the file, otherwise the new process has to
>> manually 'enable' them:
>>
>> "P'(effective) = F(effective) ? P'(permitted) : 0"
>>
>> ...or at least that seems to be how it works. Damn thing is confusing.
> Correct.  keep_caps is about not dropping the capabilities when dropping
> all 0 uids, i.e. when systemd does setuid(test).  But systemd is going
> to proceed to exec(), causing the capabilities to be re-execed from
> there.
>
> So as Mantas wrote, I think what you want is to set
> cap_sys_admin,cap_dac_override,cap_mac_override=ie to the file you are
> executing.  So long as you don't also set it to 'p', this should be ok
> as only processes with cap_sys_admin,cap_dac_override,cap_mac_override=i
> will inherit it from the file.
>
> Kinda neat, I especially like the ability to also lock the
> service into no-setuid and noroot secbits.
>
> -serge
>
The executable does not own any capabilities, since setting them in RPM 
scripts would be a security hole. Of course, enabling them manually 
fixes the problem, but it does not explain the difference in caps set 
when launching an app as root vs. non-root, ie. when UID==0, the formula:

P'(permitted) = (P(inheritable) & F(inheritable)) | (F(permitted) & cap_bset)

doesn't work. Does it mean that when launching an app as root, exec() is 
not called at all and the process gains full capabilities set (except 
restrictions introduced by bounding set)? Is the only solution to this 
problem setting the file caps before service starting?

BRs,
Michal


More information about the systemd-devel mailing list