--- Begin Message ---
Package: procps
Version: 1:3.2.8-9squeeze1
Severity: normal
We found that under the following circumstances:
* Kernel > 3.2.29 (which shows > 32 groups in /proc/${pid}/status)
* one or more users logged in with lots of supplementary groups
then ps(1) fails with a SIGSEGV after attempting to allocate lots of memory.
This appears to be due flawed assumption in ps: That the contents of
/proc/${pid}/status will fit into a buffer of 1024 bytes: if the file
is larger, only the first 1024 bytes are read, and when subsequently
scanning the buffer the code "falls off the end":
http://forums.grsecurity.net/viewtopic.php?f=3&t=3298
Although 32 groups sounds ample, sites using Active Directory will
often find their users being members of lots of groups, as group
membership is a recursive concept in AD. And the numeric group IDs are
(in our case) 9 characters each, thus easily overflowing the 1024 byte
buffer.
Here's an example:
----------------------------- 8< cut here 8< -----------------
karl@someserver: ~$ ps
Signal 11 (SEGV) caught by ps (procps version 3.2.8).
Please send bug reports to <[email protected]> or <[email protected]>
karl@someserver: ~$ strace ps 2>&1 | tail -30
stat("/proc/1997", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
open("/proc/1997/stat", O_RDONLY) = 6
read(6, "1997 (sshd) S 1989 1989 1989 0 -"..., 1023) = 191
close(6) = 0
open("/proc/1997/status", O_RDONLY) = 6
read(6, "Name:\tsshd\nState:\tS (sleeping)\nT"..., 1023) = 1023
close(6) = 0
mmap(NULL, 135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
0x7f037a2fd000
mremap(0x7f037a2fd000, 135168, 266240, MREMAP_MAYMOVE) = 0x7f0379cd9000
mremap(0x7f0379cd9000, 266240, 528384, MREMAP_MAYMOVE) = 0x7f0379c58000
mremap(0x7f0379c58000, 528384, 1052672, MREMAP_MAYMOVE) = 0x7f0379b57000
mremap(0x7f0379b57000, 1052672, 2101248, MREMAP_MAYMOVE) = 0x7f0379956000
mremap(0x7f0379956000, 2101248, 4198400, MREMAP_MAYMOVE) = 0x7f0379555000
mremap(0x7f0379555000, 4198400, 8392704, MREMAP_MAYMOVE) = 0x7f0378d54000
mremap(0x7f0378d54000, 8392704, 16781312, MREMAP_MAYMOVE) = 0x7f0377d53000
mremap(0x7f0377d53000, 16781312, 33558528, MREMAP_MAYMOVE) = 0x7f0375d52000
mremap(0x7f0375d52000, 33558528, 67112960, MREMAP_MAYMOVE) = 0x7f0371d51000
mremap(0x7f0371d51000, 67112960, 134221824, MREMAP_MAYMOVE) = 0x7f0369d50000
mremap(0x7f0369d50000, 134221824, 268439552, MREMAP_MAYMOVE) = 0x7f0359d4f000
mremap(0x7f0359d4f000, 268439552, 536875008, MREMAP_MAYMOVE) = 0x7f0339d4e000
mremap(0x7f0339d4e000, 536875008, 1073745920, MREMAP_MAYMOVE) = 0x7f02f9d4d000
mremap(0x7f02f9d4d000, 1073745920, 2147487744, MREMAP_MAYMOVE) = 0x7f0279d4c000
mremap(0x7f0279d4c000, 2147487744, 4096, MREMAP_MAYMOVE) = 0x7f0279d4c000
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
write(2, "\n\nSignal 11 (SEGV) caught by ps "..., 132
Signal 11 (SEGV) caught by ps (procps version 3.2.8).
Please send bug reports to <[email protected]> or <[email protected]>
) = 132
exit_group(139) = ?
karl@someserver: ~$ wc --bytes < /proc/1997/status
1810
----------------------------- 8< cut here 8< -----------------
I have a (temporary) patch which increases the buffer size to 8K,
which appears sufficient in our case. But this does not fix the
underlying problem of having a limited buffer size to start with...
----------------------------- 8< cut here 8< -----------------
--- a/proc/readproc.c 2013-03-12 19:43:24.000000000 +0000
+++ b/proc/readproc.c 2013-03-13 10:12:47.744038428 +0000
@@ -28,6 +28,15 @@
#include <sys/types.h>
#include <sys/stat.h>
+/* Max # of bytes to expect in /proc/%d/status.
+
+ This may be a crazy amount if lots of supplementary groups are
+ listed. Most kernels will limit the contents to 32 (NGROUPS_SMALL)
+ groups, but kernels > 3.2.29 may show ALL of the supplementary
+ groups...
+ */
+#define PROC_STATUS_BUFSIZE 8192
+
// sometimes it's easier to do this manually, w/o gcc helping
#ifdef PROF
extern void __cyg_profile_func_enter(void*,void*);
@@ -560,7 +569,7 @@
// room to spare.
static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict
const p) {
static struct stat sb; // stat() buffer
- static char sbuf[1024]; // buffer for stat,statm
+ static char sbuf[PROC_STATUS_BUFSIZE]; // buffer for stat,statm,status
char *restrict const path = PT->path;
unsigned flags = PT->flags;
@@ -655,7 +664,7 @@
// path is a path to the task, with some room to spare.
static proc_t* simple_readtask(PROCTAB *restrict const PT, const proc_t
*restrict const p, proc_t *restrict const t, char *restrict const path) {
static struct stat sb; // stat() buffer
- static char sbuf[1024]; // buffer for stat,statm
+ static char sbuf[PROC_STATUS_BUFSIZE]; // buffer for stat,statm,status
unsigned flags = PT->flags;
//printf("hhh\n");
@@ -1108,7 +1117,7 @@
* and filled out proc_t structure.
*/
proc_t * get_proc_stats(pid_t pid, proc_t *p) {
- static char path[32], sbuf[1024];
+ static char path[32], sbuf[PROC_STATUS_BUFSIZE]; // buffer for
stat,statm,status
struct stat statbuf;
sprintf(path, "/proc/%d", pid);
----------------------------- 8< cut here 8< -----------------
-- System Information:
Debian Release: 6.0.6
APT prefers stable
APT policy: (500, 'stable')
Architecture: amd64 (x86_64)
Kernel: Linux 3.2.0-0.bpo.4-amd64 (SMP w/2 CPU cores)
Locale: LANG=en_GB.utf8, LC_CTYPE=en_GB.utf8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Versions of packages procps depends on:
ii initscripts 2.88dsf-13.1+squeeze1 scripts for initializing and shutt
ii libc6 2.11.3-4 Embedded GNU C Library: Shared lib
ii libncurses5 5.7+20100313-5 shared libraries for terminal hand
ii libncursesw5 5.7+20100313-5 shared libraries for terminal hand
ii lsb-base 3.2-23.2squeeze1 Linux Standard Base 3.2 init scrip
Versions of packages procps recommends:
ii psmisc 22.16-1~bpo60+1 utilities that use the proc file s
procps suggests no packages.
-- Configuration Files:
/etc/sysctl.conf changed [not included]
-- no debconf information
--- End Message ---