forked from WHC/Hermit
v0.7.1: allow network inside the run_shell sandbox
Landlock no longer handles TCP, the Seatbelt profile drops (deny network*), and the seccomp filter stops refusing IPv4/IPv6 sockets. Sandboxed commands run without asking in auto mode on every backend (Low-IL no longer asks for network commands), and connection errors are not treated as sandbox blocks.
This commit is contained in:
+6
-12
@@ -259,7 +259,7 @@ static void put_safety(cst_buf_t *b, const cst_agent_config_t *cfg) {
|
||||
"the task requires it. Never print secrets or API keys.\n");
|
||||
if (tool_on(cfg, "run_shell"))
|
||||
cst_buf_puts(b, "- run_shell may run in a sandbox (writes only inside the "
|
||||
"workspace and temp dir, no network). If a command is "
|
||||
"workspace and temp dir; the network works). If a command is "
|
||||
"blocked the user is asked whether to rerun it outside; "
|
||||
"do not try to work around the sandbox.\n");
|
||||
}
|
||||
@@ -827,13 +827,9 @@ static void sandbox_escalate(turn_t *t, cst_tool_ctx_t *ctx,
|
||||
}
|
||||
if (ans == CST_PERM_DENY) {
|
||||
const char *note =
|
||||
cst_sandbox_probe() == CST_SANDBOX_LOWIL
|
||||
? "\n[cst: blocked by the sandbox (writes are limited to the "
|
||||
"workspace and temp dir); the user did not allow running it "
|
||||
"outside]\n"
|
||||
: "\n[cst: blocked by the sandbox (writes are limited to "
|
||||
"the workspace and temp dir, no network); the user did "
|
||||
"not allow running it outside]\n";
|
||||
"\n[cst: blocked by the sandbox (writes are limited to the "
|
||||
"workspace and temp dir); the user did not allow running it "
|
||||
"outside]\n";
|
||||
cst_buf_t b = {0};
|
||||
if (tr->out)
|
||||
cst_buf_append(&b, tr->out, tr->out_len);
|
||||
@@ -989,11 +985,9 @@ static void exec_begin(turn_t *t, pcall_t *pc, exec_t *x) {
|
||||
if (def->perm == CST_TP_WRITE) {
|
||||
ask = 0;
|
||||
} else if (def->perm == CST_TP_SHELL) {
|
||||
int sb = cst_sandbox_probe();
|
||||
if (sb != CST_SANDBOX_NONE) {
|
||||
if (cst_sandbox_probe() != CST_SANDBOX_NONE) {
|
||||
ctx->sandbox = 1;
|
||||
/* the Low-IL sandbox does not stop network access */
|
||||
ask = sb == CST_SANDBOX_LOWIL && cmd && cst_shell_uses_network(cmd);
|
||||
ask = 0;
|
||||
} else if (cmd && cst_shell_is_safe(cmd)) {
|
||||
ask = 0;
|
||||
}
|
||||
|
||||
+5
-19
@@ -86,8 +86,6 @@ static int g_abi;
|
||||
#define LL_FS_MAKE_SYM (1ULL << 12)
|
||||
#define LL_FS_REFER (1ULL << 13) /* ABI 2 */
|
||||
#define LL_FS_TRUNCATE (1ULL << 14) /* ABI 3 */
|
||||
#define LL_NET_BIND_TCP (1ULL << 0) /* ABI 4 */
|
||||
#define LL_NET_CONNECT_TCP (1ULL << 1) /* ABI 4 */
|
||||
|
||||
struct ll_ruleset_attr {
|
||||
uint64_t handled_access_fs;
|
||||
@@ -137,9 +135,7 @@ static int ll_prepare(const char *ws, const char *tmp, cst_sandbox_plan_t *p) {
|
||||
int abi = g_abi;
|
||||
struct ll_ruleset_attr attr;
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.handled_access_fs = ll_write_rights(abi);
|
||||
if (abi >= 4)
|
||||
attr.handled_access_net = LL_NET_BIND_TCP | LL_NET_CONNECT_TCP;
|
||||
attr.handled_access_fs = ll_write_rights(abi); /* network stays open */
|
||||
int fd = (int)syscall(__NR_landlock_create_ruleset, &attr, sizeof(attr), 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
@@ -193,8 +189,7 @@ static int sb_prepare(const char *ws, const char *tmp, cst_sandbox_plan_t *p) {
|
||||
"(version 1)(allow default)(deny file-write*)"
|
||||
"(allow file-write* (subpath \"%s\") (subpath \"%s\") "
|
||||
"(literal \"/dev/null\") (literal \"/dev/tty\") "
|
||||
"(literal \"/dev/dtracehelper\"))"
|
||||
"(deny network*)",
|
||||
"(literal \"/dev/dtracehelper\"))",
|
||||
qws, qtmp);
|
||||
return 0;
|
||||
}
|
||||
@@ -290,9 +285,8 @@ static const int SC_NOTIFY[] = {
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Foreign ABIs are refused, IPv4/IPv6 sockets fail with EACCES, opens
|
||||
* without write flags pass untouched, write-type calls go to the
|
||||
* supervisor. */
|
||||
/* Foreign ABIs are refused, opens without write flags pass untouched,
|
||||
* write-type calls go to the supervisor. */
|
||||
static void sc_build(sc_prog_t *p) {
|
||||
p->n = 0;
|
||||
SC_LD(offsetof(struct seccomp_data, arch));
|
||||
@@ -303,12 +297,6 @@ static void sc_build(sc_prog_t *p) {
|
||||
sc_emit(p, BPF_JMP | BPF_JGE | BPF_K, 0, 1, 0x40000000U); /* x32 */
|
||||
SC_RET(SECCOMP_RET_ERRNO | EPERM);
|
||||
#endif
|
||||
SC_JEQ(__NR_socket, 0, 5);
|
||||
SC_LD(SC_ARG(0));
|
||||
SC_JEQ(AF_INET, 2, 0);
|
||||
SC_JEQ(AF_INET6, 1, 0);
|
||||
SC_RET(SECCOMP_RET_ALLOW);
|
||||
SC_RET(SECCOMP_RET_ERRNO | EACCES);
|
||||
SC_JEQ(__NR_io_uring_setup, 0, 1);
|
||||
SC_RET(SECCOMP_RET_ERRNO | EPERM);
|
||||
SC_JEQ(__NR_openat, 0, 4);
|
||||
@@ -1446,9 +1434,7 @@ int cst_sandbox_blocked(const char *out, size_t n, int exit_code) {
|
||||
static const char *const SIGNS[] = {
|
||||
"Permission denied", "Read-only file system", "Operation not permitted",
|
||||
"EACCES", "EPERM", "EROFS",
|
||||
"[cst: sandbox", "Network is unreachable",
|
||||
/* curl when the socket itself was refused (seccomp) */
|
||||
"Could not connect to server", "Failed to connect to",
|
||||
"[cst: sandbox",
|
||||
/* localized strerror(EACCES/EPERM/EROFS) */
|
||||
"权限不够", "不允许的操作", "只读文件系统", "權限不足",
|
||||
"拒絕不符權限的操作", "許可がありません", "Keine Berechtigung",
|
||||
|
||||
Reference in New Issue
Block a user