* Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
* ubs-engine is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include "ubse_security_manager.h"
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <cstring>
#include <iostream>
#include <vector>
#include <linux/capability.h>
#include <securec.h>
#include <bitset>
#include "ubse_error.h"
#include "ubse_logger_module.h"
namespace ubse::security {
using namespace ubse::log;
UBSE_DEFINE_THIS_MODULE("ubse");
constexpr unsigned long long CAP_FULL_BIT = 64;
constexpr unsigned long long CAP_SEGMENT_BIT = 32;
constexpr unsigned long long CAP_SEGMENT_COUNT = 2;
UbseResult UbseSecurityManager::GetCapabilities()
{
__user_cap_header_struct capHeader{};
capHeader.version = _LINUX_CAPABILITY_VERSION_3;
capHeader.pid = 0;
const auto data = new (std::nothrow) __user_cap_data_struct[CAP_SEGMENT_COUNT];
if (data == nullptr) {
return UBSE_ERROR_NULLPTR;
}
auto ret = memset_s(data, sizeof(__user_cap_data_struct) * CAP_SEGMENT_COUNT, 0,
sizeof(__user_cap_data_struct) * CAP_SEGMENT_COUNT);
if (ret != EOK) {
delete[] data;
return ret;
}
errno = 0;
if (syscall(SYS_capget, &capHeader, data) < 0) {
perror("Failed to get capabilities");
delete[] data;
return UBSE_ERROR;
}
delete[] data;
return UBSE_OK;
}
void SetCapabilitiesData(__user_cap_data_struct* capData)
{
const std::vector<__u32> pCapabilities = {
CAP_SYS_NICE,
CAP_FOWNER,
CAP_DAC_OVERRIDE,
CAP_DAC_READ_SEARCH,
CAP_CHOWN,
CAP_AUDIT_WRITE,
CAP_NET_ADMIN,
CAP_SYS_PTRACE,
};
const std::vector<__u32> eCapabilities = {
CAP_SYS_NICE,
CAP_DAC_READ_SEARCH,
CAP_AUDIT_WRITE,
CAP_NET_ADMIN,
CAP_SYS_PTRACE,
};
const std::vector<__u32> iCapabilities = {
CAP_DAC_OVERRIDE,
};
for (const auto cap : pCapabilities) {
if (cap >= CAP_SEGMENT_BIT) {
capData[1].permitted |= (1ULL << (cap - CAP_SEGMENT_BIT));
} else {
capData[0].permitted |= (1ULL << cap);
}
}
for (const auto cap : eCapabilities) {
if (cap >= CAP_SEGMENT_BIT) {
capData[1].effective |= (1ULL << (cap - CAP_SEGMENT_BIT));
} else {
capData[0].effective |= (1ULL << cap);
}
}
for (const auto cap : iCapabilities) {
if (cap >= CAP_SEGMENT_BIT) {
capData[1].inheritable |= (1ULL << (cap - CAP_SEGMENT_BIT));
} else {
capData[0].inheritable |= (1ULL << cap);
}
}
}
UbseResult UbseSecurityManager::SetInitialCapabilities()
{
__user_cap_header_struct capHeader{};
capHeader.version = _LINUX_CAPABILITY_VERSION_3;
capHeader.pid = 0;
const auto capData = new (std::nothrow) __user_cap_data_struct[CAP_SEGMENT_COUNT];
if (capData == nullptr) {
return UBSE_ERROR_NULLPTR;
}
auto ret = memset_s(capData, sizeof(__user_cap_data_struct) * CAP_SEGMENT_COUNT, 0,
sizeof(__user_cap_data_struct) * CAP_SEGMENT_COUNT);
if (ret != EOK) {
delete[] capData;
return ret;
}
SetCapabilitiesData(capData);
errno = 0;
if (syscall(SYS_capset, &capHeader, capData) < 0) {
perror("Failed to set capabilities");
delete[] capData;
return UBSE_ERROR;
}
delete[] capData;
return UBSE_OK;
}
UbseResult UbseSecurityManager::ModifyEffectiveCapabilities(const std::vector<__u32>& caps, bool isAdd)
{
__user_cap_header_struct capHeader;
capHeader.version = _LINUX_CAPABILITY_VERSION_3;
capHeader.pid = 0;
__user_cap_data_struct capData[CAP_SEGMENT_COUNT];
if (syscall(SYS_capget, &capHeader, capData) < 0) {
UBSE_LOG_ERROR << "Failed to get capabilities, " << FormatRetCode(UBSE_ERROR);
return UBSE_ERROR;
}
for (const auto cap : caps) {
if (!(capData[CAP_TO_INDEX(cap)].permitted & CAP_TO_MASK(cap))) {
UBSE_LOG_ERROR << "Capability not in permitted set, " << FormatRetCode(UBSE_ERROR_INVAL);
return UBSE_ERROR_INVAL;
}
}
if (isAdd) {
for (const auto cap : caps) {
capData[CAP_TO_INDEX(cap)].effective |= CAP_TO_MASK(cap);
}
} else {
for (const auto cap : caps) {
capData[CAP_TO_INDEX(cap)].effective &= ~CAP_TO_MASK(cap);
}
}
if (syscall(SYS_capset, &capHeader, capData) < 0) {
UBSE_LOG_ERROR << "Failed to set capabilities, " << FormatRetCode(UBSE_ERROR);
return UBSE_ERROR;
}
return UBSE_OK;
}
}