This patch fixes an out of boundary write in cut: $ cut -c 2147483648 - Segmentation fault (core dumped)
The supplied number can be parsed by strtol, but the result is casted into a signed int, therefore turning negative. Afterwards, it is used as an offset into a char array to write data at the given position. This leads to the shown segmentation fault. I have changed the strtol call to strtonum, making sure that range specifications still work. Our cut regress tests pass. Also it has a nicer error message now, thanks to strtonum. While at it, I replaced a manual for-loop with memset. Index: usr.bin/cut/cut.c =================================================================== RCS file: /cvs/src/usr.bin/cut/cut.c,v retrieving revision 1.23 diff -u -p -u -p -r1.23 cut.c --- usr.bin/cut/cut.c 2 Dec 2015 00:56:46 -0000 1.23 +++ usr.bin/cut/cut.c 27 Mar 2018 11:24:31 -0000 @@ -154,11 +154,32 @@ int autostart, autostop, maxval; char positions[_POSIX2_LINE_MAX + 1]; +int +read_number(char **p) +{ + size_t pos; + int dash, n; + const char *errstr; + char *q; + + q = *p + strcspn(*p, "-"); + dash = *q == '-'; + *q = '\0'; + n = strtonum(*p, 1, _POSIX2_LINE_MAX, &errstr); + if (errstr != NULL) + errx(1, "[-bcf] list: %s %s (allowed 1-%d)", *p, errstr, + _POSIX2_LINE_MAX); + if (dash) + *q = '-'; + *p = q; + + return n; +} + void get_list(char *list) { int setautostart, start, stop; - char *pos; char *p; /* @@ -176,13 +197,15 @@ get_list(char *list) setautostart = 1; } if (isdigit((unsigned char)*p)) { - start = stop = strtol(p, &p, 10); + start = stop = read_number(&p); if (setautostart && start > autostart) autostart = start; } if (*p == '-') { - if (isdigit((unsigned char)p[1])) - stop = strtol(p + 1, &p, 10); + if (isdigit((unsigned char)p[1])) { + ++p; + stop = read_number(&p); + } if (*p == '-') { ++p; if (!autostop || autostop > stop) @@ -193,13 +216,10 @@ get_list(char *list) errx(1, "[-bcf] list: illegal list value"); if (!stop || !start) errx(1, "[-bcf] list: values may not include zero"); - if (stop > _POSIX2_LINE_MAX) - errx(1, "[-bcf] list: %d too large (max %d)", - stop, _POSIX2_LINE_MAX); if (maxval < stop) maxval = stop; - for (pos = positions + start; start++ <= stop; *pos++ = 1) - ; + if (start <= stop) + memset(positions + start, 1, stop - start + 1); } /* overlapping ranges */