Skip to content

Commit d4966c1

Browse files
chenyuan0001Kernel Patches Daemon
authored andcommitted
bpftool: Fix bypass of the batch line length check by comments
do_batch() strips trailing comments by truncating the line at '#' before checking whether fgets() filled the buffer. If a batch line longer than the buffer contains a '#' within the first sizeof(buf) - 1 bytes, the truncation makes strlen(buf) smaller and the line-length check is bypassed. The unread remainder of the line then stays in the file stream and is parsed and executed as a separate command on the next loop iteration. Continuation lines handled below are affected the same way: an overlong continuation line containing '#' bypasses the "command is too long" check, and its unread remainder is executed as a separate command. Detect the truncated read before stripping the comment, using memchr() to look for a newline (instead of strlen(), which is also fooled by an embedded NUL byte) and feof() to tell an overlong line apart from a final line without a trailing newline. A line that fills the buffer exactly (the byte after the read is a newline) is not treated as truncated, so valid maximal-length lines are no longer rejected. Use the result for the line-length checks, so overlong lines are rejected regardless of comments or NUL bytes. Fixes: 71bb428 ("tools: bpf: add bpftool") Signed-off-by: Yuan Chen <chenyuan@kylinos.cn>
1 parent 0210de9 commit d4966c1

1 file changed

Lines changed: 24 additions & 2 deletions

File tree

tools/bpf/bpftool/main.c

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,11 +367,27 @@ static int do_batch(int argc, char **argv)
367367
if (json_output)
368368
jsonw_start_array(json_wtr);
369369
while (fgets(buf, sizeof(buf), fp)) {
370+
bool truncated = !memchr(buf, '\n', sizeof(buf) - 1) && !feof(fp);
371+
372+
if (truncated) {
373+
/*
374+
* fgets() filled the buffer. If the very next byte is
375+
* a newline, the line fits the buffer exactly and is
376+
* not truncated.
377+
*/
378+
int c = fgetc(fp);
379+
380+
if (c == '\n')
381+
truncated = false;
382+
else if (c != EOF)
383+
ungetc(c, fp);
384+
}
385+
370386
cp = strchr(buf, '#');
371387
if (cp)
372388
*cp = '\0';
373389

374-
if (strlen(buf) == sizeof(buf) - 1) {
390+
if (truncated) {
375391
line_too_long = true;
376392
break;
377393
}
@@ -380,6 +396,8 @@ static int do_batch(int argc, char **argv)
380396
* with '\' in the batch file).
381397
*/
382398
while ((cp = strstr(buf, "\\\n")) != NULL) {
399+
bool cont_truncated;
400+
383401
if (!fgets(contline, sizeof(contline), fp) ||
384402
strlen(contline) == 0) {
385403
p_err("missing continuation line on command %u",
@@ -388,11 +406,15 @@ static int do_batch(int argc, char **argv)
388406
goto err_close;
389407
}
390408

409+
cont_truncated = !memchr(contline, '\n', sizeof(contline) - 1) &&
410+
!feof(fp);
411+
391412
cp = strchr(contline, '#');
392413
if (cp)
393414
*cp = '\0';
394415

395-
if (strlen(buf) + strlen(contline) + 1 > sizeof(buf)) {
416+
if (cont_truncated ||
417+
strlen(buf) + strlen(contline) + 1 > sizeof(buf)) {
396418
p_err("command %u is too long", lines);
397419
err = -1;
398420
goto err_close;

0 commit comments

Comments
 (0)