Commit Graph

422 Commits

Author SHA1 Message Date
Todd Lewis
401d587d2d fix uid/gid > 2^31 2021-10-25 19:38:10 -04:00
Issam E. Maghni
2763b9880a escape.c: Fix missing nl_langinfo on certain configs 2021-04-24 01:43:46 +00:00
Jim Warner
0d386260b4 library: let's make 'escaped_copy' multibyte aware too
This patch is intended to bring the master branch into
closer alignment with the newlib branch functionality.

The commit shown below replaced that 'escape_str' with
'escaped_copy' so that the ps program wouldn't execute
some code twice. However, it created a problem for the
top program when the UTF-8 encoding was not available.

Unlike ps who calls the escape functions directly, top
outputs those library provided strings unaltered. That
means there is no workaround (like LANG=) when such an
encoding was unavailable. This, in turn, can lead to a
corrupted display (especially with the linux console).

Now, when a UTF-8 encoding is not available, multibyte
chars are converted to '?', reducing display problems.

[ there's still a potential problem concerning 'cmd' ]
[ should program names contain multibyte characters. ]
[ unlike that newlib branch, this string is not ever ]
[ altered with the '?' char under the master branch. ]

Reference(s);
. Dec 2020, escaoed_copy repleced most escape_str
commit eea5626bb1

Signed-off-by: Jim Warner <james.warner@comcast.net>
2021-01-02 15:40:02 +11:00
Jim Warner
eea5626bb1 library: help ensure 'escape_str' isn't executed twice
Now that the ps program is using 'escape_str' for most
of the library's returned strings, this patch tries to
lessen the prospects of executing that function twice.

Our newlib branch has achieved such a goal through the
elimination of nearly all escape.c code. However, here
we avoid API change by trading some 'escape_str' calls
(with wide character overhead) for a slightly extended
'escaped_copy' call (which incurs no multibyte costs).

Note: until we migrate to the newlib version, there is
a remaining call to 'escape_str' which we can't avoid.
Such code involves the 'escape_command' function call.

[ As we prepare for this new (final?) release, there ]
[ were already internal library changes that require ]
[ a new 'revision'. This patch won't impact the API! ]

Signed-off-by: Jim Warner <james.warner@comcast.net>
2020-12-29 08:42:28 +11:00
Anton Blanchard
1b9ea61116 Increase BUFFSIZE to handle very large /proc/stat files
We read /proc/stat using a statically sized buffer. This was increased
to 64kB in 2005 via commit 777fcd3cf1 "/proc/stat for 1024 CPUs".

Unfortunately in 2020, 1024 CPUs is not enough for anyone. I have a
large machine where /proc/stat is 74kB, and vmstat gives incorrect
output.

Double the buffer to 128kB in the confidence that 2048 CPUs is actually
enough for anyone.

Signed-off-by: Anton Blanchard <anton@ozlabs.org>
2020-12-22 13:18:44 +11:00
Samanta Navarro
b0c8e3408b misc: fix typos in manual pages
Signed-off-by: Samanta Navarro <ferivoz@riseup.net>
2020-12-22 00:37:29 +00:00
Jim Warner
e319650278 misc: eliminate a couple of miscellaneous gcc warnings
This commit just addresses those warnings shown below.

Reference(s):
proc/sysinfo.c: In function `getrunners':
proc/sysinfo.c:491:26: warning: `%s' directive writing up to 255 bytes into a region of size 26 [-Wformat-overflow=]
  491 |     sprintf(tbuf, "/proc/%s/stat", ent->d_name);
      |                          ^~

pgrep.c: In function `select_procs':
pgrep.c:591:11: warning: suggest explicit braces to avoid ambiguous `else' [-Wdangling-else]
  591 |   else if (opt_older)
      |           ^

Signed-off-by: Jim Warner <james.warner@comcast.net>
2020-07-29 18:58:33 +10:00
Jim Warner
bb1a79f2c8 library: correct that 'escape_str_utf8' guy's behavior
Thanks to Konstantin for discovering 2 problems in the
issue referenced below. That 15+ year old logic went a
little too far overboard wrestling with a utf8 string.

Henceforth, we will not treat 'x9b' as special. And we
also will handle a 'combining acute accent' correctly.

Reference(s):
https://gitlab.com/procps-ng/procps/-/issues/176

Signed-off-by: Jim Warner <james.warner@comcast.net>
2020-06-23 19:05:03 +10:00
Dylan Swiggett
b52a267404 Fixes small bug in struct proc_t documentation.
From http://man7.org/linux/man-pages/man5/proc.5.html:

(22) starttime  %llu
                        The time the process started after system boot.  In
                        kernels before Linux 2.6, this value was expressed
                        in jiffies.  Since Linux 2.6, the value is expressed
                        in clock ticks (divide by sysconf(_SC_CLK_TCK)).
2020-05-11 17:39:47 +10:00
Jim Warner
8e0c33be46 library: adapted to the latest lxc conventions (again)
Well, shit! With release 4.0 on March 25th the lxc/lxd
folks have stuck it to us once again. They changed the
cgroup lxc prefix used to identify the container name.

Signed-off-by: Jim Warner <james.warner@comcast.net>
2020-04-20 22:05:34 +10:00
Jim Warner
2e7f38707a library: tweak that lxc container support a final time
Since the patch referenced below traded a compile-time
'sizeof' directive for a run-time 'strlen' call, there
is no need to declare lxc patterns as explicit arrays.

We'll also use the actual lxc patterns by omitting the
beginning slashes ('/') for both of those definitions.

And, looking to the future when most/all lxc users are
using the most recent lxc release, we will make things
slightly more efficient by reversing those two pattern
literals so the most recent pattern was checked first.

Of course, such a change only benefits tasks which are
running in a container. For the majority of processes,
both literals will be compared in that 'if' statement,
assuming the 'LXC' field is currently being displayed.

[ plus, a leftover parenthesis pair has been removed ]

Reference(s):
commit f67127e728

Signed-off-by: Jim Warner <james.warner@comcast.net>
2019-03-26 19:13:42 +11:00
Patrick Steinhardt
9b9aa9a6e9 docs: fix "delimeter" typo in fprocopen man page 2019-03-04 21:44:52 +11:00
Jim Warner
f67127e728 library: adapt readproc for the latest lxc conventions
The merge request shown below prompted (thankfully) an
examination of our lxc containers logic in readproc.c.

As it turns out, the lxc folks changed that eyecatcher
used to identify containers within a task cgroup file.

So this patch, with little extra cost, will enable the
libprocps lxc_containers() guy to handle both strings.

[ additionally, I was shocked to find lxc allows the ]
[ eyecatcher to be changed at ./configure time. such ]
[ a provision has always existed. unfortunately, the ]
[ changed value was only available to root, assuming ]
[ one wished to tackle that undocumented liblxc api. ]

Reference(s):
. what prompted lxc support reevaluation
https://gitlab.com/procps-ng/procps/merge_requests/82
. original lxc support introduced
commit 0557504f9c

Signed-off-by: Jim Warner <james.warner@comcast.net>
2019-01-22 22:46:53 +11:00
Jan Rybar
36e066df52 Possible segfault in file2strvec introduced by latest CVE fix
'rbuf' used before allocated.
Revealed by static analysis
2018-08-08 20:00:24 +10:00
Jim Warner
3352bddba5 library: tweak that change to 'supgrps_from_supgids()'
It's good that those Qualys folks were looking over my
shoulder. They suggested a change to that commit shown
below. This improvement was obviously a better choice.

Reference(s):
. original change
commit f9a8009e27

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-07 21:35:59 +10:00
Jim Warner
f9a8009e27 library: avoid problems involving 'supgid' mishandling
Following that patch referenced below, the top SUPGRPS
field would produce a segmentation fault and ps SUPGRP
would often show "(null)". Such problems resulted from
some faulty logic in the status2proc() routine dealing
with 'Groups' (supgid) which served as a source field.

For many processes the original code produced an empty
string which prevented conversion to the expected "-".
Moreover, prior to release 3.3.15 such an empty string
will become 0 after strtol() which pwcache_get_group()
translates to 'root' yielding very misleading results.

So, now we'll check for empty '/proc/#/status/Groups:'
fields & consistently provide a "-" value for callers.

[ we'll also protect against future problems in that ]
[ new qualys logic by always ensuring valid 'supgrp' ]
[ pointers - logic which revealed our original flaw! ]

Reference(s):
. original qualys patch
0071-proc-readproc.c-Harden-supgrps_from_supgids.patch

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-05-31 22:02:03 +10:00
Craig Small
2cfdbbe897 library: Increase comm length to 64
For many years, the comm length has been set to 16. Previously to that
it was 8. This means for things like kworkers they all have very cryptic
names. The kernel is now going to increase this size to 64, so the
procps library will follow this length increase.

System tools may also increase their default length to 64, or keep it at
16; there is only so much screen real estate.

References:
 https://lkml.org/lkml/2018/5/17/16
2018-05-19 08:04:19 +10:00
Qualys Security Advisory
14758ebc8f proc/readproc.c: Work around a design flaw in readeither().
readeither() caches (in new_p) a pointer to the proc_t of a task-group
leader, but readeither()'s callers can do pretty much anything with the
proc_t structure passed to and/or returned by this function. For
example, they can 1/ free it or 2/ recycle it (by passing it to
readeither() as x).

1/ leads to a use-after-free, and 2/ leads to unexpected behavior when
taskreader()/simple_readtask() is called with new_p equal to x (this is
not a theoretical flaw: 2/ happens in readproctab3() when want_task()
returns false and p is a group leader).

As a workaround, we keep a copy of new_p's first member (tid) in static
storage, and the next times we enter readeither() we check this "canary"
against the tid in new_p: if they differ, we reset new_p to NULL, which
forces the allocation of a new proc_t (the new "leader", or reference).

This always detects 2/ (because free_acquired(x,1) memsets x and hence
new_p); always detects 1/ if freed via free_acquired() and/or freeproc()
(very likely, otherwise memory may be leaked); probably detects 1/ even
if freed directly via free() (because the canary is the first member of
proc_t, likely to be overwritten by free()); but can not detect 1/ if
free() does not write to new_p's chunk at all.

Moreover, accessing new_p->tid to check the canary in case 1/ is itself
a use-after-free, so a better long-term solution should be implemented
at some point (we wanted to avoid intrusive and backward-incompatible
changes in this library function, hence this imperfect workaround).
2018-05-19 07:32:22 +10:00
Qualys Security Advisory
94eebb03b5 proc/readproc.c: Prevent integer overflows in readproctab*().
If an integer overflow is about to be reached, call xalloc_err_handler()
(since it would have been caught by calloc() or reallocarray()) and then
exit(): these integer overflows are far from reachable, with the current
PID_MAX_LIMIT (2^22), so if they are there is something very wrong going
on. Note: we check the n_*alloc variables against INT_MAX even when they
are size_t because they are later stored as int in a struct proc_data_t.
2018-05-19 07:32:22 +10:00
Qualys Security Advisory
a013f6e020 proc/readproc.c: Fix double-free()s in readtask().
If QUICK_THREADS is not defined (it is not by default, but most
distributions enable it) and task_dir_missing is true (only on very old
kernels), then readtask() forgets to reset some of the struct proc_t t's
members, which later results in double-free()s in free_acquired().

For now, we simply synchronized the list of members to be reset with the
list of members freed in free_acquired().
2018-05-19 07:32:22 +10:00
Qualys Security Advisory
1539c13507 proc/readproc.c: Fix use-after-free in readproctab2().
The memset() in the PROC_LOOSE_TASKS loop leaves a struct proc_t
uninitialized (the one at data+n_used), which leads to a use-after-free.

ps calls readproctab2(), but only if !TF_loose_tasks, and this U-A-F is
triggered only if PROC_LOOSE_TASKS, so there seems to be no vulnerable
call in the procps package itself (other users of the libprocps may be
vulnerable, though).
2018-05-19 07:32:22 +10:00
Qualys Security Advisory
a4d82a2c2c proc/readproc.c: Harden openproc().
Replace xmalloc() with xcalloc().
2018-05-19 07:32:22 +10:00
Qualys Security Advisory
19849a45e0 proc/readproc.c: Harden get_proc_stats().
Replace sprintf() with snprintf().
2018-05-19 07:32:22 +10:00
Qualys Security Advisory
1b8ec51013 proc/readproc.c: Harden simple_nextpid().
Replace memcpy+strcpy with snprintf.
2018-05-19 07:32:22 +10:00
Qualys Security Advisory
263c0ebdd8 proc/readproc.c: Harden fill_cgroup_cvt().
Check the return value of snprintf(), otherwise dst may point
out-of-bounds when it reaches the end of the dst_buffer (the snprintf()
always returns 1 in that case, even if there is not enough space left),
and vMAX becomes negative and is passed to snprintf() as a size_t.
2018-05-19 07:32:22 +10:00
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
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