Skip to content

Commit

Permalink
feat(box): support capabilities manipulation
Browse files Browse the repository at this point in the history
Signed-off-by: ComixHe <[email protected]>
  • Loading branch information
ComixHe authored and dengbo11 committed Dec 26, 2024
1 parent d9544e2 commit a3a04ef
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 9 deletions.
2 changes: 2 additions & 0 deletions apps/ll-box/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ if(${STATIC_BOX})
endif()

pkg_search_module(SECCOMP REQUIRED IMPORTED_TARGET libseccomp)
pkg_search_module(CAP REQUIRED IMPORTED_TARGET libcap)

pfl_add_executable(
SOURCES
Expand Down Expand Up @@ -51,6 +52,7 @@ pfl_add_executable(
nlohmann_json::nlohmann_json
linglong::ocppi
PkgConfig::SECCOMP
PkgConfig::CAP
COMPILE_OPTIONS
PRIVATE
-DJSON_USE_IMPLICIT_CONVERSIONS=0)
Expand Down
98 changes: 91 additions & 7 deletions apps/ll-box/src/container/container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@
#include "container/helper.h"
#include "container/mount/filesystem_driver.h"
#include "container/mount/host_mount.h"
#include "container/seccomp.h"
#include "util/debug/debug.h"
#include "util/filesystem.h"
#include "util/logger.h"
#include "util/platform.h"
#include "util/semaphore.h"

#include <sys/capability.h>
#include <sys/epoll.h>
#include <sys/mount.h>
#include <sys/prctl.h>
Expand Down Expand Up @@ -217,6 +215,82 @@ static bool parse_wstatus(const int &wstatus, std::string &info)
}
}

int setCapabilities(const Capabilities &capabilities)
{
auto get_cap_list = [](const util::str_vec &cap_str_vec) -> std::vector<cap_value_t> {
std::vector<cap_value_t> cap_list;
for (const auto &cap : cap_str_vec) {
if (auto it = capsMap.find(cap); it != capsMap.end()) {
cap_list.push_back(it->second);
}
}

return cap_list;
};

std::unique_ptr<_cap_struct, decltype(&cap_free)> caps(cap_get_proc(), cap_free);
if (caps == nullptr) {
logErr() << "call cap_get_proc failed" << util::RetErrString(0);
return 1;
}

if (!capabilities.effective.empty()
&& cap_set_flag(caps.get(),
CAP_EFFECTIVE,
capabilities.effective.size(),
get_cap_list(capabilities.effective).data(),
CAP_SET)
== -1) {
logErr() << "cap_set_flag CAP_EFFECTIVE" << util::RetErrString(-1);
return -1;
}

if (!capabilities.permitted.empty()
&& cap_set_flag(caps.get(),
CAP_PERMITTED,
capabilities.permitted.size(),
get_cap_list(capabilities.permitted).data(),
CAP_SET)
== -1) {
logErr() << "cap_set_flag CAP_PERMITTED" << util::RetErrString(-1);
return -1;
}

if (!capabilities.inheritable.empty()
&& cap_set_flag(caps.get(),
CAP_INHERITABLE,
capabilities.inheritable.size(),
get_cap_list(capabilities.inheritable).data(),
CAP_SET)
== -1) {
logErr() << "cap_set_flag CAP_INHERITABLE" << util::RetErrString(-1);
return -1;
}

// apply the modified capabilities to the process
if (cap_set_proc(caps.get()) == -1) {
logErr() << "cap_set_proc" << util::RetErrString(-1);
return -1;
}

for (auto cap : get_cap_list(capabilities.ambient)) {
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0) == -1) {
logErr() << "prctl PR_CAP_AMBIENT PR_CAP_AMBIENT_RAISE" << cap
<< util::RetErrString(-1);
return -1;
}
}

for (auto cap : get_cap_list(capabilities.bounding)) {
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, cap, 0, 0) == -1) {
logErr() << "prctl PR_CAP_AMBIENT PR_CAP_AMBIENT_LOWER" << util::RetErrString(-1);
return -1;
}
}

return 0;
}

struct ContainerPrivate
{
ContainerPrivate(Runtime r, const std::string &bundle, Container * /*unused*/)
Expand Down Expand Up @@ -583,12 +657,22 @@ int NonePrivilegeProc(void *arg)
idMap.size = 1;
linux.gidMappings.push_back(idMap);

if (auto ret = ConfigUserNamespace(linux, 0); ret != 0) {
return ret;
int ret{ -1 };
if (containerPrivate.runtime.process.capabilities) {
ret = setCapabilities(containerPrivate.runtime.process.capabilities.value());
if (ret == -1) {
logErr() << "setCapabilities failed";
return -1;
}
}

auto ret = mount("proc", "/proc", "proc", 0, nullptr);
if (0 != ret) {
if (ret = ConfigUserNamespace(linux, 0); ret != 0) {
logErr() << "ConfigUserNamespace failed";
return -1;
}

ret = mount("proc", "/proc", "proc", 0, nullptr);
if (ret == -1) {
logErr() << "mount proc failed" << util::RetErrString(ret);
return -1;
}
Expand Down
31 changes: 31 additions & 0 deletions apps/ll-box/src/util/debug/debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#include "util/logger.h"

#include <sys/capability.h>

#include <dirent.h>
#include <grp.h>
#include <pwd.h>
Expand All @@ -19,6 +21,35 @@ namespace linglong {
#define DUMP_DBG(func, line) /*NOLINT*/ \
(linglong::util::Logger(linglong::util::Logger::Debug, func, line))

void DumpCap()
{
cap_flag_value_t cap_value;
cap_value_t cap;

logDbg() << "start -----------";

// Get the current process capabilities
std::unique_ptr<_cap_struct, decltype(cap_free) *> caps(cap_get_proc(), cap_free);

// Iterate through all capabilities
for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
if (cap_get_flag(caps.get(), cap, CAP_EFFECTIVE, &cap_value) == -1) {
logDbg() << "cap_get_flag failed";
continue;
}

const char *cap_name = cap_to_name(cap);
if (cap_name == nullptr) {
logDbg() << "Unknown capability: " << cap;
continue;
}

logDbg() << cap_name << ": " << (cap_value == CAP_SET ? "yes" : "no");
}

logDbg() << "end -----------";
}

void DumpIDMap()
{
logDbg() << "DumpIDMap Start -----------";
Expand Down
2 changes: 2 additions & 0 deletions apps/ll-box/src/util/debug/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ namespace linglong {

#define DUMP_FILE_INFO(path) DumpFileInfo1(path, __FUNCTION__, __LINE__)

void DumpCap();

void DumpIDMap();

void DumpUidGidGroup();
Expand Down
76 changes: 76 additions & 0 deletions apps/ll-box/src/util/oci_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "util.h"

#include <sys/capability.h>
#include <sys/mount.h>

// Compatible with linux kernel which is under 5.10
Expand Down Expand Up @@ -52,25 +53,100 @@ LLJS_TO_OBJ(Root)
LLJS_TO(readonly);
}

const static std::map<std::string_view, int> capsMap{
{ "CAP_CHOWN", CAP_CHOWN },
{ "CAP_DAC_OVERRIDE", CAP_DAC_OVERRIDE },
{ "CAP_DAC_READ_SEARCH", CAP_DAC_READ_SEARCH },
{ "CAP_FOWNER", CAP_FOWNER },
{ "CAP_FSETID", CAP_FSETID },
{ "CAP_KILL", CAP_KILL },
{ "CAP_SETGID", CAP_SETGID },
{ "CAP_SETUID", CAP_SETUID },
{ "CAP_SETPCAP", CAP_SETPCAP },
{ "CAP_LINUX_IMMUTABLE", CAP_LINUX_IMMUTABLE },
{ "CAP_NET_BIND_SERVICE", CAP_NET_BIND_SERVICE },
{ "CAP_NET_BROADCAST", CAP_NET_BROADCAST },
{ "CAP_NET_ADMIN", CAP_NET_ADMIN },
{ "CAP_NET_RAW", CAP_NET_RAW },
{ "CAP_IPC_LOCK", CAP_IPC_LOCK },
{ "CAP_IPC_OWNER", CAP_IPC_OWNER },
{ "CAP_SYS_MODULE", CAP_SYS_MODULE },
{ "CAP_SYS_RAWIO", CAP_SYS_RAWIO },
{ "CAP_SYS_CHROOT", CAP_SYS_CHROOT },
{ "CAP_SYS_PTRACE", CAP_SYS_PTRACE },
{ "CAP_SYS_PACCT", CAP_SYS_PACCT },
{ "CAP_SYS_ADMIN", CAP_SYS_ADMIN },
{ "CAP_SYS_BOOT", CAP_SYS_BOOT },
{ "CAP_SYS_NICE", CAP_SYS_NICE },
{ "CAP_SYS_RESOURCE", CAP_SYS_RESOURCE },
{ "CAP_SYS_TIME", CAP_SYS_TIME },
{ "CAP_SYS_TTY_CONFIG", CAP_SYS_TTY_CONFIG },
{ "CAP_MKNOD", CAP_MKNOD },
{ "CAP_LEASE", CAP_LEASE },
{ "CAP_AUDIT_WRITE", CAP_AUDIT_WRITE },
{ "CAP_AUDIT_CONTROL", CAP_AUDIT_CONTROL },
{ "CAP_SETFCAP", CAP_SETFCAP },
{ "CAP_MAC_OVERRIDE", CAP_MAC_OVERRIDE },
{ "CAP_MAC_ADMIN", CAP_MAC_ADMIN },
{ "CAP_SYSLOG", CAP_SYSLOG },
{ "CAP_WAKE_ALARM", CAP_WAKE_ALARM },
{ "CAP_BLOCK_SUSPEND", CAP_BLOCK_SUSPEND },
{ "CAP_AUDIT_READ", CAP_AUDIT_READ }
};

struct Capabilities
{
util::str_vec bounding;
util::str_vec permitted;
util::str_vec inheritable;
util::str_vec effective;
util::str_vec ambient;
};

inline void from_json(const nlohmann::json &j, Capabilities &o)
{
o.bounding = j.at("bounding").get<util::str_vec>();
o.permitted = j.at("permitted").get<util::str_vec>();
o.inheritable = j.at("inheritable").get<util::str_vec>();
o.effective = j.at("effective").get<util::str_vec>();
o.ambient = j.at("ambient").get<util::str_vec>();
}

inline void to_json(nlohmann::json &j, const Capabilities &o)
{
j["bounding"] = o.bounding;
j["permitted"] = o.permitted;
j["inheritable"] = o.inheritable;
j["effective"] = o.effective;
j["ambient"] = o.ambient;
}

struct Process
{
util::str_vec args;
util::str_vec env;
std::string cwd;
std::optional<Capabilities> capabilities;
};

inline void from_json(const nlohmann::json &j, Process &o)
{
o.args = j.at("args").get<util::str_vec>();
o.env = j.at("env").get<util::str_vec>();
o.cwd = j.at("cwd").get<std::string>();
if (j.find("capabilities") != j.end()) {
o.capabilities = j.at("capabilities").get<Capabilities>();
}
}

inline void to_json(nlohmann::json &j, const Process &o)
{
j["args"] = o.args;
j["env"] = o.env;
j["cwd"] = o.cwd;
if (o.capabilities) {
j["capabilities"] = o.capabilities;
}
}

struct Mount
Expand Down
3 changes: 2 additions & 1 deletion debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ Build-Depends: cmake,
qtbase5-dev,
qtbase5-private-dev,
systemd,
zlib1g-dev
zlib1g-dev,
libcap-dev
Standards-Version: 4.1.3
Homepage: http://www.deepin.org

Expand Down
2 changes: 1 addition & 1 deletion rpm/linglong.spec
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ BuildRequires: qt5-qtbase-devel qt5-qtbase-private-devel
BuildRequires: glib2-devel nlohmann-json-devel ostree-devel yaml-cpp-devel
BuildRequires: systemd-devel gtest-devel libseccomp-devel elfutils-libelf-devel
BuildRequires: glibc-static libstdc++-static
BuildRequires: libcurl-devel openssl-devel
BuildRequires: libcurl-devel openssl-devel libcap-devel
BuildRequires: gtest-devel gmock-devel
Requires: linglong-bin = %{version}-%{release}

Expand Down

0 comments on commit a3a04ef

Please sign in to comment.