From 0000eddb1a08029166d801f012a118ddfd19830a Mon Sep 17 00:00:00 2001 From: ArBin Date: Fri, 24 Apr 2026 03:07:31 +0800 Subject: [PATCH] Make shadow limit configurable with bounds Address the inherent 256MB capacity limitation on shadow FDs - CLI Configurability: Introduced the --shadow-limit option. The default remains 256MB to preserve existing behavior, but users can now raise it for specific workloads. - Host OOM Prevention: Enforced a hard upper bound (MAX_SHADOW_LIMIT = 512MB). Inputs exceeding this bound are automatically clamped to 512MB. - Type Safety for Parsing: Migrated the internal limit representation to uint64_t to prevent integer wraparound and overflow when handling custom CLI inputs. - Input Validation: Clamp negative inputs to MAX_SHADOW_LIMIT, and reject invalid or >64-bit strings with an error. Change-Id: I814b9edb6b17b0cf3762cc95938410ecbb577f8c --- include/kbox/cli.h | 3 +++ src/cli.c | 15 +++++++++++++++ src/image.c | 3 +++ src/shadow-fd.c | 13 ++++++++++++- src/shadow-fd.h | 4 +++- 5 files changed, 36 insertions(+), 2 deletions(-) diff --git a/include/kbox/cli.h b/include/kbox/cli.h index 2ea3430..c0a3b14 100644 --- a/include/kbox/cli.h +++ b/include/kbox/cli.h @@ -4,6 +4,7 @@ #define KBOX_CLI_H #include +#include #include "kbox/mount.h" /* CLI argument structures and parsing. */ @@ -45,6 +46,8 @@ struct kbox_image_args { bool sqpoll; /* --sqpoll: busy-poll service thread */ const char *const *extra_args; /* remaining args after -- */ int extra_argc; /* count of extra_args */ + uint64_t shadow_limit; /* --shadow-limit BYTES: max size for shadow FDs + (default: 256MB) */ }; /* Parse command-line arguments. diff --git a/src/cli.c b/src/cli.c index 19dc9cc..c9d213a 100644 --- a/src/cli.c +++ b/src/cli.c @@ -21,6 +21,7 @@ enum { OPT_SYSCALL_MODE, OPT_TRACE_FORMAT, OPT_SQPOLL, + OPT_SHADOW_LIMIT, OPT_HELP, }; @@ -46,6 +47,7 @@ static const struct option longopts[] = { {"syscall-mode", required_argument, NULL, OPT_SYSCALL_MODE}, {"sqpoll", no_argument, NULL, OPT_SQPOLL}, {"trace-format", required_argument, NULL, OPT_TRACE_FORMAT}, + {"shadow-limit", required_argument, NULL, OPT_SHADOW_LIMIT}, {"help", no_argument, NULL, OPT_HELP}, {NULL, 0, NULL, 0}, }; @@ -85,6 +87,8 @@ void kbox_usage(const char *argv0) " --web-bind ADDR Bind address for web (default: " "127.0.0.1)\n" " --trace-format FMT Trace output format (json)\n" + " --shadow-limit BYTES Max size for shadow FDs (default: " + "256MB)\n" " -h, --help Show this help\n", argv0); } @@ -259,6 +263,17 @@ int kbox_parse_args(int argc, char *argv[], struct kbox_image_args *img) return -1; } break; + case OPT_SHADOW_LIMIT: { + char *end; + errno = 0; + unsigned long long v = strtoull(optarg, &end, 10); + if (*end != '\0' || errno != 0) { + fprintf(stderr, "invalid shadow limit: %s\n", optarg); + return -1; + } + img->shadow_limit = (uint64_t) v; + break; + } case 'h': case OPT_HELP: kbox_usage(argv[0]); diff --git a/src/image.c b/src/image.c index 94160d9..8b0975d 100644 --- a/src/image.c +++ b/src/image.c @@ -828,6 +828,9 @@ int kbox_run_image(const struct kbox_image_args *args) if (!root_path) return -1; + if (args->shadow_limit > 0) + kbox_shadow_set_limit(args->shadow_limit); + fs_type = args->fs_type ? args->fs_type : "ext4"; work_dir = args->work_dir ? args->work_dir : "/"; command = args->command ? args->command : "/bin/sh"; diff --git a/src/shadow-fd.c b/src/shadow-fd.c index 2ccf374..6d8d054 100644 --- a/src/shadow-fd.c +++ b/src/shadow-fd.c @@ -40,6 +40,8 @@ /* Read chunk size: 128 KB, matches KBOX_IO_CHUNK_LEN. */ #define SHADOW_CHUNK_LEN (128 * 1024) +static uint64_t current_shadow_limit = DEFAULT_SHADOW_LIMIT; + int kbox_shadow_create(const struct kbox_sysnrs *s, long lkl_fd) { /* Use kbox_lkl_stat (generic-arch layout) instead of struct stat @@ -57,7 +59,7 @@ int kbox_shadow_create(const struct kbox_sysnrs *s, long lkl_fd) if (!S_ISREG(kst.st_mode)) return -ENODEV; - if (kst.st_size > KBOX_SHADOW_MAX_SIZE) + if ((uint64_t) kst.st_size > current_shadow_limit) return -EFBIG; int memfd = memfd_create("kbox-shadow", MFD_CLOEXEC | MFD_ALLOW_SEALING); @@ -127,3 +129,12 @@ int kbox_shadow_seal(int memfd) return fcntl(memfd, F_ADD_SEALS, F_SEAL_WRITE | F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL); } + +void kbox_shadow_set_limit(uint64_t limit) +{ + if (limit > MAX_SHADOW_LIMIT) { + current_shadow_limit = MAX_SHADOW_LIMIT; + } else if (limit > 0) { + current_shadow_limit = limit; + } +} \ No newline at end of file diff --git a/src/shadow-fd.h b/src/shadow-fd.h index 51342bd..9e78779 100644 --- a/src/shadow-fd.h +++ b/src/shadow-fd.h @@ -4,8 +4,10 @@ struct kbox_sysnrs; -#define KBOX_SHADOW_MAX_SIZE (256L * 1024 * 1024) +#define DEFAULT_SHADOW_LIMIT (256ULL * 1024 * 1024) +#define MAX_SHADOW_LIMIT (512ULL * 1024 * 1024) +void kbox_shadow_set_limit(uint64_t limit); int kbox_shadow_create(const struct kbox_sysnrs *s, long lkl_fd); int kbox_shadow_seal(int memfd);