Skip to content

rule.h: fix initialization failure for libstdcxx#13

Open
aokblast wants to merge 1 commit into
masterfrom
rule/fix_seccomp
Open

rule.h: fix initialization failure for libstdcxx#13
aokblast wants to merge 1 commit into
masterfrom
rule/fix_seccomp

Conversation

@aokblast

Copy link
Copy Markdown
Contributor

The libstdcxx uses TCGETS to get the current setting of terminal. This system call requires ioctl permission in seccomp. However, allowing all ioctl is so dangerous that can break the sandbox. Therefore, we use BPF to allow TCGETS only.

The libstdcxx uses TCGETS to get the current setting of terminal.
This system call requires ioctl permission in seccomp. However, allowing
all ioctl is so dangerous that can break the sandbox. Therefore, we use
BPF to allow TCGETS only.
@aokblast

Copy link
Copy Markdown
Contributor Author

@uier uier requested a review from Copilot October 25, 2025 15:43

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds BPF filtering to securely allow only the TCGETS ioctl operation, which is required by libstdcxx for terminal initialization, while maintaining sandbox security by preventing unrestricted ioctl access.

Key Changes:

  • Introduces a new install_seccomp() function that uses BPF to filter ioctl syscalls, allowing only TCGETS
  • Adds ioctl, getrandom, and futex to the syscall whitelist to support libstdcxx initialization

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread rule.h
Comment on lines +12 to +18
int install_seccomp() {
struct sock_filter filter[] = {
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr)),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_ioctl, 1, 0),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),

BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[1])),

Copilot AI Oct 25, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BPF filter checks args[1] (second argument) for the TCGETS value, but ioctl's request code is in args[1] as a 64-bit value on 64-bit systems. This should check args[1] as the lower 32 bits, but the current code loads a 32-bit word which may not correctly match the ioctl request on all architectures. Consider using the architecture-appropriate offset or verifying this works correctly on your target platform.

Suggested change
int install_seccomp() {
struct sock_filter filter[] = {
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr)),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_ioctl, 1, 0),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[1])),
// Macro to get the offset of the lower 32 bits of args[1] in struct seccomp_data
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define ARGS1_LO_OFFSET (offsetof(struct seccomp_data, args[1]))
#else
#define ARGS1_LO_OFFSET (offsetof(struct seccomp_data, args[1]) + 4)
#endif
int install_seccomp() {
struct sock_filter filter[] = {
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr)),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_ioctl, 1, 0),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, ARGS1_LO_OFFSET),

Copilot uses AI. Check for mistakes.
Comment thread rule.h
int c_cpp_rules(char *target, bool allow_write_file)
{
scmp_filter_ctx ctx;
install_seccomp();

Copilot AI Oct 25, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return value of install_seccomp() is not checked. If the seccomp installation fails (returns -1), the function continues to set up additional seccomp rules via seccomp_init(), which could lead to an incomplete or inconsistent security policy. Should check the return value and handle failure appropriately.

Suggested change
install_seccomp();
if (install_seccomp() != 0)
{
return LOAD_SECCOMP_FAILED;
}

Copilot uses AI. Check for mistakes.
Comment thread rule.h
Comment on lines +14 to +22
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr)),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_ioctl, 1, 0),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),

BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[1])),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, TCGETS, 0, 1),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),

BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),

Copilot AI Oct 25, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BPF logic is inverted: if the syscall is NOT ioctl (jump is taken when comparison fails), it proceeds to line 16 which allows it. If it IS ioctl (no jump), it falls through to check args[1]. This means all non-ioctl syscalls are allowed, which contradicts the intended behavior of a restrictive seccomp filter. The jump offsets should be adjusted to properly filter ioctl while denying other syscalls.

Suggested change
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr)),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_ioctl, 1, 0),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[1])),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, TCGETS, 0, 1),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
// Load syscall number
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr)),
// If syscall == __NR_ioctl, jump to check args[1] (next instruction); else, kill
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_ioctl, 0, 1),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
// Load args[1] (the request argument to ioctl)
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[1])),
// If args[1] == TCGETS, allow; else, kill
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, TCGETS, 0, 1),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),

Copilot uses AI. Check for mistakes.
Comment thread rule.h
SCMP_SYS(newfstatat), SCMP_SYS(set_tid_address),
SCMP_SYS(set_robust_list), SCMP_SYS(rseq),
SCMP_SYS(prlimit64)};
SCMP_SYS(prlimit64), SCMP_SYS(getrandom), SCMP_SYS(futex), SCMP_SYS(ioctl)};

Copilot AI Oct 25, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding SCMP_SYS(ioctl) to the whitelist contradicts the PR's stated goal of restricting ioctl access to only TCGETS. This allows all ioctl operations through the libseccomp layer, effectively bypassing the BPF filter installed by install_seccomp(). If both filters are active, the behavior depends on their interaction order, which may not be what's intended.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants