Commit Graph

2365 Commits

Author SHA1 Message Date
Qualys Security Advisory
5d7e7cf468 0055-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.

---------------------------- adapted for newlib branch
. logic is quite different with 'stacks' vs. 'proc_t'
. a commented out 'debug' line was no longer present

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:45:38 +10:00
Qualys Security Advisory
67c1ec4685 0054-ps/output.c: Fix outbuf overflows in pr_args() etc.
Because there is usually less than OUTBUF_SIZE available at endp.

---------------------------- adapted for newlib branch
. logic is quite different with 'stacks' vs. 'proc_t'
. ps no longer deals with the library 'FILL...' flags

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:45:38 +10:00
Qualys Security Advisory
43c4d553e6 0053-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-06-09 21:45:38 +10:00
Qualys Security Advisory
9caf95c0bd 0052-ps/output.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).

---------------------------- adapted for newlib branch
. formerly applied to proc/escape.c
. function was moved to ps/output.c

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:45:38 +10:00
Qualys Security Advisory
f44fe715bd 0048-ps/output.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).

---------------------------- adapted for newlib branch
. formerly applied to proc/escape.c
. function was moved to ps/output.c

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:45:38 +10:00
Jim Warner
f0b245c794 ps: move other initialization code after setREL macros
While the previous patch concerned an essential change
to avoid dereferencing those NULL pointers, this patch
could be considered optional. For consistency, it just
puts all initialization logic after the setREL macros.

[ plus along the way some inter-function spacing was ]
[ standardized with just a single blank line between ]

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:45:38 +10:00
Jim Warner
26ab9ae143 ps: ensure functions not called prior to setREL macros
Under newlib design, ps must loop though all potential
print functions so as to gather the appropriate enum's
while establishing the 'relative' equivalent. The keys
to the setREL/chkREL macros are a NULL 'outbuf' param.

It's imperative that no other functions be called with
that NULL value. Unfortunately, several instances were
found where this was violated. They are now corrected!

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:45:38 +10:00
Jim Warner
292a4dd6fa ps/output.c: eliminate one irritating compiler warning
Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:45:38 +10:00
Jim Warner
4d9e4ac4f6 top: provide the means to exploit a 256-color terminal
With the Qualys security audit, we began to harden our
treatment of the top rcfile. In particular, the values
read were checked so as to prevent some malicious user
from editing it in order to achieve an evil objective.

However when it came to colors I was surprised to find
that at least one user edited the rcfile for 256-color
support. Unfortunately, our new checks prevented this.

So this commit will provide the means to exploit those
extra colors with no need to manually edit the rcfile.

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

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:20 +10:00
Jim Warner
fa96f3e5dc top: sanitized some potentially corrupt 'Inspect' data
This guards against rcfile 'Inspect' entries which may
include non-printable characters. While this shouldn't
occur, we have no real control over those crazy users.

[ and, while such data can't be used maliciously, it ]
[ does adversely impact such a user's screen display ]

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:20 +10:00
Jim Warner
34feb6183a top: prevent buffer overruns in 'inspection_utility()'
For our master branch, a Qualys patch referenced below
was reverted as being unwarranted. That original patch
was not applied in this branch so there was no revert.

However, there was 1 specific problem their patch had,
in fact, prevented. Thus, this patch now addresses it.

Reference(s):
. original qualys patch
0109-top-Protect-scat-from-buffer-overflows.patch

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:20 +10:00
Jim Warner
59c8c1c86c top: add another field sanity check in 'config_file()'
Until the Qualys security audit I had never considered
it a possibility that some malicious person might edit
the top config file to achieve some nefarious results.

And while the Qualys approach tended to concentrate on
the symptoms from such an effort, subsequent revisions
more properly concentrated on startup and that rcfile.

This commit completes those efforts with 1 more field.

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:20 +10:00
Jim Warner
8ce5f080a2 top: don't mess with groff line length in man document
I've long since forgotten why the attempt to influence
groff line lengths was made. However, I did receive an
email regarding problems formatting postscript output.

Hopefully this patch will eliminate any such problems.

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:20 +10:00
Jim Warner
50ae55ef10 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-06-09 21:35:20 +10:00
Jim Warner
80e210d38e library: refactor #define FALSE_THREADS dependent code
This refactor was done in response to the Qualys patch
referenced below, which deals with some 'readeither()'
flaws under the master branch. Under our newlib branch
those flaws mostly disappear since the function is now
private. But without a redesign the #define is broken.

When the #define FALSE_THREADS is active, some special
strings showing "[ duplicate ENUM ]" will appear under
each child thread. Note that the real reason for those
appearing isn't being exercised, only their mechanics.

In reality, they only show when a user duplicates such
enums in a results stack & only 1 instance can own it.

Reference(s):
. original qualys patch
0084-proc-readproc.c-Work-around-a-design-flaw-in-readeit.patch
. QUICK_THREADS became FALSE_THREADS
commit c546d9dd44

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:20 +10:00
Jim Warner
97d078a9af library: clean up some miscellaneous compiler warnings
Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:20 +10:00
Jim Warner
2c6a480cc8 top: just respond to the increased command name length
The command name for running tasks is displayed by top
in a variable length field, so the increase from 16 to
64 bytes was not a problem. However, there's one place
where top is sensitive to length - insp_view_choice().

So, this patch just bumps a buffer used to display it.

Reference(s):
. master branch increase to 64
commit 2cfdbbe897

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:20 +10:00
Jim Warner
a24b369132 top: eliminate a couple of warnings of -Wunused-result
Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:20 +10:00
Jim Warner
c314f9f953 top: ensure sane rcfile values for the remaining stuff
This will protect some remaining rcfile variables from
a possible manual editing of top's configuration file.

[ and correct two #error related boo-boos introduced ]
[ with the system default rcfile in the commit shown ]

Reference(s):
. introduced /etc/topdefaultrc
commit 55a42ae040

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:20 +10:00
Jim Warner
bd7e1fb343 top: Prevent out-of-bounds writes in PUFF(). __Tweaked
This commit moves some overhead to the Batch mode path
where it's needed. And given the new 'else if' test we
can delete some now redundant logic in the other path.

Reference(s):
. original qualys patch
0117-top-Prevent-out-of-bounds-writes-in-PUFF.patch

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:20 +10:00
Jim Warner
8b94d11585 top: address 'show_special()' o-o-b read/write concern
This patch addresses a potential (but unlikely) buffer
overflow by reducing, if necessary, a memcpy length by
3 bytes to provide for an eol '\0' and 2 unused buffer
positions which also might receive the '\0' character.

[ note to future analysis tool: just because you see ]
[ binary data being manipulated in the routine, that ]
[ doesn't mean such function was passed binary data! ]

Reference(s):
. original qualys patch
0116-top-Fix-out-of-bounds-read-write-in-show_special.patch

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:20 +10:00
Jim Warner
085351a0ee top: prevent buffer overflow potential in all routines
Whereas an original patch (referenced below) addressed
some symptoms related to manually edited config files,
this solution deals with root causes. And it goes much
beyond any single top field by protecting all of top's
fields. Henceforth, a duplicated field is not allowed.

Reference(s):
. original qualys patch
0114-top-Prevent-buffer-overflow-in-calibrate_fields.patch

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:20 +10:00
Jim Warner
ffee26c370 top: check sortindx risk exposure (not treat symptoms)
Rather than validate the window's 'sortindx' each time
it was referenced (as was done in the patch below), we
now ensure the validity just once when the config file
is read. Thereafter, a running top will police bounds.

Reference(s):
. original qualys patch
0102-top-Check-sortindx.patch

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:20 +10:00
Jim Warner
e691cbaef4 top: other graph_cpus, graph_mems, and summ_mscale fix
This patch replaces an original patch referenced below
(omitted under this branch). We now validate variables
'graph_cpus', 'graph_mems' and 'summ_mscale' just once
at startup. Thereafter, top enforces the proper range.

[ we afford the same treatment to that 'task_mscale' ]
[ variable, which was ignored in the original patch. ]

Reference(s):
. original qualys patch
0099-top-Check-graph_cpus-graph_mems-and-summ_mscale.patch

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:20 +10:00
Jim Warner
4550e60144 top: Do not default to the cwd in configs_r... Tweaked
While it's only documented (so far) in commit text and
an occasional email I've tried to maintain some coding
standards primarily for reference/navigation purposes.
They also served, I felt, as useful mental challenges.

Someday I will get around to formerly documenting them
but in the meantime here are the ones for this commit:

. functions are grouped into logical (i hope) sections
. functions & sections are ordered to avoid prototypes
. function names are alphabetical within every section
. all functions & sections must be referenced in top.h

This patch just attempts to honor the above standards,
while also covering this new behavior in the man page.

[ please note that the net result of these 2 patches ]
[ is simply to avoid pathname truncations should our ]
[ limit of 1024 be exceeded. they do not have a role ]
[ in solving the 'local privilege escalation' issue. ]

[ and we can never prevent a user from setting their ]
[ HOME var to a directory writable by some attacker! ]

[ the only real protection for that CVE-2018-1122 is ]
[ those soon to be enhanced rcfile integrity checks, ]
[ achieved through several of the following patches. ]

Reference(s):
. original qualys patch
0097-top-Do-not-default-to-the-cwd-in-configs_read.patch

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:20 +10:00
Jim Warner
e051535686 library: adapt for increased (cmd) program name length
In the new library 'cmd' is dynamically allocated just
like 'cmdline'. This will align us with the ref below.

Reference(s):
. master branch increase to 64
commit 2cfdbbe897

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:20 +10:00
Qualys Security Advisory
d099d0e5a1 0117-top: Prevent out-of-bounds writes in PUFF().
This patch prevents three problems:

1/ Because snprintf() returns "the number of characters (excluding the
terminating null byte) which would have been written to the final string
if enough space had been available", _eol may point past the end of _str
and write out-of-bounds (in Batch mode).

2/ _eol is never checked against _str, so "while (*(--_eol) == ' ');"
may point _eol below _str and write out-of-bounds (in Batch mode).

3/ Sanity-check Pseudo_row to protect the strcpy().
2018-06-09 21:35:20 +10:00
Qualys Security Advisory
2ba9c569e5 0115-top: Harden calibrate_fields().
- Make sure i is at least 1 before "i - 1" and "--i".

- Initialize endpflg (to 0, as it was originally, since it is static)
  before the "for" loop (the "break" may leave endpflg uninitialized,
  for example).
2018-06-09 21:35:20 +10:00
Qualys Security Advisory
6024543e79 0113-top: Impose a minimum on Screen_cols.
The safety of the critical function task_show() depends on the sanity of
Screen_cols. Just copy the tests on w_cols to Screen_cols (from the same
function adj_geometry()).
2018-06-09 21:35:20 +10:00
Qualys Security Advisory
74e9d0afe1 0112-top: Prevent integer overflow in adj_geometry(). 2018-06-09 21:35:20 +10:00
Qualys Security Advisory
34b08eb8ac 0111-top: Limit Width_mode to SCREENMAX.
adj_geometry() limits to SCREENMAX too, but belt and suspenders, and
might as well tell the user about it.
2018-06-09 21:35:20 +10:00
Qualys Security Advisory
2fabc50998 0110-top: Prevent integer overflows in config_file() and other_selection(). 2018-06-09 21:35:20 +10:00
Qualys Security Advisory
e1f419737f 0108-top: Always exit from sig_abexit().
The default action for SIGURG is to ignore the signal, for example.
This is very similar to the patch "ps/display.c: Always exit from
signal_handler()."
2018-06-09 21:35:20 +10:00
Qualys Security Advisory
022cda9599 0107-top: Initialize struct sigaction in before(). 2018-06-09 21:35:20 +10:00
Qualys Security Advisory
2c461c8b05 0106-top: Fix snprintf() call in capsmk().
Replace "snprintf(msg, sizeof(pmt)" with "snprintf(msg, sizeof(msg)".
Luckily sizeof(pmt) == sizeof(msg), but fix it anyway.
2018-06-09 21:35:20 +10:00
Qualys Security Advisory
f02fff62fb 0104-top: Initialize cp in task_show().
Found no problematic case at the moment, but this is a cheap
just-in-case.
2018-06-09 21:35:20 +10:00
Qualys Security Advisory
8b29093481 0103-top: Protect macro parameters.
---------------------------- adapted for newlib branch
. the 'isBUSY' macro is quite different under newlib

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:19 +10:00
Qualys Security Advisory
9cb8bee6a1 0101-top: Check width and col.
Otherwise they may lead to out-of-bounds writes (snprintf() returns the
number of characters which would have been written if enough space had
been available).

Also, make sure buf is null-terminated after COLPLUSCH has been written.
2018-06-09 21:35:19 +10:00
Qualys Security Advisory
766e31a2c3 0100-top: Check Rc.fixed_widest.
Otherwise it leads to crashes (for example, setting it to 2147483600 in
the configuration file segfaults top).
2018-06-09 21:35:19 +10:00
Qualys Security Advisory
0b0356de5c 0098-top: Check i when setting Curwin in config_file().
Otherwise it leads to out-of-bounds reads (and maybe writes).
2018-06-09 21:35:19 +10:00
Qualys Security Advisory
7c92bff183 0097-top: Do not default to the cwd in configs_read().
If the HOME environment variable is not set, or not absolute, use the
home directory returned by getpwuid(getuid()), if set and absolute
(instead of the cwd "."); otherwise, set p_home to NULL.

To keep the changes to a minimum, we rely on POSIX, which requires that
fopen() fails with ENOENT if the pathname (Rc_name) is an empty string.
This integrates well into the existing code, and makes write_rcfile()
work without a change.

Also, it makes the code in configs_read() easier to follow: only set and
use p_home if safe, and only set Rc_name if safe (in all the other cases
it is the empty string, and the fopen() calls fail). Plus, check for
snprintf() truncation (and if it happens, reset Rc_name to the empty
string).

Important note: top.1 should probably be updated, since it mentions the
fallback to the current working directory.
2018-06-09 21:35:19 +10:00
Qualys Security Advisory
54f02b7e11 0096-top: Fix double-fclose() in configs_read().
It happens only if RCFILE_NOERR is defined (it is not, by default).
2018-06-09 21:35:19 +10:00
Qualys Security Advisory
48d118b81b 0084-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).

---------------------------- adapted for newlib branch
. adapted via 'patch' (rejected due to 'xcalloc' ref)
. with loss of both readproctab functions, most no longer true

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:19 +10:00
Qualys Security Advisory
b9a9fd4c74 0082-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().

---------------------------- adapted for newlib branch
. now 'cmd' is also dynamic
. just synchronized with those freed in free_acquired
. QUICK_THREADS is now FALSE_THREADS, serving different purpose
. entire patch will be effectively reverted with upcoming refactor

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:19 +10:00
Qualys Security Advisory
990ea89ae9 0080-proc/readproc.c: Harden openproc().
Replace xmalloc() with xcalloc().

---------------------------- adapted for newlib branch
. trade xcalloc() for calloc()
. thus we must account for potential ENOMEM

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:19 +10:00
Qualys Security Advisory
c03e52786d 0078-proc/readproc.c: Harden simple_nextpid().
Replace memcpy+strcpy with snprintf.

---------------------------- adapted for newlib branch
. adapted via 'patch' (without rejections)

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:19 +10:00
Qualys Security Advisory
ed463c7d88 0077-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.

---------------------------- adapted for newlib branch
. adapted via 'patch (without rejections)

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:19 +10:00
Qualys Security Advisory
1052091107 0076-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.

---------------------------- adapted for newlib branch
. logic is now in pids.c
. former 'vectorize_this_str' is now 'pids_vectorize_this'

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:19 +10:00
Qualys Security Advisory
d9c0a3e36f 0075-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.

---------------------------- adapted for newlib branch
. adapted via 'patch (without rejections)

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:19 +10:00
Qualys Security Advisory
86d3d37406 0074-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).

---------------------------- adapted for newlib branch
. there were many formatting differences
. i introduced several myself (especially comments)
. stdlib 'realloc' used, not that home grown xrealloc
. stdlib 'realloc' required extra 'return NULL' statement

Signed-off-by: Jim Warner <james.warner@comcast.net>
2018-06-09 21:35:19 +10:00