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

Mantas Mikulėnas grawity at gmail.com
Wed May 28 04:52:46 PDT 2014


On Wed, May 28, 2014 at 1:37 PM, Michal Witanowski
<m.witanowski at samsung.com> wrote:
>
> 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

Not sure what security hole you see here. If the executable owns
cap_foo=ei (*not* cap_foo=eip), then running it will not grant any
capabilities unless its process (or the parent process) explicitly
adds them to the inheritable set...

> 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?

When launching the app as root, exec() *is* called of course, but the
difference is that uid 0 always has all capabilities after an exec
(unless the "noroot" securebit was set):

"Capabilities and execution of programs by root
       In  order  to  provide  an  all-powerful  root  using
capability sets, during an
       execve(2):

       1. If a set-user-ID-root program is being executed, or the real
user ID  of  the
          process  is 0 (root) then the file inheritable and permitted
sets are defined
          to be all ones (i.e., all capabilities enabled)."

-- 
Mantas Mikulėnas <grawity at gmail.com>


More information about the systemd-devel mailing list