Apply nodiscard to critical core bounds validation and setup primitives

This commit is contained in:
Robert Swiecki
2026-04-13 21:29:26 +02:00
parent ca4e1654a6
commit 7205b841a6
13 changed files with 55 additions and 55 deletions

10
caps.cc
View File

@@ -106,7 +106,7 @@ static std::string capToStr(int val) {
return util::StrPrintf("CAP_UNKNOWN(%d)", val);
}
static bool getCaps(cap_user_data_t cap_data) {
[[nodiscard]] static bool getCaps(cap_user_data_t cap_data) {
const struct __user_cap_header_struct cap_hdr = {
.version = _LINUX_CAPABILITY_VERSION_3,
.pid = 0,
@@ -118,7 +118,7 @@ static bool getCaps(cap_user_data_t cap_data) {
return true;
}
static bool setCaps(const cap_user_data_t cap_data) {
[[nodiscard]] static bool setCaps(const cap_user_data_t cap_data) {
const struct __user_cap_header_struct cap_hdr = {
.version = _LINUX_CAPABILITY_VERSION_3,
.pid = 0,
@@ -136,19 +136,19 @@ static void clearInheritable(cap_user_data_t cap_data) {
}
}
static bool getPermitted(cap_user_data_t cap_data, unsigned int cap) {
[[nodiscard]] static bool getPermitted(cap_user_data_t cap_data, unsigned int cap) {
size_t off_byte = CAP_TO_INDEX(cap);
unsigned mask = CAP_TO_MASK(cap);
return cap_data[off_byte].permitted & mask;
}
static bool getEffective(cap_user_data_t cap_data, unsigned int cap) {
[[nodiscard]] static bool getEffective(cap_user_data_t cap_data, unsigned int cap) {
size_t off_byte = CAP_TO_INDEX(cap);
unsigned mask = CAP_TO_MASK(cap);
return cap_data[off_byte].effective & mask;
}
static bool getInheritable(cap_user_data_t cap_data, unsigned int cap) {
[[nodiscard]] static bool getInheritable(cap_user_data_t cap_data, unsigned int cap) {
size_t off_byte = CAP_TO_INDEX(cap);
unsigned mask = CAP_TO_MASK(cap);
return cap_data[off_byte].inheritable & mask;

View File

@@ -131,7 +131,7 @@ struct ThreadCtx {
static thread_local ThreadCtx current_ctx;
bool addFd(int fd, uint32_t events, fdCb_t cb, void* data) {
[[nodiscard]] bool addFd(int fd, uint32_t events, fdCb_t cb, void* data) {
if (fd < 0) {
return false;
}

View File

@@ -34,7 +34,7 @@ constexpr uint32_t MSG_TAG_ERROR = quad('E', 'R', 'R', 'F');
typedef void (*fdCb_t)(int fd, uint32_t events, void* data);
typedef void (*periodicCb_t)();
bool addFd(int fd, uint32_t events, fdCb_t cb, void* data);
[[nodiscard]] bool addFd(int fd, uint32_t events, fdCb_t cb, void* data);
bool removeFd(int fd);
bool modFd(int fd, uint32_t events);
void addPeriodic(periodicCb_t cb);

4
net.cc
View File

@@ -353,7 +353,7 @@ static void pastaProcess(nsj_t* nsj, int pid, int err_pipe) {
pasta_path = argv[0];
}
util::makeRangeCOE(STDERR_FILENO + 1, ~0U);
(void)util::makeRangeCOE(STDERR_FILENO + 1, ~0U);
/* LOG doesn't use STDERR_FILENO so it's fine to use it */
int err = 0;
@@ -369,7 +369,7 @@ static void pastaProcess(nsj_t* nsj, int pid, int err_pipe) {
PLOG_W("execvpe('%s')", pasta_path);
}
util::writeToFd(err_pipe, &err, sizeof(err));
(void)util::writeToFd(err_pipe, &err, sizeof(err));
}
static bool spawnPasta(nsj_t* nsj, int pid) {

View File

@@ -539,7 +539,7 @@ static void handle_host_udp_control(Context* ctx, UdpFlow* flow, uint32_t events
kUdpStateTable[state_idx].on_host_control(ctx, flow, events);
}
static bool udp_setup_socks5_control(
[[nodiscard]] static bool udp_setup_socks5_control(
Context* ctx, UdpFlow* flow, uint32_t proxy_ip4, uint16_t proxy_port) {
int tcp_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
if (tcp_fd == -1) {
@@ -580,7 +580,7 @@ static bool udp_setup_socks5_control(
return true;
}
static int create_and_bind_udp_socket(Context* ctx) {
[[nodiscard]] static int create_and_bind_udp_socket(Context* ctx) {
int fd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
if (fd == -1) {
PLOG_E("socket(AF_INET, SOCK_DGRAM) for UDP flow failed");

View File

@@ -89,7 +89,7 @@ bool installUnotifyFilter(nsj_t* nsj, int ipc_fd) {
return true;
}
static bool prepareAndCommit(nsj_t* nsj) {
[[nodiscard]] static bool prepareAndCommit(nsj_t* nsj) {
if (nsj->seccomp_fprog.len == 0) {
return true;
}
@@ -114,7 +114,7 @@ static bool prepareAndCommit(nsj_t* nsj) {
return true;
}
bool applyPolicy(nsj_t* nsj, int ipc_fd) {
[[nodiscard]] bool applyPolicy(nsj_t* nsj, int ipc_fd) {
if (ipc_fd != -1 && nsj->njc.seccomp_unotify()) {
if (!installUnotifyFilter(nsj, ipc_fd)) {
return false;
@@ -123,7 +123,7 @@ bool applyPolicy(nsj_t* nsj, int ipc_fd) {
return prepareAndCommit(nsj);
}
bool preparePolicy(nsj_t* nsj) {
[[nodiscard]] bool preparePolicy(nsj_t* nsj) {
nsj->seccomp_fprog.len = 0;
nsj->seccomp_fprog.filter = nullptr;
nsj->seccomp_unotify_fprog.len = 0;

View File

@@ -117,7 +117,7 @@ static std::string cloneFlagsToStr(uint64_t flags) {
}
/* Reset the execution environment for the new process */
static bool resetEnv(void) {
[[nodiscard]] static bool resetEnv(void) {
/* Set all previously changed signals to their default behavior */
for (const auto& sig : nssigs) {
if (signal(sig, SIG_DFL) == SIG_ERR) {
@@ -452,7 +452,7 @@ void killAll(nsj_t* nsj, int signal) {
}
}
static bool initParent(nsj_t* nsj, pid_t pid, int ipc_fd) {
[[nodiscard]] static bool initParent(nsj_t* nsj, pid_t pid, int ipc_fd) {
if (!net::initParent(nsj, pid, ipc_fd)) {
LOG_W("Couldn't initialize net namespace for pid=%d", pid);
return false;
@@ -524,7 +524,7 @@ pid_t runChild(
close(parent_fd);
newProc(nsj, netfd, fd_in, fd_out, fd_err, child_fd);
util::sendMsg(child_fd, monitor::MSG_TAG_ERROR);
(void)util::sendMsg(child_fd, monitor::MSG_TAG_ERROR);
LOG_E("Launching child process failed");
pause();
_exit(0xff);
@@ -563,7 +563,7 @@ pid_t runChild(
* Returns child pid in the parent, 0 in the child, -1 on error.
* On success, *pidfd receives a file descriptor referring to the child.
*/
pid_t cloneProc(uint64_t flags, int exit_signal, int* pidfd) {
[[nodiscard]] pid_t cloneProc(uint64_t flags, int exit_signal, int* pidfd) {
exit_signal &= CSIGNAL;
if (flags & CLONE_VM) {
@@ -594,7 +594,7 @@ pid_t cloneProc(uint64_t flags, int exit_signal, int* pidfd) {
* Lightweight clone3 wrapper for internal helpers (mnt, pid) that need
* specific flags (e.g. CLONE_FS) but no pidfd tracking.
*/
pid_t cloneProcNoPidfd(uint64_t flags, int exit_signal) {
[[nodiscard]] pid_t cloneProcNoPidfd(uint64_t flags, int exit_signal) {
exit_signal &= CSIGNAL;
struct clone_args ca = {};
@@ -608,7 +608,7 @@ pid_t cloneProcNoPidfd(uint64_t flags, int exit_signal) {
return ret;
}
int systemExe(const std::vector<std::string>& args, char** env) {
[[nodiscard]] int systemExe(const std::vector<std::string>& args, char** env) {
bool exec_failed = false;
std::vector<const char*> argv;
@@ -634,7 +634,7 @@ int systemExe(const std::vector<std::string>& args, char** env) {
close(sv[0]);
execve(argv[0], (char* const*)argv.data(), (char* const*)env);
PLOG_W("execve('%s')", argv[0]);
util::writeToFd(sv[1], "A", 1);
(void)util::writeToFd(sv[1], "A", 1);
_exit(0);
}

View File

@@ -44,10 +44,10 @@ int reapAll(nsj_t* nsj);
int reapProc(nsj_t* nsj, pid_t pid, bool should_wait = false);
uint64_t checkTimeouts(
nsj_t* nsj, pid_t target_pid, time_t start_time, const std::string& remote_txt, int pidfd);
int systemExe(const std::vector<std::string>& args, char** env);
pid_t cloneProc(uint64_t flags, int exit_signal, int* pidfd);
[[nodiscard]] int systemExe(const std::vector<std::string>& args, char** env);
[[nodiscard]] pid_t cloneProc(uint64_t flags, int exit_signal, int* pidfd);
pid_t cloneProcNoPidfd(uint64_t flags, int exit_signal);
[[nodiscard]] pid_t cloneProcNoPidfd(uint64_t flags, int exit_signal);
} // namespace subproc

View File

@@ -142,7 +142,7 @@ static void unotifyCb(int fd, uint32_t events, void* /* data */) {
* Returns true if the fd was successfully absorbed by the loop. On failure,
* the fd is untouched and remains the caller's responsibility to close.
*/
bool start(nsj_t* nsj, int fd, int pidfd) {
[[nodiscard]] bool start(nsj_t* nsj, int fd, int pidfd) {
if (current_ctx.fd != -1) {
LOG_W("unotify::start called on already initialized context");
return false;

18
user.cc
View File

@@ -61,7 +61,7 @@ constexpr char kNewGidPath[] =
namespace user {
static bool setResGid(gid_t gid) {
[[nodiscard]] static bool setResGid(gid_t gid) {
LOG_D("setresgid(%d)", gid);
#if defined(__NR_setresgid32)
if (util::syscall(__NR_setresgid32, (uintptr_t)gid, (uintptr_t)gid, (uintptr_t)gid) == -1) {
@@ -77,7 +77,7 @@ static bool setResGid(gid_t gid) {
return true;
}
static bool setResUid(uid_t uid) {
[[nodiscard]] static bool setResUid(uid_t uid) {
LOG_D("setresuid(%d)", uid);
#if defined(__NR_setresuid32)
if (util::syscall(__NR_setresuid32, (uintptr_t)uid, (uintptr_t)uid, (uintptr_t)uid) == -1) {
@@ -93,7 +93,7 @@ static bool setResUid(uid_t uid) {
return true;
}
static bool hasGidMapSelf(nsj_t* nsj) {
[[nodiscard]] static bool hasGidMapSelf(nsj_t* nsj) {
for (const auto& gid : nsj->gids) {
if (!gid.is_newidmap) {
return true;
@@ -102,7 +102,7 @@ static bool hasGidMapSelf(nsj_t* nsj) {
return false;
}
static bool setGroupsDeny(nsj_t* nsj, pid_t pid) {
[[nodiscard]] static bool setGroupsDeny(nsj_t* nsj, pid_t pid) {
/*
* No need to write 'deny' to /proc/pid/setgroups if our euid==0, as writing to
* uid_map/gid_map will succeed anyway
@@ -120,7 +120,7 @@ static bool setGroupsDeny(nsj_t* nsj, pid_t pid) {
return true;
}
static bool uidMapSelf(nsj_t* nsj, pid_t pid) {
[[nodiscard]] static bool uidMapSelf(nsj_t* nsj, pid_t pid) {
std::string map;
for (const auto& uid : nsj->uids) {
if (uid.is_newidmap) {
@@ -147,7 +147,7 @@ static bool uidMapSelf(nsj_t* nsj, pid_t pid) {
return true;
}
static bool gidMapSelf(nsj_t* nsj, pid_t pid) {
[[nodiscard]] static bool gidMapSelf(nsj_t* nsj, pid_t pid) {
std::string map;
for (const auto& gid : nsj->gids) {
if (gid.is_newidmap) {
@@ -175,7 +175,7 @@ static bool gidMapSelf(nsj_t* nsj, pid_t pid) {
}
/* Use newgidmap for writing the gid map */
static bool gidMapExternal(nsj_t* nsj, pid_t pid) {
[[nodiscard]] static bool gidMapExternal(nsj_t* nsj, pid_t pid) {
bool use = false;
std::vector<std::string> argv = {kNewGidPath, std::to_string(pid)};
@@ -201,7 +201,7 @@ static bool gidMapExternal(nsj_t* nsj, pid_t pid) {
}
/* Use newuidmap for writing the uid map */
static bool uidMapExternal(nsj_t* nsj, pid_t pid) {
[[nodiscard]] static bool uidMapExternal(nsj_t* nsj, pid_t pid) {
bool use = false;
std::vector<std::string> argv = {kNewUidPath, std::to_string(pid)};
@@ -226,7 +226,7 @@ static bool uidMapExternal(nsj_t* nsj, pid_t pid) {
return true;
}
static bool uidGidMap(nsj_t* nsj, pid_t pid) {
[[nodiscard]] static bool uidGidMap(nsj_t* nsj, pid_t pid) {
RETURN_ON_FAILURE(gidMapSelf(nsj, pid));
RETURN_ON_FAILURE(gidMapExternal(nsj, pid));
RETURN_ON_FAILURE(uidMapSelf(nsj, pid));

2
user.h
View File

@@ -32,7 +32,7 @@ namespace user {
bool initNsFromParent(nsj_t* nsj, pid_t pid);
bool initNs(nsj_t* nsj);
bool parseId(nsj_t* nsj, const std::string& i_id, const std::string& o_id, size_t cnt, bool is_gid,
[[nodiscard]] bool parseId(nsj_t* nsj, const std::string& i_id, const std::string& o_id, size_t cnt, bool is_gid,
bool is_newidmap);
} // namespace user

20
util.cc
View File

@@ -53,7 +53,7 @@
namespace util {
ssize_t readFromFd(int fd, void* buf, size_t len) {
[[nodiscard]] ssize_t readFromFd(int fd, void* buf, size_t len) {
uint8_t* charbuf = (uint8_t*)buf;
size_t readSz = 0;
@@ -70,7 +70,7 @@ ssize_t readFromFd(int fd, void* buf, size_t len) {
return readSz;
}
ssize_t readFromFile(const char* fname, void* buf, size_t len) {
[[nodiscard]] ssize_t readFromFile(const char* fname, void* buf, size_t len) {
int fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
if (fd == -1) {
LOG_E("open(%s, O_RDONLY|O_CLOEXEC)", QC(fname));
@@ -81,7 +81,7 @@ ssize_t readFromFile(const char* fname, void* buf, size_t len) {
return ret;
}
bool writeToFd(int fd, const void* buf, size_t len) {
[[nodiscard]] bool writeToFd(int fd, const void* buf, size_t len) {
const uint8_t* charbuf = (const uint8_t*)buf;
size_t writtenSz = 0;
@@ -95,7 +95,7 @@ bool writeToFd(int fd, const void* buf, size_t len) {
return true;
}
bool sendMsg(int sock, uint32_t msg_val, int fd) {
[[nodiscard]] bool sendMsg(int sock, uint32_t msg_val, int fd) {
struct msghdr msg = {};
struct iovec io = {
.iov_base = &msg_val,
@@ -122,7 +122,7 @@ bool sendMsg(int sock, uint32_t msg_val, int fd) {
return (TEMP_FAILURE_RETRY(sendmsg(sock, &msg, 0)) == sizeof(msg_val));
}
bool recvMsg(int sock, uint32_t* msg_val, int* fd) {
[[nodiscard]] bool recvMsg(int sock, uint32_t* msg_val, int* fd) {
struct msghdr msg = {};
uint32_t local_msg = 0;
struct iovec io = {
@@ -165,7 +165,7 @@ bool recvMsg(int sock, uint32_t* msg_val, int* fd) {
return true;
}
bool readFromFileToStr(const char* fname, std::string* str) {
[[nodiscard]] bool readFromFileToStr(const char* fname, std::string* str) {
int fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
if (fd == -1) {
PLOG_W("Couldn't open file %s", QC(fname));
@@ -191,7 +191,7 @@ bool readFromFileToStr(const char* fname, std::string* str) {
return true;
}
bool writeBufToFile(
[[nodiscard]] bool writeBufToFile(
const char* filename, const void* buf, size_t len, int open_flags, bool log_errors) {
int fd;
TEMP_FAILURE_RETRY(fd = open(filename, open_flags | O_CLOEXEC, 0644));
@@ -220,7 +220,7 @@ bool writeBufToFile(
return true;
}
bool createDirRecursively(const char* dir) {
[[nodiscard]] bool createDirRecursively(const char* dir) {
if (dir[0] != '/') {
LOG_W("The directory path must start with '/': '%s' provided", dir);
return false;
@@ -499,7 +499,7 @@ long getrlimit(int res, struct rlimit64* curlim) {
return util::syscall(__NR_prlimit64, 0, res, (uintptr_t)nullptr, (uintptr_t)curlim);
}
bool makeRangeCOE(unsigned int first, unsigned int last) {
[[nodiscard]] bool makeRangeCOE(unsigned int first, unsigned int last) {
if (util::syscall(__NR_close_range, first, last, CLOSE_RANGE_CLOEXEC) == -1) {
if (errno != ENOSYS) {
PLOG_E("close_range(first=%u, last=%u, CLOSE_RANGE_CLOEXEC)", first, last);
@@ -554,7 +554,7 @@ void detachFromTTY(void) {
LOG_D("Successfully detached from controlling terminal via TIOCNOTTY");
}
bool setNonBlock(int fd) {
[[nodiscard]] bool setNonBlock(int fd) {
int fl = fcntl(fd, F_GETFL, 0);
if (fl == -1 || fcntl(fd, F_SETFL, fl | O_NONBLOCK) == -1) {
PLOG_W("fcntl(fd=%d, O_NONBLOCK)", fd);

20
util.h
View File

@@ -47,16 +47,16 @@
namespace util {
ssize_t readFromFd(int fd, void* buf, size_t len);
ssize_t readFromFile(const char* fname, void* buf, size_t len);
bool readFromFileToStr(const char* fname, std::string* str);
bool writeToFd(int fd, const void* buf, size_t len);
[[nodiscard]] ssize_t readFromFd(int fd, void* buf, size_t len);
[[nodiscard]] ssize_t readFromFile(const char* fname, void* buf, size_t len);
[[nodiscard]] bool readFromFileToStr(const char* fname, std::string* str);
[[nodiscard]] bool writeToFd(int fd, const void* buf, size_t len);
bool sendMsg(int sock, uint32_t msg, int fd = -1);
bool recvMsg(int sock, uint32_t* msg, int* fd = nullptr);
bool writeBufToFile(
[[nodiscard]] bool sendMsg(int sock, uint32_t msg, int fd = -1);
[[nodiscard]] bool recvMsg(int sock, uint32_t* msg, int* fd = nullptr);
[[nodiscard]] bool writeBufToFile(
const char* filename, const void* buf, size_t len, int open_flags, bool log_errors = true);
bool createDirRecursively(const char* dir);
[[nodiscard]] bool createDirRecursively(const char* dir);
std::string* StrAppend(std::string* str, const char* format, ...)
__attribute__((format(printf, 2, 3)));
std::string StrPrintf(const char* format, ...) __attribute__((format(printf, 1, 2)));
@@ -73,11 +73,11 @@ long syscall(long sysno, uintptr_t a0 = 0, uintptr_t a1 = 0, uintptr_t a2 = 0, u
uintptr_t a4 = 0, uintptr_t a5 = 0);
long setrlimit(int res, const struct rlimit64& newlim);
long getrlimit(int res, struct rlimit64* curlim);
bool makeRangeCOE(unsigned int first, unsigned int last);
[[nodiscard]] bool makeRangeCOE(unsigned int first, unsigned int last);
const char* stripLeadingSlashes(const char* path);
bool kernelVersionAtLeast(int major, int minor, int patch);
void detachFromTTY(void);
bool setNonBlock(int fd);
[[nodiscard]] bool setNonBlock(int fd);
bool setNoDelay(int fd);
/*