CLD-404 Details

Other IDs this deficiency may be known by:

CVE ID CVE-2018-1123 (nvd) (mitre) (debian) (archlinux) (red hat) (suse) (ubuntu)
Other ID(s)

Basic Information:

Affected Package(s) procps-ng
Deficiency Type SECURITY
Date Created 2018-05-17 13:20:34
Date Last Modified 2018-05-17 17:44:46

Version Specific Information:

Cucumber 1.0 i686fixed in procps-ng-3.3.11-i686-2
Cucumber 1.0 x86_64fixed in procps-ng-3.3.11-x86_64-2 and procps-ng-lib_i686-3.3.11-lib_i686-2

Cucumber 1.1 i686 fixed in procps-ng-3.3.11-i686-2
Cucumber 1.1 x86_64 fixed in procps-ng-3.3.11-x86_64-2 and procps-ng-lib_i686-3.3.11-lib_i686-2

Details:

=================================== Overview ===================================

  An attacker can overflow the output buffer of ps, when executed by
  another user, administrator, or script: a denial of service only (not
  an LPE), because ps mmap()s its output buffer and mprotect()s its last
  page with PROT_NONE (an effective guard page).

================================ Initial Report ================================

From http://www.openwall.com/lists/oss-security/2018/05/17/1:

ps's functions pr_args(), pr_comm(), and pr_fname() are vulnerable to an
mmap-based buffer overflow of outbuf (ps's output buffer):

 401 static int pr_args(char *restrict const outbuf, const proc_t *restrict const pp){
 402   char *endp = outbuf;
 403   int rightward = max_rightward;
 404   int fh = forest_helper(outbuf);
 405 
 406   endp += fh;
 407   rightward -= fh;
 408 
 409   if(pp->cmdline && !bsd_c_option)
 410     endp += escaped_copy(endp, *pp->cmdline, OUTBUF_SIZE, &rightward);
 411   else
 412     endp += escape_command(endp, pp, OUTBUF_SIZE, &rightward, ESC_DEFUNCT);
 413 
 414   if(bsd_e_option && rightward>1) {
 415     if(pp->environ && *pp->environ) {
 416       *endp++ = ' ';
 417       rightward--;
 418       endp += escape_strlist(endp, pp->environ, OUTBUF_SIZE, &rightward);
 419     }
 420   }
 421   return max_rightward-rightward;
 422 }

The number of bytes written to endp by the escape*() functions is added
to endp (a pointer into outbuf), but never subtracted from OUTBUF_SIZE.
Normally "rightward" prevents this buffer overflow, because the maximum
number of "cells" written to outbuf is OUTBUF_SIZE, and is equal to the
number of "bytes" written to outbuf; but not in escape_str_utf8():

 36 static int escape_str_utf8(char *restrict dst, const char *restrict src, int bufsize, int *maxcells){
 ..
 50     if (!(len = mbrtowc (&wc, src, MB_CUR_MAX, &s)))
 ..
 78       int wlen = wcwidth(wc);
 ..
100           memcpy(dst, src, len);
101           my_cells += wlen;
102           dst += len;
103           my_bytes += len;
104           src += len;

For example, in the "en_US.UTF-8" locale, the multibyte sequence
"\xf4\x81\x8e\xb6" consumes 4 bytes, but only 1 cell, and an easy
trigger for one of the outbuf overflows is:

$ (A=`python -c 'print "\xf4\x81\x8e\xb6" * 32767'` exec -a `python -c 'print "A" * 65535'` sleep 60) &
[1] 2670

# env LANG=en_US.UTF-8 ps awwe
  PID TTY      STAT   TIME COMMAND
...
Signal 11 (SEGV) caught by ps (procps-ng version 3.3.10).
 2670 pts/0    S      0:00ps:display.c:66: please report this bug
Segmentation fault

This buffer overflow is a denial of service only (not an LPE), because
ps mmap()s outbuf and mprotect()s its last page with PROT_NONE (an
effective guard page):

2147 void init_output(void){
....
2164   outbuf = mmap(
2165     0,
2166     page_size * (outbuf_pages+1), // 1 more, for guard page at high addresses
2167     PROT_READ | PROT_WRITE,
2168     MAP_PRIVATE | MAP_ANONYMOUS,
2169     -1,
2170     0
2171   );
....
2174   mprotect(outbuf + page_size*outbuf_pages, page_size, PROT_NONE); // guard page

================================= Our Analysis =================================

Fixed in patch 0054-ps-output.c-Fix-outbuf-overflows-in-pr_args-etc.patch
https://www.qualys.com/2018/05/17/procps-ng-audit-report-patches.tar.gz

================================= Our Solution =================================

We have applied the aforementioned patch and rebuilt