Commit Graph

2047 Commits

Author SHA1 Message Date
Qualys Security Advisory
6939463606 proc/readproc.c: Harden vectorize_this_str().
This detects an integer overflow of "strlen + 1", prevents an integer
overflow of "tot + adj + (2 * pSZ)", and avoids calling snprintf with a
string longer than INT_MAX. Truncate rather than fail, since the callers
do not expect a failure of this function.
2018-05-19 07:32:22 +10:00
Qualys Security Advisory
39dcf47bc8 proc/readproc.c: Harden read_unvectored().
1/ Prevent an out-of-bounds write if sz is 0.

2/ Limit sz to INT_MAX, because the return value is an int, not an
unsigned int (and because if INT_MAX is equal to SSIZE_MAX, man 2 read
says "If count is greater than SSIZE_MAX, the result is unspecified.")

3/ Always null-terminate dst (unless sz is 0), because a return value of
0 because of an open() error (for example) is indistinguishable from a
return value of 0 because of an empty file.

4/ Use an unsigned int for i (just like n), not an int.

5/ Check for snprintf() truncation.
2018-05-19 07:32:22 +10:00
Qualys Security Advisory
36c350f07c proc/readproc.c: Fix bugs and overflows in file2strvec().
Note: this is by far the most important and complex patch of the whole
series, please review it carefully; thank you very much!

For this patch, we decided to keep the original function's design and
skeleton, to avoid regressions and behavior changes, while fixing the
various bugs and overflows. And like the "Harden file2str()" patch, this
patch does not fail when about to overflow, but truncates instead: there
is information available about this process, so return it to the caller;
also, we used INT_MAX as a limit, but a lower limit could be used.

The easy changes:

- Replace sprintf() with snprintf() (and check for truncation).

- Replace "if (n == 0 && rbuf == 0)" with "if (n <= 0 && tot <= 0)" and
  do break instead of return: it simplifies the code (only one place to
  handle errors), and also guarantees that in the while loop either n or
  tot is > 0 (or both), even if n is reset to 0 when about to overflow.

- Remove the "if (n < 0)" block in the while loop: it is (and was) dead
  code, since we enter the while loop only if n >= 0.

- Rewrite the missing-null-terminator detection: in the original
  function, if the size of the file is a multiple of 2047, a null-
  terminator is appended even if the file is already null-terminated.

- Replace "if (n <= 0 && !end_of_file)" with "if (n < 0 || tot <= 0)":
  originally, it was equivalent to "if (n < 0)", but we added "tot <= 0"
  to handle the first break of the while loop, and to guarantee that in
  the rest of the function tot is > 0.

- Double-force ("belt and suspenders") the null-termination of rbuf:
  this is (and was) essential to the correctness of the function.

- Replace the final "while" loop with a "for" loop that behaves just
  like the preceding "for" loop: in the original function, this would
  lead to unexpected results (for example, if rbuf is |\0|A|\0|, this
  would return the array {"",NULL} but should return {"","A",NULL}; and
  if rbuf is |A|\0|B| (should never happen because rbuf should be null-
  terminated), this would make room for two pointers in ret, but would
  write three pointers to ret).

The hard changes:

- Prevent the integer overflow of tot in the while loop, but unlike
  file2str(), file2strvec() cannot let tot grow until it almost reaches
  INT_MAX, because it needs more space for the pointers: this is why we
  introduced ARG_LEN, which also guarantees that we can add "align" and
  a few sizeof(char*)s to tot without overflowing.

- Prevent the integer overflow of "tot + c + align": when INT_MAX is
  (almost) reached, we write the maximal safe amount of pointers to ret
  (ARG_LEN guarantees that there is always space for *ret = rbuf and the
  NULL terminator).
2018-05-19 07:32:22 +10:00
Qualys Security Advisory
ccf8de0874 proc/readproc.c: Harden file2str().
1/ Replace sprintf() with snprintf() (and check for truncation).

2/ Prevent an integer overflow of ub->siz. The "tot_read--" is needed to
avoid an off-by-one overflow in "ub->buf[tot_read] = '\0'". It is safe
to decrement tot_read here, because we know that tot_read is equal to
ub->siz (and ub->siz is very large).

We believe that truncation is a better option than failure (implementing
failure instead should be as easy as replacing the "tot_read--" with
"tot_read = 0").
2018-05-19 07:32:22 +10:00
Qualys Security Advisory
344f6d3c0e proc/readproc.c: Harden stat2proc().
1/ Use a "size_t num" instead of an "unsigned num" (also, do not store
the return value of sscanf() into num, it was unused anyway).

2/ Check the return value of strchr() and strrchr().

3/ Never jump over the terminating null byte with "S = tmp + 2".
2018-05-19 07:32:22 +10:00
Qualys Security Advisory
20269a4129 proc/readproc.c: Harden supgrps_from_supgids().
1/ Prevent an integer overflow of t.

2/ Avoid an infinite loop if s contains characters other than comma,
spaces, +, -, and digits.

3/ Handle all possible return values of snprintf().
2018-05-19 07:32:22 +10:00
Qualys Security Advisory
6fb2bbaa0d proc/readproc.c: Harden status2proc().
1/ Do not read past the terminating null byte when hashing the name.

2/ S[x] is used as an index, but S is "char *S" (signed) and hence may
index the array out-of-bounds. Bit-mask S[x] with 127 (the array has 128
entries).

3/ Use a size_t for j, not an int (strlen() returns a size_t).

Notes:

- These are (mostly) theoretical problems, because the contents of
  /proc/PID/status are (mostly) trusted.

- The "name" member of the status_table_struct has 8 bytes, and
  "RssShmem" occupies exactly 8 bytes, which means that "name" is not
  null-terminated. This is fine right now, because status2proc() uses
  memcmp(), not strcmp(), but it is worth mentioning.
2018-05-19 07:32:22 +10:00
Qualys Security Advisory
27e45cf43b proc/readproc.c: Fix the unhex() function.
This function is unused (SIGNAL_STRING is defined by default, and if it
is not, procps does not compile -- for example, there is no "outbuf" in
help_pr_sig()) but fix it anyway. There are two bugs:

- it accepts non-hexadecimal characters (anything >= 0x30);

- "(c - (c>0x57) ? 0x57 : 0x30)" is always equal to 0x57.
2018-05-19 07:32:22 +10:00
Qualys Security Advisory
920b0ada70 proc/sysinfo.c: Ensure null-termination in getstat().
There was a "buff[BUFFSIZE-1] = 0;" but there may be garbage between
what is read() (less than BUFFSIZE-1 bytes) and this null byte. Reuse
the construct from the preceding getrunners().
2018-05-19 07:32:22 +10:00
Qualys Security Advisory
015669383f ps/sortformat.c: Avoid "sep_loc + 1" when sep_loc is NULL. 2018-05-19 07:32:22 +10:00
Qualys Security Advisory
bb89dad867 ps/sortformat.c: Handle large width in aix_format_parse().
Unlikely to ever happen, since it would imply a very large string, but
better safe than sorry.
2018-05-19 07:32:22 +10:00
Qualys Security Advisory
cde22815af ps/sortformat.c: Catch negative width in format_parse().
The existing strspn() check guarantees that the string contains no '-'
but atoi() does not catch errors, especially not integer overflows.
2018-05-19 07:32:22 +10:00
Qualys Security Advisory
db00f54f4a ps/sortformat.c: Double-check chars in verify_short_sort().
To avoid an out-of-bounds access at checkoff[tmp]. The strspn() at the
beginning of the function protects against it already, but double-check
this in case of some future change.
2018-05-19 07:32:22 +10:00
Qualys Security Advisory
afca7eee75 ps/display.c: Fix "move process-only flags to the process".
Use "proc |= (task & PROC_ONLY)" not "proc |= (task &~ PROC_ONLY)".
2018-05-19 07:32:22 +10:00
Qualys Security Advisory
2e4a594221 ps/display.c: Always exit from signal_handler().
Right now, "we _exit() anyway" is not always true: for example, the
default action for SIGURG is to ignore the signal, which means that
"kill(getpid(), signo);" does not terminate the process. Call _exit()
explicitly, in this case (rather than exit(), because the terminating
kill() calls do not call the functions registered with atexit() either).
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
7dd7bdb09f ps/output.c: Always null-terminate outbuf in show_one_proc().
Before "strlen(outbuf)", if one of the pr_*() functions forgot to do it.
This prevents an out-of-bounds read in strlen(), and an out-of-bounds
write in "outbuf[sz] = '\n'". Another solution would be to replace
strlen() with strnlen(), but this is not used anywhere else in the
code-base and may not exist in all libc's.
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
db25d0375a ps/output.c: Protect outbuf in various pr_*() functions.
pr_bsdstart(): Replace "strcpy(outbuf," with "snprintf(outbuf, COLWID,"
(which is used in all surrounding functions). (side note: the fact that
many pr_*() functions simply return "snprintf(outbuf, COLWID," justifies
the "amount" checks added to show_one_proc() by the "ps/output.c:
Replace strcpy() with snprintf() in show_one_proc()." patch)

pr_stime(): Check the return value of strftime() (in case of an error,
"the contents of the array are undefined").

help_pr_sig(): Handle the "len < 8" case, otherwise "sig+len-8" may
point outside the sig string.

pr_context(): Handle the empty string case, or else "outbuf[len-1]"
points outside outbuf.
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
14e0247ea5 ps/output.c: Enforce a safe range for max_rightward.
Enforce a maximum max_rightward of OUTBUF_SIZE-1, because it is used in
constructs such as "snprintf(outbuf, max_rightward+1," (we could remove
the extra check at the beginning of forest_helper() now, but we decided
to leave it, as a precaution and reminder).

The minimum max_rightward check is not strictly needed, because it is
unsigned. However, we decided to add it anyway:

- most of the other variables are signed;

- make it visually clear that this case is properly handled;

- ideally, the minimum max_rightward should be 1, not 0 (to prevent
  integer overflows such as "max_rightward-1"), but this might change
  the behavior/output of ps, so we decided against it, for now.

Instead, we fixed the only function that overflows if max_rightward is
0. Also, enforce the same safe range for max_leftward, although it is
never used throughout the code-base.
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
1d9ddb615a ps/output.c: Replace strcpy() with snprintf() in show_one_proc().
This strcpy() should normally not overflow outbuf, but names can be
overridden (via -o). Also, check "amount" in all cases.
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
97408d8b10 ps/output.c: Remove the page_shift variable.
It is static and not used anywhere.
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
e66bf564f8 ps/output.c: Check return value of mmap() in init_output().
We decided not to check the return value of the mprotect() calls,
because they are not vital to the operation of ps.
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
bb9c217f29 ps/display.c: Harden show_tree().
1/ Do not go deeper than the size of forest_prefix[], to prevent a
buffer overflow (sizeof(forest_prefix) is roughly 128K, but the maximum
/proc/sys/kernel/pid_max is 4M). (actually, we go deeper, but we stop
adding bytes to forest_prefix[])

2/ Always null-terminate forest_prefix[] at the current level.
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
136e372495 ps/output.c: Fix outbuf overflows in pr_args() etc.
Because there is usually less than OUTBUF_SIZE available at endp.
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
d31f5eb545 ps/output.c: Harden forest_helper().
This patch solves several problems:

1/ Limit the number of characters written (to outbuf) to OUTBUF_SIZE-1
(-1 for the null-terminator).

2/ Always null-terminate outbuf at q.

3/ Move the "rightward" checks *before* the strcpy() calls.

4/ Avoid an integer overflow in these checks (e.g., rightward-4).
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
62f19dc5df proc/escape.c: Handle negative snprintf() return value.
May happen if strlen(src) > INT_MAX for example. This patch prevents
escaped_copy() from increasing maxroom and returning -1 (= number of
bytes consumed in dst).
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
7efa102248 proc/escape.c: Prevent buffer overflows in escape_command().
This solves several problems:

1/ outbuf[1] was written to, but not outbuf[0], which was left
uninitialized (well, SECURE_ESCAPE_ARGS() already fixes this, but do it
explicitly as well); we know it is safe to write one byte to outbuf,
because SECURE_ESCAPE_ARGS() guarantees it.

2/ If bytes was 1, the write to outbuf[1] was an off-by-one overflow.

3/ Do not call escape_str() with a 0 bufsize if bytes == overhead.

4/ Prevent various buffer overflows if bytes <= overhead.
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
37ce162604 proc/escape.c: Prevent integer overflows in escape_str_utf8().
Simply rearrange the old comparisons. The new comparisons are safe,
because we know from previous checks that:

1/ wlen > 0

2/ my_cells < *maxcells (also: my_cells >= 0 and *maxcells > 0)

3/ len > 1

4/ my_bytes+1 < bufsize (also: my_bytes >= 0 and bufsize > 0)
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
8d359b04ab proc/escape.c: Handle negative wcwidth() return value.
This should never happen, because wcwidth() is called only if iswprint()
returns nonzero. But belt-and-suspenders, and make it visually clear
(very important for the next patch).
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
47303a3592 proc/escape.c: Make sure all escape*() arguments are safe.
The SECURE_ESCAPE_ARGS() macro solves several potential problems
(although we found no problematic calls to the escape*() functions in
procps's code-base, but had to thoroughly review every call; and this is
library code):

1/ off-by-one overflows if the size of the destination buffer is 0;

2/ buffer overflows if this size (or "maxroom") is negative;

3/ integer overflows (for example, "*maxcells+1");

4/ always null-terminate the destination buffer (unless its size is 0).
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
00ab5f0b32 proc/whattime.c: Always initialize buf.
In the human_readable case; otherwise the strcat() that follows may
append bytes to the previous contents of buf.

Also, slightly enlarge buf, as it was a bit too tight.

Could also replace all sprintf()s with snprintf()s, but all the calls
here output a limited number of characters, so they should be safe.
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
7382ac88d5 proc/slab.c: Initialize struct slab_info in get_slabnode().
Especially its "next" member: this is what caused the crash in "slabtop:
Reset slab_list if get_slabinfo() fails." (if parse_slabinfo*() fails in
sscanf(), for example, then curr is set to NULL but it is already linked
into the "list" and its "next" member was never initialized).
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
a33be33885 proc/sysinfo.c: Fix off-by-one in get_pid_digits().
At "pidbuf[rc] = '\0';" if "rc = read()" returns "sizeof pidbuf"
(unlikely to ever happen, but still).
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
8136a7a664 proc/sysinfo.c: Prevent integer overflow of realloc() size. 2018-05-19 07:32:21 +10:00
Qualys Security Advisory
5b6ab39c6d proc/slab.c: Check correct number of items after sscanf(). 2018-05-19 07:32:21 +10:00
Qualys Security Advisory
3ccc6ed262 proc/slab.h: Fix off-by-one overflow in sscanf().
In proc/slab.c, functions parse_slabinfo20() and parse_slabinfo11(),
sscanf() might overflow curr->name, because "String input conversions
store a terminating null byte ('\0') to mark the end of the input; the
maximum field width does not include this terminator."

Add one byte to name[] for this terminator.
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
bf12b14db9 proc/sig.c: Harden print_given_signals().
And signal_name_to_number().
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
3244e7ddb0 proc/devname.c: Never write more than "chop" (part 2).
"chop" is the maximum offset where the null-byte should be written;
respect this even if about to write just one (non-null) character.
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
6b7ceb36a4 proc/devname.c: Never write more than "chop" characters.
This should be guaranteed by "tmp[chop] = '\0';" and "if(!c) break;" but
this patch adds a very easy belt-and-suspenders check.
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
730bdc33e7 proc/devname.c: Prevent off-by-one overflow in dev_to_tty(). 2018-05-19 07:32:21 +10:00
Qualys Security Advisory
9f59bd5c52 proc/devname.c: Use snprintf() in link_name().
Found no problematic use case at the moment, but better safe than sorry.
Also, return an error on snprintf() or readlink() truncation.
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
59666e6255 proc/version.h: Protect parameter in LINUX_VERSION() macro.
Just in case (no problematic use case at the moment).
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
f1077b7a55 proc/alloc.*: Use size_t, not unsigned int.
Otherwise this can truncate sizes on 64-bit platforms, and is one of the
reasons the integer overflows in file2strvec() are exploitable at all.
Also: catch potential integer overflow in xstrdup() (should never
happen, but better safe than sorry), and use memcpy() instead of
strcpy() (faster).

Warnings:

- in glibc, realloc(ptr, 0) is equivalent to free(ptr), but not here,
  because of the ++size;

- here, xstrdup() can return NULL (if str is NULL), which goes against
  the idea of the xalloc wrappers.

We were tempted to call exit() or xerrx() in those cases, but decided
against it, because it might break things in unexpected places; TODO?
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
98b79d1ef1 proc/alloc.c: Use vfprintf(), not fprintf().
This can disclose information from the stack, but is unlikely to have a
security impact in the context of the procps utilities:

user@debian:~$ w 2>&1 | xxd
00000000: a03c 79b7 1420 6661 696c 6564 2074 6f20  .<y.. failed to
00000010: 616c 6c6f 6361 7465 2033 3232 3137 3439  allocate 3221749
00000020: 3738 3020 6279 7465 7320 6f66 206d 656d  780 bytes of mem
00000030: 6f72 79                                  ory
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
7941bb512a proc/readproc.c: Add checks to get_ns_name() and get_ns_id(). 2018-05-19 07:32:21 +10:00
Qualys Security Advisory
3ce9f837a3 proc/sig.c: Fix the strtosig() function.
Do not memleak "copy" in case of an error.

Do not use "sizeof(converted)" in snprintf(), since "converted" is a
"char *" (luckily, 8 >= sizeof(char *)). Also, remove "sizeof(char)"
which is guaranteed to be 1 by the C standard, and replace 8 with 12,
which is enough to hold any stringified int and does not consume more
memory (in both cases, the glibc malloc()ates a minimum-sized chunk).
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
7367c4b1fd skill: Do not scan past the null-terminator in check_proc(). 2018-05-19 07:32:21 +10:00
Qualys Security Advisory
a9ee0bf622 skill: Check return value of str*chr() in check_proc(). 2018-05-19 07:32:21 +10:00
Qualys Security Advisory
52673d2fc7 skill: Properly null-terminate buf in check_proc().
Right now, if read() returns less than 127 bytes (the most likely case),
the end of the "string" buf will contain garbage from the stack, because
buf is always null-terminated at a fixed offset 127. This is especially
bad because the next operation is a strrchr().

Also, make sure that the whole /proc/PID/stat file is read, otherwise
its parsing may be unsafe (the strrchr() may point into user-controlled
data, comm). This should never happen with the current file format (comm
is very short), but be safe, just in case.
2018-05-19 07:32:21 +10:00
Qualys Security Advisory
37547e9f5f skill: Check the return value of fstat(). 2018-05-19 07:32:21 +10:00
Qualys Security Advisory
858df7cc89 skill: Prevent multiple overflows in ENLIST().
First problem: saved_argc was used to calculate the size of the array,
but saved_argc was never initialized. This triggers an immediate heap-
based buffer overflow:

$ skill -c0 -c0 -c0 -c0
Segmentation fault (core dumped)

Second problem: saved_argc was not the upper bound anyway, because one
argument can ENLIST() several times (for example, in parse_namespaces())
and overflow the array as well.

Third problem: integer overflow of the size of the array.
2018-05-19 07:32:21 +10:00