Linux kernel shows the warning below, when _LINUX_CAPABILITY_VERSION_1 is
used in capset() and capget().
[
1710243.523230] capability: warning: `haproxy' uses 32-bit capabilities (legacy support in use)
This triggers questions from users. Warning is shown by kernel, because
since Linux 2.6.25, 64-bit capabilities support was introduced in
_LINUX_CAPABILITY_VERSION_2. It's in order to be able to continiously
extend capabilities list with the new ones.
We can't use _LINUX_CAPABILITY_VERSION_2, because this version triggers
another warning, according linux/kernel/capability.c (see also more details
about it in comments from kernel sources and in man capset(2)).
kernel/capability.c:
...
static int cap_validate_magic(cap_user_header_t header, unsigned *tocopy)
{
__u32 version;
if (get_user(version, &header->version))
return -EFAULT;
switch (version) {
case _LINUX_CAPABILITY_VERSION_1:
warn_legacy_capability_use();
*tocopy = _LINUX_CAPABILITY_U32S_1;
break;
case _LINUX_CAPABILITY_VERSION_2:
warn_deprecated_v2();
fallthrough; /* v3 is otherwise equivalent to v2 */
case _LINUX_CAPABILITY_VERSION_3:
*tocopy = _LINUX_CAPABILITY_U32S_3;
break;
default:
...
So, to avoid any warnings, lets use _LINUX_CAPABILITY_VERSION_3, which
according to comments in linux/kernel/capability.c, has the same
functionality as _LINUX_CAPABILITY_VERSION_2 (i.e. array of 2
__user_cap_data_struct with 32-bits integers for each capability set), but
comes in Linux 2.6.26 with a header change, in order to protect legacy
source code.
For the moment, we don't authorize capabilities higher, than CAP_SYS_ADMIN
(21-st bit), so we always check the "low" 32 bits, i.e.
__user_cap_data_struct[0].
struct __user_cap_header_struct cap_hdr_haproxy = {
.pid = 0, /* current process */
- .version = _LINUX_CAPABILITY_VERSION_1,
+ .version = _LINUX_CAPABILITY_VERSION_3,
};
/* supported names, zero-terminated */
* only _LINUX_CAPABILITY_U32S_1 * (sizeof(struct __user_cap_data_struct)),
* i.e. only the __user_cap_data_struct[0].
*/
- struct __user_cap_data_struct start_cap_data[_LINUX_CAPABILITY_U32S_1] = { };
+ struct __user_cap_data_struct start_cap_data[_LINUX_CAPABILITY_U32S_3] = { };
/* started as root */
if (!from_uid)
* only _LINUX_CAPABILITY_U32S_1 * (sizeof(struct __user_cap_data_struct)),
* i.e. only the __user_cap_data_struct[0].
*/
- struct __user_cap_data_struct cap_data[_LINUX_CAPABILITY_U32S_1] = { };
+ struct __user_cap_data_struct cap_data[_LINUX_CAPABILITY_U32S_3] = { };
if (from_uid != 0)
return 0;
*/
int finalize_caps_after_setuid(int from_uid, int to_uid)
{
- struct __user_cap_data_struct cap_data[_LINUX_CAPABILITY_U32S_1] = { };
+ struct __user_cap_data_struct cap_data[_LINUX_CAPABILITY_U32S_3] = { };
if (from_uid != 0)
return 0;