Skip to content

Commit d1aeeb4

Browse files
tht2005kmk3
andauthored
feature: add arg-max-count and arg-max-len options to firejail.config (#6878)
Replace the hardcoded `MAX_ARGS` and `MAX_ARG_LEN` limits with new global configuration options, `arg-max-count` and `arg-max-len`, which limit the maximum number of command-line arguments and the maximum length of each argument (respectively). Closes #4633. Co-authored-by: Kelvin M. Klann <[email protected]>
1 parent b613c30 commit d1aeeb4

File tree

5 files changed

+70
-11
lines changed

5 files changed

+70
-11
lines changed

etc/firejail.config

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,18 @@
99
# Enable AppArmor functionality, default enabled.
1010
# apparmor yes
1111

12+
# Maximum number of arguments in the command line.
13+
# Example: `firejail --foo /usr/bin/bar baz` has 4 arguments.
14+
# This limit is intended to make stack smashing harder (see
15+
# https://github.com/netblue30/firejail/issues/4633).
16+
# arg-max-count 128
17+
18+
# Maximum length of each argument in the command line.
19+
# Example: `--foo=bar` has a length of 9.
20+
# This limit is intended to make stack smashing harder (see
21+
# https://github.com/netblue30/firejail/issues/4633).
22+
# arg-max-len 4096
23+
1224
# Number of ARP probes sent when assigning an IP address for --net option,
1325
# default 2. This is a partial implementation of RFC 5227. A 0.5 seconds
1426
# timeout is implemented for each probe. Increase this number to 4 if your

src/firejail/checkcfg.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "../include/syscall.h"
2323
#include <sys/stat.h>
2424
#include <linux/loop.h>
25+
#include <limits.h>
2526

2627
#define MAX_READ 8192 // line buffer for profile files
2728

@@ -33,6 +34,8 @@ char *xpra_extra_params = "";
3334
char *xvfb_screen = "800x600x24";
3435
char *xvfb_extra_params = "";
3536
char *netfilter_default = NULL;
37+
int arg_max_count = 128; // maximum number of command arguments (argc)
38+
unsigned long arg_max_len = 4096; // --foobar=PATH
3639
unsigned long join_timeout = 5000000; // microseconds
3740
char *config_seccomp_error_action_str = "EPERM";
3841
char *config_seccomp_filter_add = NULL;
@@ -216,6 +219,26 @@ int checkcfg(int val) {
216219
else
217220
goto errout;
218221
}
222+
223+
// arg max count
224+
else if (strncmp(ptr, "arg-max-count ", 14) == 0) {
225+
long tmp = strtol(ptr + 14, NULL, 10);
226+
if (tmp < 0 || tmp >= INT_MAX) {
227+
if (arg_debug) {
228+
printf("arg-max-count out of range: %ld, using %d\n",
229+
tmp, INT_MAX);
230+
}
231+
arg_max_count = INT_MAX;
232+
}
233+
else {
234+
arg_max_count = (int)tmp;
235+
}
236+
}
237+
238+
// arg max len
239+
else if (strncmp(ptr, "arg-max-len ", 12) == 0)
240+
arg_max_len = strtoul(ptr + 12, NULL, 10);
241+
219242
// arp probes
220243
else if (strncmp(ptr, "arp-probes ", 11) == 0) {
221244
int arp_probes = atoi(ptr + 11);

src/firejail/firejail.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -397,9 +397,7 @@ extern pid_t sandbox_pid;
397397
extern mode_t orig_umask;
398398
extern unsigned long long start_timestamp;
399399

400-
#define MAX_ARGS 128 // maximum number of command arguments (argc)
401-
#define MAX_ARG_LEN (PATH_MAX + 32) // --foobar=PATH
402-
extern char *fullargv[MAX_ARGS];
400+
extern char **fullargv;
403401
extern int fullargc;
404402

405403
// main.c
@@ -879,6 +877,8 @@ extern char *xpra_extra_params;
879877
extern char *xvfb_screen;
880878
extern char *xvfb_extra_params;
881879
extern char *netfilter_default;
880+
extern int arg_max_count;
881+
extern unsigned long arg_max_len;
882882
extern unsigned long join_timeout;
883883
extern char *config_seccomp_error_action_str;
884884
extern char *config_seccomp_filter_add;

src/firejail/main.c

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ int arg_restrict_namespaces = 0;
176176
int parent_to_child_fds[2];
177177
int child_to_parent_fds[2];
178178

179-
char *fullargv[MAX_ARGS]; // expanded argv for restricted shell
179+
char **fullargv = NULL; // expanded argv for restricted shell
180180
int fullargc = 0;
181181
static pid_t child = 0;
182182
pid_t sandbox_pid;
@@ -1075,20 +1075,24 @@ int main(int argc, char **argv, char **envp) {
10751075
// check standard streams before opening any file
10761076
fix_std_streams();
10771077

1078+
// initialize values from firejail.config (needed for arg_max_count)
1079+
checkcfg(0);
1080+
10781081
// argument count should be larger than 0
10791082
if (argc == 0 || !argv || strlen(argv[0]) == 0) {
10801083
fprintf(stderr, "Error: argv is invalid\n");
10811084
exit(1);
1082-
} else if (argc >= MAX_ARGS) {
1083-
fprintf(stderr, "Error: too many arguments: argc (%d) >= MAX_ARGS (%d)\n", argc, MAX_ARGS);
1085+
} else if (argc >= arg_max_count) {
1086+
fprintf(stderr, "Error: too many arguments: argc (%d) >= arg-max-count (%d)\n",
1087+
argc, arg_max_count);
10841088
exit(1);
10851089
}
10861090

10871091
// sanity check for arguments
10881092
for (i = 0; i < argc; i++) {
1089-
if (strlen(argv[i]) >= MAX_ARG_LEN) {
1090-
fprintf(stderr, "Error: too long argument: argv[%d] len (%zu) >= MAX_ARG_LEN (%d): %s\n",
1091-
i, strlen(argv[i]), MAX_ARG_LEN, argv[i]);
1093+
if (strlen(argv[i]) >= arg_max_len) {
1094+
fprintf(stderr, "Error: too long argument: argv[%d] len (%zu) >= arg-max-len (%lu): '%s'\n",
1095+
i, strlen(argv[i]), arg_max_len, argv[i]);
10921096
exit(1);
10931097
}
10941098
}
@@ -1247,9 +1251,28 @@ int main(int argc, char **argv, char **envp) {
12471251
}
12481252
EUID_ASSERT();
12491253

1254+
#ifndef ARGC_MAX_RESTRICTED_SHELL
1255+
#define ARGC_MAX_RESTRICTED_SHELL 4096
1256+
#endif
12501257
// is this a login shell, or a command passed by sshd,
12511258
// insert command line options from /etc/firejail/login.users
12521259
if (*argv[0] == '-' || parent_sshd) {
1260+
// use a sane size for allocation
1261+
int fullargv_sz = arg_max_count;
1262+
if (fullargv_sz > ARGC_MAX_RESTRICTED_SHELL) {
1263+
if (arg_debug) {
1264+
printf("arg-max-count %d > %d, allocating %d elements for fullargv\n",
1265+
arg_max_count, ARGC_MAX_RESTRICTED_SHELL,
1266+
ARGC_MAX_RESTRICTED_SHELL);
1267+
}
1268+
fullargv_sz = ARGC_MAX_RESTRICTED_SHELL;
1269+
}
1270+
1271+
fullargv = malloc(fullargv_sz * sizeof(char *));
1272+
if (!fullargv)
1273+
errExit("malloc");
1274+
memset(fullargv, 0, fullargv_sz * sizeof(char *));
1275+
12531276
if (argc == 1)
12541277
login_shell = 1;
12551278
fullargc = restricted_shell(cfg.username);
@@ -1270,7 +1293,7 @@ int main(int argc, char **argv, char **envp) {
12701293
#endif
12711294

12721295
int j;
1273-
for (i = 1, j = fullargc; i < argc && j < MAX_ARGS; i++, j++, fullargc++)
1296+
for (i = 1, j = fullargc; i < argc && j < fullargv_sz; i++, j++, fullargc++)
12741297
fullargv[j] = argv[i];
12751298

12761299
// replace argc/argv with fullargc/fullargv

src/firejail/restricted_shell.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,11 @@ int restricted_shell(const char *user) {
8686
if (fnmatch(usr, user, 0) == 0) {
8787
// process program arguments
8888

89+
assert(fullargv != NULL);
8990
fullargv[0] = "firejail";
9091
int i;
9192
ptr = args;
92-
for (i = 1; i < MAX_ARGS; i++) {
93+
for (i = 1; i < arg_max_count; i++) {
9394
// skip blanks
9495
while (*ptr == ' ' || *ptr == '\t')
9596
ptr++;

0 commit comments

Comments
 (0)