setpriv: support setting unnamed capabilities

When setting capabilities, we accept human readable names like for
example `sys_rawio` or `net_admin`. To do so the translation between the
capability name and its in-kernel index, we rely on the function
`capng_name_to_capability`. When the function does not know the named
capability, it will return an error value and we abort setting the
capability.

This relies upon the ability of libcap to know all capabilities inside
of the kernel. But actually, it is possible that new capabilities are
introduced inside of the Linux kernel which are not recognized yet by
the library. When dumping these unknown capabilities, libcap will simply
return a string like "cap_38", that is it will append the capability's
in-kernel index to the prefix "cap_". This may lead a user to also think
that "cap_38" may be passed to the switches "--inh-caps" or
"--ambient-caps", which is unfortunately not the case.

We can do better here by instead accepting strings in the form of
"cap_N". To do so, we can simply rely on the fact that capability
indices are steadily increasing and that the highest index known to the
kernel is stored inside of the kernel's procfs, made readily available
by our function `real_cap_last_cap()`. So in case libcap does not know a
capability name, we can simply parse the string and, if it is in the
correct format, check whether the detected index is between 0 and the
highest capability index. If so, we can treat it as a valid capability
string and apply it.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
This commit is contained in:
Patrick Steinhardt 2017-07-17 23:14:09 +02:00 committed by Karel Zak
parent 18751601a8
commit fbd15c4d47
1 changed files with 3 additions and 0 deletions

View File

@ -529,6 +529,9 @@ static void do_caps(enum cap_type type, const char *caps)
int cap = capng_name_to_capability(c + 1);
if (0 <= cap)
cap_update(action, type, cap);
else if (sscanf(c + 1, "cap_%d", &cap) == 1
&& 0 <= cap && cap <= real_cap_last_cap())
cap_update(action, type, cap);
else
errx(EXIT_FAILURE,
_("unknown capability \"%s\""), c + 1);