162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include "cap_helpers.h"
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci/* Avoid including <sys/capability.h> from the libcap-devel package,
562306a36Sopenharmony_ci * so directly declare them here and use them from glibc.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ciint capget(cap_user_header_t header, cap_user_data_t data);
862306a36Sopenharmony_ciint capset(cap_user_header_t header, const cap_user_data_t data);
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ciint cap_enable_effective(__u64 caps, __u64 *old_caps)
1162306a36Sopenharmony_ci{
1262306a36Sopenharmony_ci	struct __user_cap_data_struct data[_LINUX_CAPABILITY_U32S_3];
1362306a36Sopenharmony_ci	struct __user_cap_header_struct hdr = {
1462306a36Sopenharmony_ci		.version = _LINUX_CAPABILITY_VERSION_3,
1562306a36Sopenharmony_ci	};
1662306a36Sopenharmony_ci	__u32 cap0 = caps;
1762306a36Sopenharmony_ci	__u32 cap1 = caps >> 32;
1862306a36Sopenharmony_ci	int err;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci	err = capget(&hdr, data);
2162306a36Sopenharmony_ci	if (err)
2262306a36Sopenharmony_ci		return err;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	if (old_caps)
2562306a36Sopenharmony_ci		*old_caps = (__u64)(data[1].effective) << 32 | data[0].effective;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	if ((data[0].effective & cap0) == cap0 &&
2862306a36Sopenharmony_ci	    (data[1].effective & cap1) == cap1)
2962306a36Sopenharmony_ci		return 0;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	data[0].effective |= cap0;
3262306a36Sopenharmony_ci	data[1].effective |= cap1;
3362306a36Sopenharmony_ci	err = capset(&hdr, data);
3462306a36Sopenharmony_ci	if (err)
3562306a36Sopenharmony_ci		return err;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	return 0;
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ciint cap_disable_effective(__u64 caps, __u64 *old_caps)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	struct __user_cap_data_struct data[_LINUX_CAPABILITY_U32S_3];
4362306a36Sopenharmony_ci	struct __user_cap_header_struct hdr = {
4462306a36Sopenharmony_ci		.version = _LINUX_CAPABILITY_VERSION_3,
4562306a36Sopenharmony_ci	};
4662306a36Sopenharmony_ci	__u32 cap0 = caps;
4762306a36Sopenharmony_ci	__u32 cap1 = caps >> 32;
4862306a36Sopenharmony_ci	int err;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	err = capget(&hdr, data);
5162306a36Sopenharmony_ci	if (err)
5262306a36Sopenharmony_ci		return err;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if (old_caps)
5562306a36Sopenharmony_ci		*old_caps = (__u64)(data[1].effective) << 32 | data[0].effective;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (!(data[0].effective & cap0) && !(data[1].effective & cap1))
5862306a36Sopenharmony_ci		return 0;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	data[0].effective &= ~cap0;
6162306a36Sopenharmony_ci	data[1].effective &= ~cap1;
6262306a36Sopenharmony_ci	err = capset(&hdr, data);
6362306a36Sopenharmony_ci	if (err)
6462306a36Sopenharmony_ci		return err;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	return 0;
6762306a36Sopenharmony_ci}
68