2002-02-02 04:17:29 +05:30
|
|
|
/*
|
|
|
|
* New Interface to Process Table -- PROCTAB Stream (a la Directory streams)
|
|
|
|
* Copyright (C) 1996 Charles L. Blake.
|
|
|
|
* Copyright (C) 1998 Michael K. Johnson
|
2003-09-18 07:48:43 +05:30
|
|
|
* Copyright 1998-2003 Albert Cahalan
|
2012-03-02 17:59:36 +05:30
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
2002-02-02 04:17:29 +05:30
|
|
|
*/
|
2011-06-04 19:56:58 +05:30
|
|
|
|
2002-06-24 09:59:04 +05:30
|
|
|
#include "version.h"
|
|
|
|
#include "readproc.h"
|
2002-12-09 12:30:07 +05:30
|
|
|
#include "alloc.h"
|
2011-05-18 14:03:44 +05:30
|
|
|
#include "escape.h"
|
2002-12-09 12:30:07 +05:30
|
|
|
#include "pwcache.h"
|
2002-06-24 09:59:04 +05:30
|
|
|
#include "devname.h"
|
|
|
|
#include "procps.h"
|
2002-02-02 04:17:29 +05:30
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2002-12-03 14:37:59 +05:30
|
|
|
#include <errno.h>
|
2002-02-02 04:17:29 +05:30
|
|
|
#include <stdarg.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <fcntl.h>
|
2014-07-06 19:51:01 +05:30
|
|
|
#include <dirent.h>
|
2002-02-02 04:17:29 +05:30
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
1970-01-01 05:30:00 +05:30
|
|
|
#include <limits.h>
|
1970-01-01 05:30:00 +05:30
|
|
|
#include <stdint.h>
|
2014-06-28 10:30:22 +05:30
|
|
|
#ifdef WITH_SYSTEMD
|
|
|
|
#include <systemd/sd-login.h>
|
|
|
|
#endif
|
2017-05-30 20:03:28 +05:30
|
|
|
#ifdef WITH_ELOGIND
|
|
|
|
#include <elogind/sd-login.h>
|
|
|
|
#endif
|
2002-02-02 04:17:29 +05:30
|
|
|
|
2003-09-18 03:28:32 +05:30
|
|
|
// sometimes it's easier to do this manually, w/o gcc helping
|
2003-02-17 06:27:15 +05:30
|
|
|
#ifdef PROF
|
|
|
|
extern void __cyg_profile_func_enter(void*,void*);
|
|
|
|
#define ENTER(x) __cyg_profile_func_enter((void*)x,(void*)x)
|
|
|
|
#define LEAVE(x) __cyg_profile_func_exit((void*)x,(void*)x)
|
|
|
|
#else
|
|
|
|
#define ENTER(x)
|
|
|
|
#define LEAVE(x)
|
|
|
|
#endif
|
|
|
|
|
2011-08-11 03:12:14 +05:30
|
|
|
#ifdef QUICK_THREADS
|
|
|
|
// used when multi-threaded and some memory must not be freed
|
|
|
|
#define MK_THREAD(q) q->pad_1 = '\xee'
|
|
|
|
#define IS_THREAD(q) ( q->pad_1 == '\xee' )
|
|
|
|
#endif
|
|
|
|
|
2011-12-02 15:17:19 +05:30
|
|
|
// utility buffers of MAX_BUFSZ bytes each, available to
|
|
|
|
// any function following an openproc() call
|
|
|
|
static char *src_buffer,
|
|
|
|
*dst_buffer;
|
|
|
|
#define MAX_BUFSZ 1024*64*2
|
|
|
|
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
// dynamic 'utility' buffer support for file2str() calls
|
|
|
|
struct utlbuf_s {
|
|
|
|
char *buf; // dynamically grown buffer
|
|
|
|
int siz; // current len of the above
|
|
|
|
} utlbuf_s;
|
|
|
|
|
2011-08-01 16:58:46 +05:30
|
|
|
#ifndef SIGNAL_STRING
|
2006-06-17 09:44:57 +05:30
|
|
|
// convert hex string to unsigned long long
|
|
|
|
static unsigned long long unhex(const char *restrict cp){
|
|
|
|
unsigned long long ull = 0;
|
|
|
|
for(;;){
|
|
|
|
char c = *cp++;
|
1970-01-01 05:30:00 +05:30
|
|
|
if(!( (c >= '0' && c <= '9') ||
|
|
|
|
(c >= 'A' && c <= 'F') ||
|
|
|
|
(c >= 'a' && c <= 'f') )) break;
|
|
|
|
ull = (ull<<4) | (c - (c >= 'a' ? 'a'-10 : c >= 'A' ? 'A'-10 : '0'));
|
2006-06-17 09:44:57 +05:30
|
|
|
}
|
|
|
|
return ull;
|
|
|
|
}
|
2011-08-01 16:58:46 +05:30
|
|
|
#endif
|
2006-06-17 09:44:57 +05:30
|
|
|
|
2003-09-20 13:59:55 +05:30
|
|
|
static int task_dir_missing;
|
|
|
|
|
2011-08-01 16:58:46 +05:30
|
|
|
// free any additional dynamically acquired storage associated with a proc_t
|
|
|
|
// ( and if it's to be reused, refresh it otherwise destroy it )
|
|
|
|
static inline void free_acquired (proc_t *p, int reuse) {
|
2011-08-11 03:12:14 +05:30
|
|
|
#ifdef QUICK_THREADS
|
|
|
|
if (!IS_THREAD(p)) {
|
|
|
|
#endif
|
2014-06-28 10:30:22 +05:30
|
|
|
if (p->environ) free((void*)*p->environ);
|
|
|
|
if (p->cmdline) free((void*)*p->cmdline);
|
|
|
|
if (p->cgroup) free((void*)*p->cgroup);
|
2016-07-03 10:30:00 +05:30
|
|
|
if (p->cgname) free(p->cgname);
|
2014-06-28 10:30:22 +05:30
|
|
|
if (p->supgid) free(p->supgid);
|
|
|
|
if (p->supgrp) free(p->supgrp);
|
|
|
|
if (p->sd_mach) free(p->sd_mach);
|
|
|
|
if (p->sd_ouid) free(p->sd_ouid);
|
|
|
|
if (p->sd_seat) free(p->sd_seat);
|
|
|
|
if (p->sd_sess) free(p->sd_sess);
|
|
|
|
if (p->sd_slice) free(p->sd_slice);
|
|
|
|
if (p->sd_unit) free(p->sd_unit);
|
|
|
|
if (p->sd_uunit) free(p->sd_uunit);
|
2011-08-11 03:12:14 +05:30
|
|
|
#ifdef QUICK_THREADS
|
|
|
|
}
|
|
|
|
#endif
|
2011-08-01 16:58:46 +05:30
|
|
|
memset(p, reuse ? '\0' : '\xff', sizeof(*p));
|
|
|
|
}
|
|
|
|
|
2003-02-17 06:27:15 +05:30
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2002-02-02 04:17:29 +05:30
|
|
|
|
2003-02-17 06:27:15 +05:30
|
|
|
typedef struct status_table_struct {
|
2016-04-13 10:30:00 +05:30
|
|
|
unsigned char name[8]; // /proc/*/status field name
|
2003-12-13 22:21:40 +05:30
|
|
|
unsigned char len; // name length
|
2003-02-17 06:27:15 +05:30
|
|
|
#ifdef LABEL_OFFSET
|
|
|
|
long offset; // jump address offset
|
|
|
|
#else
|
|
|
|
void *addr;
|
|
|
|
#endif
|
|
|
|
} status_table_struct;
|
|
|
|
|
|
|
|
#ifdef LABEL_OFFSET
|
2003-05-30 08:43:32 +05:30
|
|
|
#define F(x) {#x, sizeof(#x)-1, (long)(&&case_##x-&&base)},
|
2003-02-17 06:27:15 +05:30
|
|
|
#else
|
|
|
|
#define F(x) {#x, sizeof(#x)-1, &&case_##x},
|
|
|
|
#endif
|
|
|
|
#define NUL {"", 0, 0},
|
2002-12-03 14:37:59 +05:30
|
|
|
|
2016-04-13 10:30:00 +05:30
|
|
|
#define GPERF_TABLE_SIZE 128
|
|
|
|
|
2003-02-17 06:27:15 +05:30
|
|
|
// Derived from:
|
2011-08-01 16:58:46 +05:30
|
|
|
// gperf -7 --language=ANSI-C --key-positions=1,3,4 -C -n -c <if-not-piped>
|
2016-04-13 10:30:00 +05:30
|
|
|
// ( --key-positions verified by omission & reported "Computed positions" )
|
2003-12-13 22:21:40 +05:30
|
|
|
//
|
|
|
|
// Suggested method:
|
|
|
|
// Grep this file for "case_", then strip those down to the name.
|
2011-08-01 16:58:46 +05:30
|
|
|
// Eliminate duplicates (due to #ifs), the ' case_' prefix and
|
|
|
|
// any c comments. Leave the colon and newline so that "Pid:\n",
|
|
|
|
// "Threads:\n", etc. would be lines, but no quote, no escape, etc.
|
|
|
|
//
|
|
|
|
// After a pipe through gperf, insert the resulting 'asso_values'
|
2011-09-24 19:57:37 +05:30
|
|
|
// into our 'asso' array. Then convert the gperf 'wordlist' array
|
2011-08-01 16:58:46 +05:30
|
|
|
// into our 'table' array by wrapping the string literals within
|
|
|
|
// the F macro and replacing empty strings with the NUL define.
|
2003-12-13 22:21:40 +05:30
|
|
|
//
|
2010-05-18 12:32:03 +05:30
|
|
|
// In the status_table_struct watch out for name size (grrr, expanding)
|
2016-04-13 10:30:00 +05:30
|
|
|
// and the number of entries. Currently, the table is padded to 128
|
|
|
|
// entries and we therefore mask with 127.
|
2002-02-02 04:17:29 +05:30
|
|
|
|
2003-09-28 08:15:05 +05:30
|
|
|
static void status2proc(char *S, proc_t *restrict P, int is_proc){
|
2003-12-13 22:21:40 +05:30
|
|
|
long Threads = 0;
|
|
|
|
long Tgid = 0;
|
|
|
|
long Pid = 0;
|
|
|
|
|
2010-05-18 12:32:03 +05:30
|
|
|
// 128 entries because we trust the kernel to use ASCII names
|
2003-12-13 22:21:40 +05:30
|
|
|
static const unsigned char asso[] =
|
|
|
|
{
|
2016-04-13 10:30:00 +05:30
|
|
|
101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
|
|
|
|
101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
|
|
|
|
101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
|
|
|
|
101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
|
|
|
|
101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
|
|
|
|
101, 101, 101, 101, 101, 101, 101, 101, 6, 101,
|
|
|
|
101, 101, 101, 101, 101, 45, 55, 25, 31, 50,
|
|
|
|
50, 10, 0, 35, 101, 101, 21, 101, 30, 101,
|
|
|
|
20, 36, 0, 5, 0, 40, 0, 0, 101, 101,
|
|
|
|
101, 101, 101, 101, 101, 101, 101, 30, 101, 15,
|
|
|
|
0, 1, 101, 10, 101, 10, 101, 101, 101, 25,
|
|
|
|
101, 40, 0, 101, 0, 50, 6, 40, 101, 1,
|
|
|
|
35, 101, 101, 101, 101, 101, 101, 101
|
2003-02-17 06:27:15 +05:30
|
|
|
};
|
2003-12-13 22:21:40 +05:30
|
|
|
|
2016-04-13 10:30:00 +05:30
|
|
|
static const status_table_struct table[GPERF_TABLE_SIZE] = {
|
2010-05-18 12:32:03 +05:30
|
|
|
F(VmHWM)
|
2016-04-13 10:30:00 +05:30
|
|
|
F(Threads)
|
|
|
|
NUL NUL NUL
|
2010-05-18 12:32:03 +05:30
|
|
|
F(VmRSS)
|
2016-04-13 10:30:00 +05:30
|
|
|
F(VmSwap)
|
|
|
|
NUL NUL NUL
|
2010-05-18 12:32:03 +05:30
|
|
|
F(Tgid)
|
2016-04-13 10:30:00 +05:30
|
|
|
F(VmStk)
|
|
|
|
NUL NUL NUL
|
2010-05-18 12:32:03 +05:30
|
|
|
F(VmSize)
|
2016-04-13 10:30:00 +05:30
|
|
|
F(Gid)
|
|
|
|
NUL NUL NUL
|
2010-05-18 12:32:03 +05:30
|
|
|
F(VmPTE)
|
2016-04-13 10:30:00 +05:30
|
|
|
F(VmPeak)
|
|
|
|
NUL NUL NUL
|
2010-05-18 12:32:03 +05:30
|
|
|
F(ShdPnd)
|
2016-04-13 10:30:00 +05:30
|
|
|
F(Pid)
|
|
|
|
NUL NUL NUL
|
2010-05-18 12:32:03 +05:30
|
|
|
F(PPid)
|
2016-04-13 10:30:00 +05:30
|
|
|
F(VmLib)
|
|
|
|
NUL NUL NUL
|
2010-05-18 12:32:03 +05:30
|
|
|
F(SigPnd)
|
2016-04-13 10:30:00 +05:30
|
|
|
F(VmLck)
|
|
|
|
NUL NUL NUL
|
2003-12-13 22:21:40 +05:30
|
|
|
F(SigCgt)
|
2016-04-13 10:30:00 +05:30
|
|
|
F(State)
|
|
|
|
NUL NUL NUL
|
2010-05-18 12:32:03 +05:30
|
|
|
F(CapPrm)
|
2016-04-13 10:30:00 +05:30
|
|
|
F(Uid)
|
|
|
|
NUL NUL NUL
|
|
|
|
F(SigIgn)
|
|
|
|
F(SigQ)
|
|
|
|
NUL NUL NUL
|
|
|
|
F(RssShmem)
|
|
|
|
F(Name)
|
|
|
|
NUL NUL NUL
|
|
|
|
F(CapInh)
|
|
|
|
F(VmData)
|
|
|
|
NUL NUL NUL
|
|
|
|
F(FDSize)
|
|
|
|
NUL NUL NUL NUL
|
|
|
|
F(SigBlk)
|
|
|
|
NUL NUL NUL NUL
|
2010-05-18 12:32:03 +05:30
|
|
|
F(CapEff)
|
2016-04-13 10:30:00 +05:30
|
|
|
NUL NUL NUL NUL
|
|
|
|
F(CapBnd)
|
|
|
|
NUL NUL NUL NUL
|
2010-05-18 12:32:03 +05:30
|
|
|
F(VmExe)
|
2016-04-13 10:30:00 +05:30
|
|
|
NUL NUL NUL NUL
|
2010-05-18 12:32:03 +05:30
|
|
|
F(Groups)
|
2016-04-13 10:30:00 +05:30
|
|
|
NUL NUL NUL NUL
|
|
|
|
F(RssAnon)
|
|
|
|
NUL NUL NUL NUL
|
|
|
|
F(RssFile)
|
2003-02-17 06:27:15 +05:30
|
|
|
};
|
2002-02-02 04:17:29 +05:30
|
|
|
|
2003-02-17 06:27:15 +05:30
|
|
|
#undef F
|
|
|
|
#undef NUL
|
2002-02-02 04:17:29 +05:30
|
|
|
|
2003-02-17 06:27:15 +05:30
|
|
|
ENTER(0x220);
|
|
|
|
|
|
|
|
goto base;
|
2003-02-12 13:45:53 +05:30
|
|
|
|
2003-02-17 06:27:15 +05:30
|
|
|
for(;;){
|
|
|
|
char *colon;
|
|
|
|
status_table_struct entry;
|
|
|
|
|
|
|
|
// advance to next line
|
|
|
|
S = strchr(S, '\n');
|
|
|
|
if(unlikely(!S)) break; // if no newline
|
|
|
|
S++;
|
|
|
|
|
|
|
|
// examine a field name (hash and compare)
|
|
|
|
base:
|
1970-01-01 05:30:00 +05:30
|
|
|
if(unlikely(!S[0] || !S[1] || !S[2] || !S[3])) break;
|
|
|
|
entry = table[(GPERF_TABLE_SIZE -1) & (asso[S[3]&127] + asso[S[2]&127] + asso[S[0]&127])];
|
2003-02-17 06:27:15 +05:30
|
|
|
colon = strchr(S, ':');
|
|
|
|
if(unlikely(!colon)) break;
|
|
|
|
if(unlikely(colon[1]!='\t')) break;
|
|
|
|
if(unlikely(colon-S != entry.len)) continue;
|
|
|
|
if(unlikely(memcmp(entry.name,S,colon-S))) continue;
|
|
|
|
|
|
|
|
S = colon+2; // past the '\t'
|
|
|
|
|
|
|
|
#ifdef LABEL_OFFSET
|
|
|
|
goto *(&&base + entry.offset);
|
2002-02-02 04:17:29 +05:30
|
|
|
#else
|
2003-02-17 06:27:15 +05:30
|
|
|
goto *entry.addr;
|
2002-02-02 04:17:29 +05:30
|
|
|
#endif
|
|
|
|
|
2011-08-01 16:58:46 +05:30
|
|
|
case_Name:
|
|
|
|
{ unsigned u = 0;
|
2003-02-18 09:21:03 +05:30
|
|
|
while(u < sizeof P->cmd - 1u){
|
2003-02-17 06:27:15 +05:30
|
|
|
int c = *S++;
|
|
|
|
if(unlikely(c=='\n')) break;
|
2003-02-18 09:21:03 +05:30
|
|
|
if(unlikely(c=='\0')) break; // should never happen
|
2003-02-17 06:27:15 +05:30
|
|
|
if(unlikely(c=='\\')){
|
|
|
|
c = *S++;
|
|
|
|
if(c=='\n') break; // should never happen
|
|
|
|
if(!c) break; // should never happen
|
|
|
|
if(c=='n') c='\n'; // else we assume it is '\\'
|
|
|
|
}
|
2003-02-18 09:21:03 +05:30
|
|
|
P->cmd[u++] = c;
|
2003-02-17 06:27:15 +05:30
|
|
|
}
|
2003-02-18 09:21:03 +05:30
|
|
|
P->cmd[u] = '\0';
|
|
|
|
S--; // put back the '\n' or '\0'
|
2003-02-17 06:27:15 +05:30
|
|
|
continue;
|
|
|
|
}
|
2006-06-17 09:44:57 +05:30
|
|
|
#ifdef SIGNAL_STRING
|
2003-02-17 06:27:15 +05:30
|
|
|
case_ShdPnd:
|
2006-06-17 09:44:57 +05:30
|
|
|
memcpy(P->signal, S, 16);
|
|
|
|
P->signal[16] = '\0';
|
2003-02-17 06:27:15 +05:30
|
|
|
continue;
|
|
|
|
case_SigBlk:
|
|
|
|
memcpy(P->blocked, S, 16);
|
|
|
|
P->blocked[16] = '\0';
|
|
|
|
continue;
|
|
|
|
case_SigCgt:
|
|
|
|
memcpy(P->sigcatch, S, 16);
|
|
|
|
P->sigcatch[16] = '\0';
|
|
|
|
continue;
|
|
|
|
case_SigIgn:
|
|
|
|
memcpy(P->sigignore, S, 16);
|
|
|
|
P->sigignore[16] = '\0';
|
|
|
|
continue;
|
|
|
|
case_SigPnd:
|
2006-06-17 09:44:57 +05:30
|
|
|
memcpy(P->_sigpnd, S, 16);
|
|
|
|
P->_sigpnd[16] = '\0';
|
2003-02-17 06:27:15 +05:30
|
|
|
continue;
|
2006-06-17 09:44:57 +05:30
|
|
|
#else
|
|
|
|
case_ShdPnd:
|
|
|
|
P->signal = unhex(S);
|
|
|
|
continue;
|
|
|
|
case_SigBlk:
|
|
|
|
P->blocked = unhex(S);
|
|
|
|
continue;
|
|
|
|
case_SigCgt:
|
|
|
|
P->sigcatch = unhex(S);
|
|
|
|
continue;
|
|
|
|
case_SigIgn:
|
|
|
|
P->sigignore = unhex(S);
|
|
|
|
continue;
|
|
|
|
case_SigPnd:
|
|
|
|
P->_sigpnd = unhex(S);
|
|
|
|
continue;
|
|
|
|
#endif
|
2003-02-17 06:27:15 +05:30
|
|
|
case_State:
|
|
|
|
P->state = *S;
|
|
|
|
continue;
|
|
|
|
case_Tgid:
|
2003-12-13 22:21:40 +05:30
|
|
|
Tgid = strtol(S,&S,10);
|
|
|
|
continue;
|
|
|
|
case_Pid:
|
|
|
|
Pid = strtol(S,&S,10);
|
|
|
|
continue;
|
|
|
|
case_PPid:
|
|
|
|
P->ppid = strtol(S,&S,10);
|
|
|
|
continue;
|
|
|
|
case_Threads:
|
|
|
|
Threads = strtol(S,&S,10);
|
2003-02-17 06:27:15 +05:30
|
|
|
continue;
|
|
|
|
case_Uid:
|
|
|
|
P->ruid = strtol(S,&S,10);
|
|
|
|
P->euid = strtol(S,&S,10);
|
|
|
|
P->suid = strtol(S,&S,10);
|
|
|
|
P->fuid = strtol(S,&S,10);
|
|
|
|
continue;
|
2003-12-13 22:21:40 +05:30
|
|
|
case_Gid:
|
|
|
|
P->rgid = strtol(S,&S,10);
|
|
|
|
P->egid = strtol(S,&S,10);
|
|
|
|
P->sgid = strtol(S,&S,10);
|
|
|
|
P->fgid = strtol(S,&S,10);
|
|
|
|
continue;
|
2003-02-17 06:27:15 +05:30
|
|
|
case_VmData:
|
|
|
|
P->vm_data = strtol(S,&S,10);
|
|
|
|
continue;
|
|
|
|
case_VmExe:
|
|
|
|
P->vm_exe = strtol(S,&S,10);
|
|
|
|
continue;
|
|
|
|
case_VmLck:
|
|
|
|
P->vm_lock = strtol(S,&S,10);
|
|
|
|
continue;
|
|
|
|
case_VmLib:
|
|
|
|
P->vm_lib = strtol(S,&S,10);
|
|
|
|
continue;
|
|
|
|
case_VmRSS:
|
|
|
|
P->vm_rss = strtol(S,&S,10);
|
|
|
|
continue;
|
2016-04-13 10:30:00 +05:30
|
|
|
case_RssAnon: // subset of VmRSS, linux-4.5
|
|
|
|
P->vm_rss_anon = strtol(S,&S,10);
|
|
|
|
continue;
|
|
|
|
case_RssFile: // subset of VmRSS, linux-4.5
|
|
|
|
P->vm_rss_file = strtol(S,&S,10);
|
|
|
|
continue;
|
|
|
|
case_RssShmem: // subset of VmRSS, linux-4.5
|
|
|
|
P->vm_rss_shared = strtol(S,&S,10);
|
|
|
|
continue;
|
2003-02-17 06:27:15 +05:30
|
|
|
case_VmSize:
|
|
|
|
P->vm_size = strtol(S,&S,10);
|
|
|
|
continue;
|
|
|
|
case_VmStk:
|
|
|
|
P->vm_stack = strtol(S,&S,10);
|
|
|
|
continue;
|
2010-05-18 12:32:03 +05:30
|
|
|
case_VmSwap: // Linux 2.6.34
|
|
|
|
P->vm_swap = strtol(S,&S,10);
|
|
|
|
continue;
|
2011-08-01 16:58:46 +05:30
|
|
|
case_Groups:
|
2018-05-30 10:30:00 +05:30
|
|
|
{ char *ss = S, *nl = strchr(S, '\n');
|
|
|
|
size_t j;
|
2012-10-11 22:32:10 +05:30
|
|
|
|
2018-05-30 10:30:00 +05:30
|
|
|
while (' ' == *ss || '\t' == *ss) ss++;
|
|
|
|
if (ss >= nl) continue;
|
|
|
|
j = nl ? (size_t)(nl - ss) : strlen(ss);
|
1970-01-01 05:30:00 +05:30
|
|
|
if (j > 0 && j < INT_MAX) {
|
2011-08-01 16:58:46 +05:30
|
|
|
P->supgid = xmalloc(j+1); // +1 in case space disappears
|
2018-05-30 10:30:00 +05:30
|
|
|
memcpy(P->supgid, ss, j);
|
2011-08-01 16:58:46 +05:30
|
|
|
if (unlikely(' ' != P->supgid[--j])) ++j;
|
|
|
|
P->supgid[j] = '\0'; // whack the space or the newline
|
|
|
|
for ( ; j; j--)
|
|
|
|
if (' ' == P->supgid[j])
|
|
|
|
P->supgid[j] = ',';
|
2012-06-28 10:30:01 +05:30
|
|
|
}
|
2011-08-01 16:58:46 +05:30
|
|
|
continue;
|
|
|
|
}
|
2010-05-18 12:32:03 +05:30
|
|
|
case_CapBnd:
|
|
|
|
case_CapEff:
|
|
|
|
case_CapInh:
|
|
|
|
case_CapPrm:
|
|
|
|
case_FDSize:
|
|
|
|
case_SigQ:
|
|
|
|
case_VmHWM: // 2005, peak VmRSS unless VmRSS is bigger
|
|
|
|
case_VmPTE:
|
|
|
|
case_VmPeak: // 2005, peak VmSize unless VmSize is bigger
|
|
|
|
continue;
|
2003-02-17 06:27:15 +05:30
|
|
|
}
|
2003-09-28 08:15:05 +05:30
|
|
|
|
2006-06-17 09:44:57 +05:30
|
|
|
#if 0
|
2003-09-28 08:15:05 +05:30
|
|
|
// recent kernels supply per-tgid pending signals
|
|
|
|
if(is_proc && *ShdPnd){
|
2011-08-01 16:58:46 +05:30
|
|
|
memcpy(P->signal, ShdPnd, 16);
|
|
|
|
P->signal[16] = '\0';
|
2003-09-28 08:15:05 +05:30
|
|
|
}
|
2006-06-17 09:44:57 +05:30
|
|
|
#endif
|
|
|
|
|
|
|
|
// recent kernels supply per-tgid pending signals
|
|
|
|
#ifdef SIGNAL_STRING
|
|
|
|
if(!is_proc || !P->signal[0]){
|
2011-08-01 16:58:46 +05:30
|
|
|
memcpy(P->signal, P->_sigpnd, 16);
|
|
|
|
P->signal[16] = '\0';
|
2006-06-17 09:44:57 +05:30
|
|
|
}
|
|
|
|
#else
|
2011-08-01 16:58:46 +05:30
|
|
|
if(!is_proc){
|
|
|
|
P->signal = P->_sigpnd;
|
2006-06-17 09:44:57 +05:30
|
|
|
}
|
|
|
|
#endif
|
2003-09-28 08:15:05 +05:30
|
|
|
|
2003-12-13 22:21:40 +05:30
|
|
|
// Linux 2.4.13-pre1 to max 2.4.xx have a useless "Tgid"
|
|
|
|
// that is not initialized for built-in kernel tasks.
|
|
|
|
// Only 2.6.0 and above have "Threads" (nlwp) info.
|
|
|
|
|
|
|
|
if(Threads){
|
2011-08-01 16:58:46 +05:30
|
|
|
P->nlwp = Threads;
|
|
|
|
P->tgid = Tgid; // the POSIX PID value
|
|
|
|
P->tid = Pid; // the thread ID
|
2003-12-13 22:21:40 +05:30
|
|
|
}else{
|
2011-08-01 16:58:46 +05:30
|
|
|
P->nlwp = 1;
|
|
|
|
P->tgid = Pid;
|
|
|
|
P->tid = Pid;
|
2003-12-13 22:21:40 +05:30
|
|
|
}
|
|
|
|
|
2012-06-28 10:30:01 +05:30
|
|
|
if (!P->supgid)
|
|
|
|
P->supgid = xstrdup("-");
|
|
|
|
|
2003-02-17 06:27:15 +05:30
|
|
|
LEAVE(0x220);
|
|
|
|
}
|
2016-04-13 10:30:00 +05:30
|
|
|
#undef GPERF_TABLE_SIZE
|
2003-02-17 06:27:15 +05:30
|
|
|
|
2011-08-01 16:58:46 +05:30
|
|
|
static void supgrps_from_supgids (proc_t *p) {
|
|
|
|
char *g, *s;
|
|
|
|
int t;
|
|
|
|
|
|
|
|
if (!p->supgid || '-' == *p->supgid) {
|
2011-12-03 04:47:02 +05:30
|
|
|
p->supgrp = xstrdup("-");
|
2011-08-01 16:58:46 +05:30
|
|
|
return;
|
|
|
|
}
|
|
|
|
s = p->supgid;
|
|
|
|
t = 0;
|
|
|
|
do {
|
1970-01-01 05:30:00 +05:30
|
|
|
const int max = P_G_SZ+2;
|
|
|
|
char *end = NULL;
|
|
|
|
gid_t gid;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
while (',' == *s) ++s;
|
|
|
|
gid = strtol(s, &end, 10);
|
2018-06-01 10:30:00 +05:30
|
|
|
if (end <= s) break;
|
1970-01-01 05:30:00 +05:30
|
|
|
s = end;
|
|
|
|
g = pwcache_get_group(gid);
|
|
|
|
|
|
|
|
if (t >= INT_MAX - max) break;
|
|
|
|
p->supgrp = xrealloc(p->supgrp, t + max);
|
|
|
|
|
|
|
|
len = snprintf(p->supgrp+t, max, "%s%s", t ? "," : "", g);
|
|
|
|
if (len <= 0) (p->supgrp+t)[len = 0] = '\0';
|
|
|
|
else if (len >= max) len = max-1;
|
|
|
|
t += len;
|
2011-08-01 16:58:46 +05:30
|
|
|
} while (*s);
|
2018-06-01 10:30:00 +05:30
|
|
|
|
|
|
|
if (!p->supgrp)
|
|
|
|
p->supgrp = xstrdup("-");
|
2011-08-01 16:58:46 +05:30
|
|
|
}
|
|
|
|
|
2003-02-17 06:27:15 +05:30
|
|
|
///////////////////////////////////////////////////////////////////////
|
2011-04-15 19:22:40 +05:30
|
|
|
static void oomscore2proc(const char* S, proc_t *restrict P)
|
|
|
|
{
|
|
|
|
sscanf(S, "%d", &P->oom_score);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void oomadj2proc(const char* S, proc_t *restrict P)
|
|
|
|
{
|
|
|
|
sscanf(S, "%d", &P->oom_adj);
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
2013-04-09 00:33:13 +05:30
|
|
|
static const char *ns_names[] = {
|
|
|
|
[IPCNS] = "ipc",
|
|
|
|
[MNTNS] = "mnt",
|
|
|
|
[NETNS] = "net",
|
|
|
|
[PIDNS] = "pid",
|
|
|
|
[USERNS] = "user",
|
|
|
|
[UTSNS] = "uts",
|
|
|
|
};
|
|
|
|
|
|
|
|
const char *get_ns_name(int id) {
|
1970-01-01 05:30:00 +05:30
|
|
|
if (id < 0 || id >= NUM_NS)
|
2013-04-09 00:33:13 +05:30
|
|
|
return NULL;
|
|
|
|
return ns_names[id];
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_ns_id(const char *name) {
|
|
|
|
int i;
|
|
|
|
|
1970-01-01 05:30:00 +05:30
|
|
|
if (!name)
|
|
|
|
return -1;
|
2013-04-09 00:33:13 +05:30
|
|
|
for (i = 0; i < NUM_NS; i++)
|
|
|
|
if (!strcmp(ns_names[i], name))
|
|
|
|
return i;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-11-10 11:30:00 +05:30
|
|
|
static void ns2proc(const char *directory, proc_t *restrict p) {
|
|
|
|
char path[PROCPATHLEN];
|
|
|
|
struct stat sb;
|
2013-04-09 00:33:13 +05:30
|
|
|
int i;
|
|
|
|
|
2013-11-10 11:30:00 +05:30
|
|
|
for (i = 0; i < NUM_NS; i++) {
|
|
|
|
snprintf(path, sizeof(path), "%s/ns/%s", directory, ns_names[i]);
|
|
|
|
if (0 == stat(path, &sb))
|
|
|
|
p->ns[i] = (long)sb.st_ino;
|
|
|
|
#if 0
|
|
|
|
else // this allows a caller to distinguish
|
|
|
|
p->ns[i] = -errno; // between the ENOENT or EACCES errors
|
|
|
|
#endif
|
|
|
|
}
|
2013-04-09 00:33:13 +05:30
|
|
|
}
|
2014-06-28 10:30:22 +05:30
|
|
|
|
|
|
|
static void sd2proc(proc_t *restrict p) {
|
2017-05-30 20:03:28 +05:30
|
|
|
#if defined(WITH_SYSTEMD) || defined(WITH_ELOGIND)
|
2014-06-28 10:30:22 +05:30
|
|
|
char buf[64];
|
|
|
|
uid_t uid;
|
|
|
|
|
|
|
|
if (0 > sd_pid_get_machine_name(p->tid, &p->sd_mach))
|
|
|
|
p->sd_mach = strdup("-");
|
|
|
|
|
|
|
|
if (0 > sd_pid_get_owner_uid(p->tid, &uid))
|
|
|
|
p->sd_ouid = strdup("-");
|
|
|
|
else {
|
|
|
|
snprintf(buf, sizeof(buf), "%d", (int)uid);
|
|
|
|
p->sd_ouid = strdup(buf);
|
|
|
|
}
|
|
|
|
if (0 > sd_pid_get_session(p->tid, &p->sd_sess)) {
|
|
|
|
p->sd_sess = strdup("-");
|
|
|
|
p->sd_seat = strdup("-");
|
|
|
|
} else {
|
|
|
|
if (0 > sd_session_get_seat(p->sd_sess, &p->sd_seat))
|
|
|
|
p->sd_seat = strdup("-");
|
|
|
|
}
|
|
|
|
if (0 > sd_pid_get_slice(p->tid, &p->sd_slice))
|
|
|
|
p->sd_slice = strdup("-");
|
|
|
|
if (0 > sd_pid_get_unit(p->tid, &p->sd_unit))
|
|
|
|
p->sd_unit = strdup("-");
|
|
|
|
if (0 > sd_pid_get_user_unit(p->tid, &p->sd_uunit))
|
|
|
|
p->sd_uunit = strdup("-");
|
2016-06-02 10:30:00 +05:30
|
|
|
#else
|
|
|
|
p->sd_mach = strdup("?");
|
|
|
|
p->sd_ouid = strdup("?");
|
|
|
|
p->sd_seat = strdup("?");
|
|
|
|
p->sd_sess = strdup("?");
|
|
|
|
p->sd_slice = strdup("?");
|
|
|
|
p->sd_unit = strdup("?");
|
|
|
|
p->sd_uunit = strdup("?");
|
2014-06-28 10:30:22 +05:30
|
|
|
#endif
|
2016-06-02 10:30:00 +05:30
|
|
|
}
|
2013-04-09 00:33:13 +05:30
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
2002-02-02 04:17:29 +05:30
|
|
|
|
2002-12-21 16:04:50 +05:30
|
|
|
// Reads /proc/*/stat files, being careful not to trip over processes with
|
|
|
|
// names like ":-) 1 2 3 4 5 6".
|
2002-11-25 15:46:33 +05:30
|
|
|
static void stat2proc(const char* S, proc_t *restrict P) {
|
1970-01-01 05:30:00 +05:30
|
|
|
size_t num;
|
2002-12-03 14:37:59 +05:30
|
|
|
char* tmp;
|
|
|
|
|
2003-02-17 06:27:15 +05:30
|
|
|
ENTER(0x160);
|
|
|
|
|
2002-02-02 04:17:29 +05:30
|
|
|
/* fill in default values for older kernels */
|
|
|
|
P->processor = 0;
|
2002-10-03 15:11:57 +05:30
|
|
|
P->rtprio = -1;
|
|
|
|
P->sched = -1;
|
2003-12-13 22:21:40 +05:30
|
|
|
P->nlwp = 0;
|
2002-12-03 14:37:59 +05:30
|
|
|
|
1970-01-01 05:30:00 +05:30
|
|
|
S = strchr(S, '(');
|
|
|
|
if(unlikely(!S)) return;
|
|
|
|
S++;
|
2002-12-21 11:52:00 +05:30
|
|
|
tmp = strrchr(S, ')');
|
1970-01-01 05:30:00 +05:30
|
|
|
if(unlikely(!tmp)) return;
|
|
|
|
if(unlikely(!tmp[1])) return;
|
2002-12-03 14:37:59 +05:30
|
|
|
num = tmp - S;
|
2002-12-07 14:04:03 +05:30
|
|
|
if(unlikely(num >= sizeof P->cmd)) num = sizeof P->cmd - 1;
|
2002-12-03 14:37:59 +05:30
|
|
|
memcpy(P->cmd, S, num);
|
|
|
|
P->cmd[num] = '\0';
|
|
|
|
S = tmp + 2; // skip ") "
|
|
|
|
|
1970-01-01 05:30:00 +05:30
|
|
|
sscanf(S,
|
2002-02-02 04:17:29 +05:30
|
|
|
"%c "
|
|
|
|
"%d %d %d %d %d "
|
2002-05-28 09:48:55 +05:30
|
|
|
"%lu %lu %lu %lu %lu "
|
2016-03-03 16:13:52 +05:30
|
|
|
"%llu %llu %llu %llu " /* utime stime cutime cstime */
|
2003-10-16 09:00:41 +05:30
|
|
|
"%ld %ld "
|
|
|
|
"%d "
|
|
|
|
"%ld "
|
2016-03-03 16:13:52 +05:30
|
|
|
"%llu " /* start_time */
|
2002-05-28 09:48:55 +05:30
|
|
|
"%lu "
|
2002-02-02 04:17:29 +05:30
|
|
|
"%ld "
|
2003-01-16 13:33:40 +05:30
|
|
|
"%lu %"KLF"u %"KLF"u %"KLF"u %"KLF"u %"KLF"u "
|
2002-02-02 04:17:29 +05:30
|
|
|
"%*s %*s %*s %*s " /* discard, no RT signals & Linux 2.1 used hex */
|
2013-03-26 14:46:43 +05:30
|
|
|
"%"KLF"u %*u %*u "
|
2002-10-03 15:11:57 +05:30
|
|
|
"%d %d "
|
|
|
|
"%lu %lu",
|
2002-02-02 04:17:29 +05:30
|
|
|
&P->state,
|
|
|
|
&P->ppid, &P->pgrp, &P->session, &P->tty, &P->tpgid,
|
2002-05-28 09:48:55 +05:30
|
|
|
&P->flags, &P->min_flt, &P->cmin_flt, &P->maj_flt, &P->cmaj_flt,
|
|
|
|
&P->utime, &P->stime, &P->cutime, &P->cstime,
|
2003-10-16 09:00:41 +05:30
|
|
|
&P->priority, &P->nice,
|
|
|
|
&P->nlwp,
|
2004-04-17 08:43:56 +05:30
|
|
|
&P->alarm,
|
2002-05-28 09:48:55 +05:30
|
|
|
&P->start_time,
|
|
|
|
&P->vsize,
|
2002-02-02 04:17:29 +05:30
|
|
|
&P->rss,
|
|
|
|
&P->rss_rlim, &P->start_code, &P->end_code, &P->start_stack, &P->kstk_esp, &P->kstk_eip,
|
|
|
|
/* P->signal, P->blocked, P->sigignore, P->sigcatch, */ /* can't use */
|
2004-04-13 09:26:52 +05:30
|
|
|
&P->wchan, /* &P->nswap, &P->cnswap, */ /* nswap and cnswap dead for 2.4.xx and up */
|
2002-02-02 04:17:29 +05:30
|
|
|
/* -- Linux 2.0.35 ends here -- */
|
2002-10-03 15:11:57 +05:30
|
|
|
&P->exit_signal, &P->processor, /* 2.2.1 ends with "exit_signal" */
|
|
|
|
/* -- Linux 2.2.8 to 2.5.17 end here -- */
|
|
|
|
&P->rtprio, &P->sched /* both added to 2.5.18 */
|
2002-02-02 04:17:29 +05:30
|
|
|
);
|
2003-12-13 22:21:40 +05:30
|
|
|
|
|
|
|
if(!P->nlwp){
|
|
|
|
P->nlwp = 1;
|
|
|
|
}
|
|
|
|
|
2003-02-17 06:27:15 +05:30
|
|
|
LEAVE(0x160);
|
2002-02-02 04:17:29 +05:30
|
|
|
}
|
|
|
|
|
2003-02-17 06:27:15 +05:30
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2002-11-25 15:46:33 +05:30
|
|
|
static void statm2proc(const char* s, proc_t *restrict P) {
|
2017-05-13 10:31:00 +05:30
|
|
|
sscanf(s, "%ld %ld %ld %ld %ld %ld %ld",
|
2002-02-02 04:17:29 +05:30
|
|
|
&P->size, &P->resident, &P->share,
|
|
|
|
&P->trs, &P->lrs, &P->drs, &P->dt);
|
|
|
|
}
|
|
|
|
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
static int file2str(const char *directory, const char *what, struct utlbuf_s *ub) {
|
2013-04-14 10:30:00 +05:30
|
|
|
#define buffGRW 1024
|
|
|
|
char path[PROCPATHLEN];
|
1970-01-01 05:30:00 +05:30
|
|
|
int fd, num, tot_read = 0, len;
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
|
|
|
|
/* on first use we preallocate a buffer of minimum size to emulate
|
|
|
|
former 'local static' behavior -- even if this read fails, that
|
2013-04-14 10:30:00 +05:30
|
|
|
buffer will likely soon be used for another subdirectory anyway
|
|
|
|
( besides, with this xcalloc we will never need to use memcpy ) */
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
if (ub->buf) ub->buf[0] = '\0';
|
2013-04-14 10:30:00 +05:30
|
|
|
else ub->buf = xcalloc((ub->siz = buffGRW));
|
1970-01-01 05:30:00 +05:30
|
|
|
len = snprintf(path, sizeof path, "%s/%s", directory, what);
|
|
|
|
if (len <= 0 || (size_t)len >= sizeof path) return -1;
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
if (-1 == (fd = open(path, O_RDONLY, 0))) return -1;
|
2013-04-14 10:30:00 +05:30
|
|
|
while (0 < (num = read(fd, ub->buf + tot_read, ub->siz - tot_read))) {
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
tot_read += num;
|
2013-04-14 10:30:00 +05:30
|
|
|
if (tot_read < ub->siz) break;
|
1970-01-01 05:30:00 +05:30
|
|
|
if (ub->siz >= INT_MAX - buffGRW) {
|
|
|
|
tot_read--;
|
|
|
|
break;
|
|
|
|
}
|
2013-04-14 10:30:00 +05:30
|
|
|
ub->buf = xrealloc(ub->buf, (ub->siz += buffGRW));
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
};
|
|
|
|
ub->buf[tot_read] = '\0';
|
2002-02-02 04:17:29 +05:30
|
|
|
close(fd);
|
2013-03-30 10:30:00 +05:30
|
|
|
if (unlikely(tot_read < 1)) return -1;
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
return tot_read;
|
2013-03-29 10:30:00 +05:30
|
|
|
#undef buffGRW
|
2002-02-02 04:17:29 +05:30
|
|
|
}
|
|
|
|
|
2002-10-12 09:55:57 +05:30
|
|
|
static char** file2strvec(const char* directory, const char* what) {
|
2002-02-02 04:17:29 +05:30
|
|
|
char buf[2048]; /* read buf bytes at a time */
|
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).
1970-01-01 05:30:00 +05:30
|
|
|
char *p, *rbuf = 0, *endbuf, **q, **ret, *strp;
|
2002-02-02 04:17:29 +05:30
|
|
|
int fd, tot = 0, n, c, end_of_file = 0;
|
|
|
|
int align;
|
|
|
|
|
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).
1970-01-01 05:30:00 +05:30
|
|
|
const int len = snprintf(buf, sizeof buf, "%s/%s", directory, what);
|
|
|
|
if(len <= 0 || (size_t)len >= sizeof buf) return NULL;
|
2002-12-03 14:37:59 +05:30
|
|
|
fd = open(buf, O_RDONLY, 0);
|
|
|
|
if(fd==-1) return NULL;
|
2002-02-02 04:17:29 +05:30
|
|
|
|
|
|
|
/* read whole file into a memory buffer, allocating as we go */
|
2010-12-16 14:54:44 +05:30
|
|
|
while ((n = read(fd, buf, sizeof buf - 1)) >= 0) {
|
2002-10-14 02:02:09 +05:30
|
|
|
if (n < (int)(sizeof buf - 1))
|
2002-02-02 04:17:29 +05:30
|
|
|
end_of_file = 1;
|
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).
1970-01-01 05:30:00 +05:30
|
|
|
if (n <= 0 && tot <= 0) { /* nothing read now, nothing read before */
|
|
|
|
break; /* process died between our open and read */
|
2010-12-16 14:54:44 +05:30
|
|
|
}
|
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).
1970-01-01 05:30:00 +05:30
|
|
|
/* ARG_LEN is our guesstimated median length of a command-line argument
|
|
|
|
or environment variable (the minimum is 1, the maximum is 131072) */
|
|
|
|
#define ARG_LEN 64
|
|
|
|
if (tot >= INT_MAX / (ARG_LEN + (int)sizeof(char*)) * ARG_LEN - n) {
|
|
|
|
end_of_file = 1; /* integer overflow: null-terminate and break */
|
|
|
|
n = 0; /* but tot > 0 */
|
2002-02-02 04:17:29 +05:30
|
|
|
}
|
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).
1970-01-01 05:30:00 +05:30
|
|
|
#undef ARG_LEN
|
|
|
|
if (end_of_file &&
|
|
|
|
((n > 0 && buf[n-1] != '\0') || /* last read char not null */
|
2018-07-23 18:14:52 +05:30
|
|
|
(n <= 0 && rbuf && rbuf[tot-1] != '\0'))) /* last read char not null */
|
2002-02-02 04:17:29 +05:30
|
|
|
buf[n++] = '\0'; /* so append null-terminator */
|
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).
1970-01-01 05:30:00 +05:30
|
|
|
|
|
|
|
if (n <= 0) break; /* unneeded (end_of_file = 1) but avoid realloc */
|
2002-02-02 04:17:29 +05:30
|
|
|
rbuf = xrealloc(rbuf, tot + n); /* allocate more memory */
|
|
|
|
memcpy(rbuf + tot, buf, n); /* copy buffer into it */
|
|
|
|
tot += n; /* increment total byte ctr */
|
|
|
|
if (end_of_file)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
close(fd);
|
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).
1970-01-01 05:30:00 +05:30
|
|
|
if (n < 0 || tot <= 0) { /* error, or nothing read */
|
2002-02-02 04:17:29 +05:30
|
|
|
if (rbuf) free(rbuf);
|
|
|
|
return NULL; /* read error */
|
|
|
|
}
|
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).
1970-01-01 05:30:00 +05:30
|
|
|
rbuf[tot-1] = '\0'; /* belt and suspenders (the while loop did it, too) */
|
2002-02-02 04:17:29 +05:30
|
|
|
endbuf = rbuf + tot; /* count space for pointers */
|
|
|
|
align = (sizeof(char*)-1) - ((tot + sizeof(char*)-1) & (sizeof(char*)-1));
|
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).
1970-01-01 05:30:00 +05:30
|
|
|
c = sizeof(char*); /* one extra for NULL term */
|
|
|
|
for (p = rbuf; p < endbuf; p++) {
|
|
|
|
if (!*p || *p == '\n') {
|
|
|
|
if (c >= INT_MAX - (tot + (int)sizeof(char*) + align)) break;
|
2002-02-02 04:17:29 +05:30
|
|
|
c += sizeof(char*);
|
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).
1970-01-01 05:30:00 +05:30
|
|
|
}
|
2011-01-19 16:46:56 +05:30
|
|
|
if (*p == '\n')
|
|
|
|
*p = 0;
|
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
|
|
|
|
rbuf = xrealloc(rbuf, tot + c + align); /* make room for ptrs AT END */
|
|
|
|
endbuf = rbuf + tot; /* addr just past data buf */
|
|
|
|
q = ret = (char**) (endbuf+align); /* ==> free(*ret) to dealloc */
|
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).
1970-01-01 05:30:00 +05:30
|
|
|
for (strp = p = rbuf; p < endbuf; p++) {
|
|
|
|
if (!*p) { /* NUL char implies that */
|
|
|
|
if (c < 2 * (int)sizeof(char*)) break;
|
|
|
|
c -= sizeof(char*);
|
|
|
|
*q++ = strp; /* point ptrs to the strings */
|
|
|
|
strp = p+1; /* next string -> next char */
|
|
|
|
}
|
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
*q = 0; /* null ptr list terminator */
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-05-18 14:03:44 +05:30
|
|
|
// this is the former under utilized 'read_cmdline', which has been
|
|
|
|
// generalized in support of these new libproc flags:
|
2012-07-01 10:30:11 +05:30
|
|
|
// PROC_EDITCGRPCVT, PROC_EDITCMDLCVT and PROC_EDITENVRCVT
|
2011-08-11 03:12:14 +05:30
|
|
|
static int read_unvectored(char *restrict const dst, unsigned sz, const char* whom, const char *what, char sep) {
|
|
|
|
char path[PROCPATHLEN];
|
1970-01-01 05:30:00 +05:30
|
|
|
int fd, len;
|
2002-12-03 14:48:27 +05:30
|
|
|
unsigned n = 0;
|
2011-05-18 14:03:44 +05:30
|
|
|
|
1970-01-01 05:30:00 +05:30
|
|
|
if(sz <= 0) return 0;
|
|
|
|
if(sz >= INT_MAX) sz = INT_MAX-1;
|
|
|
|
dst[0] = '\0';
|
|
|
|
|
|
|
|
len = snprintf(path, sizeof(path), "%s/%s", whom, what);
|
|
|
|
if(len <= 0 || (size_t)len >= sizeof(path)) return 0;
|
2011-08-11 03:12:14 +05:30
|
|
|
fd = open(path, O_RDONLY);
|
2002-12-03 14:48:27 +05:30
|
|
|
if(fd==-1) return 0;
|
2011-08-11 03:12:14 +05:30
|
|
|
|
2002-12-03 14:37:59 +05:30
|
|
|
for(;;){
|
|
|
|
ssize_t r = read(fd,dst+n,sz-n);
|
|
|
|
if(r==-1){
|
|
|
|
if(errno==EINTR) continue;
|
|
|
|
break;
|
|
|
|
}
|
1970-01-01 05:30:00 +05:30
|
|
|
if(r<=0) break; // EOF
|
2002-12-03 14:37:59 +05:30
|
|
|
n += r;
|
2011-05-18 14:03:44 +05:30
|
|
|
if(n==sz) { // filled the buffer
|
|
|
|
--n; // make room for '\0'
|
|
|
|
break;
|
|
|
|
}
|
2002-12-03 14:37:59 +05:30
|
|
|
}
|
2002-12-28 15:07:42 +05:30
|
|
|
close(fd);
|
2002-12-03 14:37:59 +05:30
|
|
|
if(n){
|
1970-01-01 05:30:00 +05:30
|
|
|
unsigned i = n;
|
2014-01-24 22:37:34 +05:30
|
|
|
while(i && dst[i-1]=='\0') --i; // skip trailing zeroes
|
2011-05-18 14:03:44 +05:30
|
|
|
while(i--)
|
|
|
|
if(dst[i]=='\n' || dst[i]=='\0') dst[i]=sep;
|
2011-12-11 23:30:50 +05:30
|
|
|
if(dst[n-1]==' ') dst[n-1]='\0';
|
2002-12-03 14:37:59 +05:30
|
|
|
}
|
2011-05-18 14:03:44 +05:30
|
|
|
dst[n] = '\0';
|
2002-12-03 14:37:59 +05:30
|
|
|
return n;
|
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
|
2011-05-18 14:03:44 +05:30
|
|
|
static char** vectorize_this_str (const char* src) {
|
|
|
|
#define pSZ (sizeof(char*))
|
|
|
|
char *cpy, **vec;
|
1970-01-01 05:30:00 +05:30
|
|
|
size_t adj, tot;
|
2011-05-18 14:03:44 +05:30
|
|
|
|
|
|
|
tot = strlen(src) + 1; // prep for our vectors
|
1970-01-01 05:30:00 +05:30
|
|
|
if (tot < 1 || tot >= INT_MAX) tot = INT_MAX-1; // integer overflow?
|
2011-05-18 14:03:44 +05:30
|
|
|
adj = (pSZ-1) - ((tot + pSZ-1) & (pSZ-1)); // calc alignment bytes
|
2011-12-03 04:47:02 +05:30
|
|
|
cpy = xcalloc(tot + adj + (2 * pSZ)); // get new larger buffer
|
2011-05-18 14:03:44 +05:30
|
|
|
snprintf(cpy, tot, "%s", src); // duplicate their string
|
|
|
|
vec = (char**)(cpy + tot + adj); // prep pointer to pointers
|
|
|
|
*vec = cpy; // point 1st vector to string
|
|
|
|
*(vec+1) = NULL; // null ptr 'list' delimit
|
|
|
|
return vec; // ==> free(*vec) to dealloc
|
|
|
|
#undef pSZ
|
|
|
|
}
|
|
|
|
|
2011-08-11 03:12:14 +05:30
|
|
|
// This routine reads a 'cgroup' for the designated proc_t.
|
2011-05-18 14:03:44 +05:30
|
|
|
// It is similar to file2strvec except we filter and concatenate
|
|
|
|
// the data into a single string represented as a single vector.
|
2011-08-11 03:12:14 +05:30
|
|
|
static void fill_cgroup_cvt (const char* directory, proc_t *restrict p) {
|
2012-06-30 10:29:59 +05:30
|
|
|
#define vMAX ( MAX_BUFSZ - (int)(dst - dst_buffer) )
|
2016-07-03 10:30:00 +05:30
|
|
|
char *src, *dst, *grp, *eob, *name;
|
1970-01-01 05:30:00 +05:30
|
|
|
int tot, x, whackable_int = MAX_BUFSZ, len;
|
2011-05-18 14:03:44 +05:30
|
|
|
|
2012-06-30 10:29:59 +05:30
|
|
|
*(dst = dst_buffer) = '\0'; // empty destination
|
|
|
|
tot = read_unvectored(src_buffer, MAX_BUFSZ, directory, "cgroup", '\0');
|
|
|
|
for (src = src_buffer, eob = src_buffer + tot; src < eob; src += x) {
|
2011-05-18 14:03:44 +05:30
|
|
|
x = 1; // loop assist
|
|
|
|
if (!*src) continue;
|
|
|
|
x = strlen((grp = src));
|
|
|
|
if ('/' == grp[x - 1]) continue; // skip empty root cgroups
|
|
|
|
#if 0
|
|
|
|
grp += strspn(grp, "0123456789:"); // jump past group number
|
|
|
|
#endif
|
1970-01-01 05:30:00 +05:30
|
|
|
if (vMAX <= 1) break;
|
|
|
|
len = snprintf(dst, vMAX, "%s", (dst > dst_buffer) ? "," : "");
|
|
|
|
if (len < 0 || len >= vMAX) break;
|
|
|
|
dst += len;
|
2011-05-18 14:03:44 +05:30
|
|
|
dst += escape_str(dst, grp, vMAX, &whackable_int);
|
|
|
|
}
|
2012-06-30 10:29:59 +05:30
|
|
|
p->cgroup = vectorize_this_str(dst_buffer[0] ? dst_buffer : "-");
|
2016-07-03 10:30:00 +05:30
|
|
|
|
|
|
|
name = strstr(p->cgroup[0], ":name=");
|
|
|
|
if (name && *(name+6)) name += 6; else name = p->cgroup[0];
|
|
|
|
p->cgname = strdup(name);
|
2011-05-05 15:37:25 +05:30
|
|
|
#undef vMAX
|
|
|
|
}
|
|
|
|
|
2011-08-11 03:12:14 +05:30
|
|
|
// This routine reads a 'cmdline' for the designated proc_t, "escapes"
|
|
|
|
// the result into a single string represented as a single vector
|
|
|
|
// and guarantees the caller a valid proc_t.cmdline pointer.
|
|
|
|
static void fill_cmdline_cvt (const char* directory, proc_t *restrict p) {
|
2011-05-18 14:03:44 +05:30
|
|
|
#define uFLG ( ESC_BRACKETS | ESC_DEFUNCT )
|
2011-12-02 15:17:19 +05:30
|
|
|
int whackable_int = MAX_BUFSZ;
|
2011-05-18 14:03:44 +05:30
|
|
|
|
2011-12-02 15:17:19 +05:30
|
|
|
if (read_unvectored(src_buffer, MAX_BUFSZ, directory, "cmdline", ' '))
|
|
|
|
escape_str(dst_buffer, src_buffer, MAX_BUFSZ, &whackable_int);
|
2011-05-18 14:03:44 +05:30
|
|
|
else
|
2011-12-02 15:17:19 +05:30
|
|
|
escape_command(dst_buffer, p, MAX_BUFSZ, &whackable_int, uFLG);
|
|
|
|
p->cmdline = vectorize_this_str(dst_buffer);
|
2011-05-18 14:03:44 +05:30
|
|
|
#undef uFLG
|
|
|
|
}
|
|
|
|
|
2012-07-01 10:30:11 +05:30
|
|
|
// This routine reads an 'environ' for the designated proc_t and
|
|
|
|
// guarantees the caller a valid proc_t.environ pointer.
|
|
|
|
static void fill_environ_cvt (const char* directory, proc_t *restrict p) {
|
|
|
|
int whackable_int = MAX_BUFSZ;
|
|
|
|
|
|
|
|
dst_buffer[0] = '\0';
|
|
|
|
if (read_unvectored(src_buffer, MAX_BUFSZ, directory, "environ", ' '))
|
|
|
|
escape_str(dst_buffer, src_buffer, MAX_BUFSZ, &whackable_int);
|
|
|
|
p->environ = vectorize_this_str(dst_buffer[0] ? dst_buffer : "-");
|
|
|
|
}
|
|
|
|
|
2011-05-18 14:03:44 +05:30
|
|
|
// warning: interface may change
|
|
|
|
int read_cmdline(char *restrict const dst, unsigned sz, unsigned pid) {
|
2011-08-11 03:12:14 +05:30
|
|
|
char path[PROCPATHLEN];
|
|
|
|
snprintf(path, sizeof(path), "/proc/%u", pid);
|
|
|
|
return read_unvectored(dst, sz, path, "cmdline", ' ');
|
2011-05-18 14:03:44 +05:30
|
|
|
}
|
|
|
|
|
2011-05-05 15:37:25 +05:30
|
|
|
|
2015-06-13 10:30:00 +05:30
|
|
|
// Provide the means to value proc_t.lxcname (perhaps only with "-") while
|
|
|
|
// tracking all names already seen thus avoiding the overhead of repeating
|
|
|
|
// malloc() and free() calls.
|
|
|
|
static const char *lxc_containers (const char *path) {
|
|
|
|
static struct utlbuf_s ub = { NULL, 0 }; // util buffer for whole cgroup
|
|
|
|
static char lxc_none[] = "-";
|
|
|
|
/*
|
|
|
|
try to locate the lxc delimiter eyecatcher somewhere in a task's cgroup
|
|
|
|
directory -- the following are from nested privileged plus unprivileged
|
|
|
|
containers, where the '/lxc/' delimiter precedes the container name ...
|
|
|
|
10:cpuset:/lxc/lxc-P/lxc/lxc-P-nested
|
|
|
|
10:cpuset:/user.slice/user-1000.slice/session-c2.scope/lxc/lxc-U/lxc/lxc-U-nested
|
|
|
|
|
|
|
|
... some minor complications are the potential addition of more cgroups
|
|
|
|
for a controller displacing the lxc name (normally last on a line), and
|
|
|
|
environments with unexpected /proc/##/cgroup ordering/contents as with:
|
|
|
|
10:cpuset:/lxc/lxc-P/lxc/lxc-P-nested/MY-NEW-CGROUP
|
|
|
|
or
|
|
|
|
2:name=systemd:/
|
|
|
|
1:cpuset,cpu,cpuacct,devices,freezer,net_cls,blkio,perf_event,net_prio:/lxc/lxc-P
|
|
|
|
*/
|
|
|
|
if (file2str(path, "cgroup", &ub) > 0) {
|
2020-04-14 10:30:00 +05:30
|
|
|
/* ouch, the next defaults could be changed at lxc ./configure time
|
2019-01-10 11:30:00 +05:30
|
|
|
( and a changed 'lxc.cgroup.pattern' is only available to root ) */
|
2020-04-14 10:30:00 +05:30
|
|
|
static const char *lxc_delm1 = "lxc.payload."; // with lxc-4.0.0
|
|
|
|
static const char *lxc_delm2 = "lxc.payload/"; // thru lxc-3.2.1
|
|
|
|
static const char *lxc_delm3 = "lxc/"; // thru lxc-3.0.3
|
2019-01-10 11:30:00 +05:30
|
|
|
const char *delim;
|
2015-06-13 10:30:00 +05:30
|
|
|
char *p1;
|
|
|
|
|
2019-01-10 11:30:00 +05:30
|
|
|
if ((p1 = strstr(ub.buf, (delim = lxc_delm1)))
|
2020-04-14 10:30:00 +05:30
|
|
|
|| ((p1 = strstr(ub.buf, (delim = lxc_delm2)))
|
|
|
|
|| ((p1 = strstr(ub.buf, (delim = lxc_delm3)))))) {
|
2015-06-13 10:30:00 +05:30
|
|
|
static struct lxc_ele {
|
|
|
|
struct lxc_ele *next;
|
|
|
|
const char *name;
|
|
|
|
} *anchor = NULL;
|
|
|
|
struct lxc_ele *ele = anchor;
|
2019-01-10 11:30:00 +05:30
|
|
|
int delim_len = strlen(delim);
|
2015-06-13 10:30:00 +05:30
|
|
|
char *p2;
|
|
|
|
|
|
|
|
if ((p2 = strchr(p1, '\n'))) // isolate a controller's line
|
|
|
|
*p2 = '\0';
|
|
|
|
do { // deal with nested containers
|
2019-02-13 11:30:00 +05:30
|
|
|
p2 = p1 + delim_len;
|
2019-01-10 11:30:00 +05:30
|
|
|
p1 = strstr(p2, delim);
|
2015-06-13 10:30:00 +05:30
|
|
|
} while (p1);
|
|
|
|
if ((p1 = strchr(p2, '/'))) // isolate name only substring
|
|
|
|
*p1 = '\0';
|
|
|
|
while (ele) { // have we already seen a name
|
|
|
|
if (!strcmp(ele->name, p2))
|
|
|
|
return ele->name; // return just a recycled name
|
|
|
|
ele = ele->next;
|
|
|
|
}
|
|
|
|
ele = (struct lxc_ele *)xmalloc(sizeof(struct lxc_ele));
|
|
|
|
ele->name = xstrdup(p2);
|
|
|
|
ele->next = anchor; // push the new container name
|
|
|
|
anchor = ele;
|
|
|
|
return ele->name; // return a new container name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return lxc_none;
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
2002-02-02 04:17:29 +05:30
|
|
|
/* These are some nice GNU C expression subscope "inline" functions.
|
|
|
|
* The can be used with arbitrary types and evaluate their arguments
|
|
|
|
* exactly once.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Test if item X of type T is present in the 0 terminated list L */
|
|
|
|
# define XinL(T, X, L) ( { \
|
|
|
|
T x = (X), *l = (L); \
|
|
|
|
while (*l && *l != x) l++; \
|
|
|
|
*l == x; \
|
|
|
|
} )
|
|
|
|
|
|
|
|
/* Test if item X of type T is present in the list L of length N */
|
|
|
|
# define XinLN(T, X, L, N) ( { \
|
|
|
|
T x = (X), *l = (L); \
|
|
|
|
int i = 0, n = (N); \
|
|
|
|
while (i < n && l[i] != x) i++; \
|
|
|
|
i < n && l[i] == x; \
|
|
|
|
} )
|
|
|
|
|
2003-09-18 03:28:32 +05:30
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// This reads process info from /proc in the traditional way, for one process.
|
|
|
|
// The pid (tgid? tid?) is already in p, and a path to it in path, with some
|
|
|
|
// room to spare.
|
2003-09-20 13:59:55 +05:30
|
|
|
static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict const p) {
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
static struct utlbuf_s ub = { NULL, 0 }; // buf for stat,statm,status
|
2011-08-01 16:58:46 +05:30
|
|
|
static struct stat sb; // stat() buffer
|
2003-09-20 13:59:55 +05:30
|
|
|
char *restrict const path = PT->path;
|
2003-09-18 03:28:32 +05:30
|
|
|
unsigned flags = PT->flags;
|
2002-02-02 04:17:29 +05:30
|
|
|
|
2011-08-01 16:58:46 +05:30
|
|
|
if (unlikely(stat(path, &sb) == -1)) /* no such dirent (anymore) */
|
|
|
|
goto next_proc;
|
2002-09-27 19:18:00 +05:30
|
|
|
|
2002-10-22 11:42:12 +05:30
|
|
|
if ((flags & PROC_UID) && !XinLN(uid_t, sb.st_uid, PT->uids, PT->nuid))
|
2011-08-01 16:58:46 +05:30
|
|
|
goto next_proc; /* not one of the requested uids */
|
2002-02-02 04:17:29 +05:30
|
|
|
|
2011-08-01 16:58:46 +05:30
|
|
|
p->euid = sb.st_uid; /* need a way to get real uid */
|
|
|
|
p->egid = sb.st_gid; /* need a way to get real gid */
|
2002-09-27 19:18:00 +05:30
|
|
|
|
2011-08-01 16:58:46 +05:30
|
|
|
if (flags & PROC_FILLSTAT) { // read /proc/#/stat
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
if (unlikely(file2str(path, "stat", &ub) == -1))
|
2011-08-01 16:58:46 +05:30
|
|
|
goto next_proc;
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
stat2proc(ub.buf, p);
|
2002-12-09 00:21:56 +05:30
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
|
2011-08-01 16:58:46 +05:30
|
|
|
if (flags & PROC_FILLMEM) { // read /proc/#/statm
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
if (likely(file2str(path, "statm", &ub) != -1))
|
|
|
|
statm2proc(ub.buf, p);
|
2011-08-01 16:58:46 +05:30
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
|
2011-08-01 16:58:46 +05:30
|
|
|
if (flags & PROC_FILLSTATUS) { // read /proc/#/status
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
if (likely(file2str(path, "status", &ub) != -1)){
|
|
|
|
status2proc(ub.buf, p, 1);
|
2011-08-01 16:58:46 +05:30
|
|
|
if (flags & PROC_FILLSUPGRP)
|
|
|
|
supgrps_from_supgids(p);
|
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
}
|
|
|
|
|
2004-07-22 02:47:35 +05:30
|
|
|
// if multithreaded, some values are crap
|
|
|
|
if(p->nlwp > 1){
|
|
|
|
p->wchan = (KLONG)~0ull;
|
|
|
|
}
|
|
|
|
|
2011-08-01 16:58:46 +05:30
|
|
|
/* some number->text resolving which is time consuming */
|
2002-10-22 11:42:12 +05:30
|
|
|
if (flags & PROC_FILLUSR){
|
2016-06-18 03:47:45 +05:30
|
|
|
memcpy(p->euser, pwcache_get_user(p->euid), sizeof p->euser);
|
2002-10-22 11:42:12 +05:30
|
|
|
if(flags & PROC_FILLSTATUS) {
|
2016-06-18 03:47:45 +05:30
|
|
|
memcpy(p->ruser, pwcache_get_user(p->ruid), sizeof p->ruser);
|
|
|
|
memcpy(p->suser, pwcache_get_user(p->suid), sizeof p->suser);
|
|
|
|
memcpy(p->fuser, pwcache_get_user(p->fuid), sizeof p->fuser);
|
2002-10-02 17:40:39 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-01 16:58:46 +05:30
|
|
|
/* some number->text resolving which is time consuming */
|
2002-10-22 11:42:12 +05:30
|
|
|
if (flags & PROC_FILLGRP){
|
2016-06-18 03:47:45 +05:30
|
|
|
memcpy(p->egroup, pwcache_get_group(p->egid), sizeof p->egroup);
|
2002-10-22 11:42:12 +05:30
|
|
|
if(flags & PROC_FILLSTATUS) {
|
2016-06-18 03:47:45 +05:30
|
|
|
memcpy(p->rgroup, pwcache_get_group(p->rgid), sizeof p->rgroup);
|
|
|
|
memcpy(p->sgroup, pwcache_get_group(p->sgid), sizeof p->sgroup);
|
|
|
|
memcpy(p->fgroup, pwcache_get_group(p->fgid), sizeof p->fgroup);
|
2002-02-02 04:17:29 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-01 10:30:11 +05:30
|
|
|
if (unlikely(flags & PROC_FILLENV)) { // read /proc/#/environ
|
|
|
|
if (flags & PROC_EDITENVRCVT)
|
|
|
|
fill_environ_cvt(path, p);
|
|
|
|
else
|
|
|
|
p->environ = file2strvec(path, "environ");
|
2016-07-03 10:30:00 +05:30
|
|
|
}
|
2011-05-18 14:03:44 +05:30
|
|
|
|
2011-08-01 16:58:46 +05:30
|
|
|
if (flags & (PROC_FILLCOM|PROC_FILLARG)) { // read /proc/#/cmdline
|
2011-05-18 14:03:44 +05:30
|
|
|
if (flags & PROC_EDITCMDLCVT)
|
2011-08-11 03:12:14 +05:30
|
|
|
fill_cmdline_cvt(path, p);
|
2011-05-18 14:03:44 +05:30
|
|
|
else
|
|
|
|
p->cmdline = file2strvec(path, "cmdline");
|
2016-07-03 10:30:00 +05:30
|
|
|
}
|
2002-10-02 17:40:39 +05:30
|
|
|
|
2012-06-28 10:30:01 +05:30
|
|
|
if ((flags & PROC_FILLCGROUP)) { // read /proc/#/cgroup
|
2011-05-18 14:03:44 +05:30
|
|
|
if (flags & PROC_EDITCGRPCVT)
|
2011-08-11 03:12:14 +05:30
|
|
|
fill_cgroup_cvt(path, p);
|
2011-05-18 14:03:44 +05:30
|
|
|
else
|
|
|
|
p->cgroup = file2strvec(path, "cgroup");
|
2016-07-03 10:30:00 +05:30
|
|
|
}
|
2011-05-18 14:03:44 +05:30
|
|
|
|
2011-04-15 19:22:40 +05:30
|
|
|
if (unlikely(flags & PROC_FILLOOM)) {
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
if (likely(file2str(path, "oom_score", &ub) != -1))
|
|
|
|
oomscore2proc(ub.buf, p);
|
|
|
|
if (likely(file2str(path, "oom_adj", &ub) != -1))
|
|
|
|
oomadj2proc(ub.buf, p);
|
2011-05-18 14:03:44 +05:30
|
|
|
}
|
2011-05-05 15:37:25 +05:30
|
|
|
|
2013-11-10 11:30:00 +05:30
|
|
|
if (unlikely(flags & PROC_FILLNS)) // read /proc/#/ns/*
|
|
|
|
ns2proc(path, p);
|
2013-04-09 00:33:13 +05:30
|
|
|
|
2014-06-28 10:30:22 +05:30
|
|
|
if (unlikely(flags & PROC_FILLSYSTEMD)) // get sd-login.h stuff
|
|
|
|
sd2proc(p);
|
2015-06-13 10:30:00 +05:30
|
|
|
|
|
|
|
if (unlikely(flags & PROC_FILL_LXC)) // value the lxc name
|
|
|
|
p->lxcname = lxc_containers(path);
|
|
|
|
|
2002-02-02 04:17:29 +05:30
|
|
|
return p;
|
2003-09-18 03:28:32 +05:30
|
|
|
next_proc:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2003-09-20 13:59:55 +05:30
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// This reads /proc/*/task/* data, for one task.
|
2011-08-11 03:12:14 +05:30
|
|
|
#ifdef QUICK_THREADS
|
|
|
|
// p is the POSIX process (task group summary) & source for some copies if !NULL
|
|
|
|
#else
|
2003-09-20 13:59:55 +05:30
|
|
|
// p is the POSIX process (task group summary) (not needed by THIS implementation)
|
2011-08-11 03:12:14 +05:30
|
|
|
#endif
|
2003-09-20 13:59:55 +05:30
|
|
|
// t is the POSIX thread (task group member, generally not the leader)
|
|
|
|
// 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) {
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
static struct utlbuf_s ub = { NULL, 0 }; // buf for stat,statm,status
|
2011-08-01 16:58:46 +05:30
|
|
|
static struct stat sb; // stat() buffer
|
2003-09-20 13:59:55 +05:30
|
|
|
unsigned flags = PT->flags;
|
|
|
|
|
2011-08-01 16:58:46 +05:30
|
|
|
if (unlikely(stat(path, &sb) == -1)) /* no such dirent (anymore) */
|
|
|
|
goto next_task;
|
2003-09-20 13:59:55 +05:30
|
|
|
|
2011-08-11 03:12:14 +05:30
|
|
|
// if ((flags & PROC_UID) && !XinLN(uid_t, sb.st_uid, PT->uids, PT->nuid))
|
|
|
|
// goto next_task; /* not one of the requested uids */
|
2003-09-20 13:59:55 +05:30
|
|
|
|
2011-08-01 16:58:46 +05:30
|
|
|
t->euid = sb.st_uid; /* need a way to get real uid */
|
|
|
|
t->egid = sb.st_gid; /* need a way to get real gid */
|
2003-09-20 13:59:55 +05:30
|
|
|
|
2011-08-11 03:12:14 +05:30
|
|
|
if (flags & PROC_FILLSTAT) { // read /proc/#/task/#/stat
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
if (unlikely(file2str(path, "stat", &ub) == -1))
|
2011-08-01 16:58:46 +05:30
|
|
|
goto next_task;
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
stat2proc(ub.buf, t);
|
2003-09-20 13:59:55 +05:30
|
|
|
}
|
|
|
|
|
2011-08-11 03:12:14 +05:30
|
|
|
#ifndef QUICK_THREADS
|
|
|
|
if (flags & PROC_FILLMEM) // read /proc/#/task/#statm
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
if (likely(file2str(path, "statm", &ub) != -1))
|
|
|
|
statm2proc(ub.buf, t);
|
2003-09-28 08:15:05 +05:30
|
|
|
#endif
|
2003-09-20 13:59:55 +05:30
|
|
|
|
2011-08-11 03:12:14 +05:30
|
|
|
if (flags & PROC_FILLSTATUS) { // read /proc/#/task/#/status
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
if (likely(file2str(path, "status", &ub) != -1)) {
|
|
|
|
status2proc(ub.buf, t, 0);
|
2011-08-11 03:12:14 +05:30
|
|
|
#ifndef QUICK_THREADS
|
|
|
|
if (flags & PROC_FILLSUPGRP)
|
|
|
|
supgrps_from_supgids(t);
|
|
|
|
#endif
|
|
|
|
}
|
2003-09-20 13:59:55 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/* some number->text resolving which is time consuming */
|
|
|
|
if (flags & PROC_FILLUSR){
|
2016-06-18 03:47:45 +05:30
|
|
|
memcpy(t->euser, pwcache_get_user(t->euid), sizeof t->euser);
|
2003-09-20 13:59:55 +05:30
|
|
|
if(flags & PROC_FILLSTATUS) {
|
2016-06-18 03:47:45 +05:30
|
|
|
memcpy(t->ruser, pwcache_get_user(t->ruid), sizeof t->ruser);
|
|
|
|
memcpy(t->suser, pwcache_get_user(t->suid), sizeof t->suser);
|
|
|
|
memcpy(t->fuser, pwcache_get_user(t->fuid), sizeof t->fuser);
|
2003-09-20 13:59:55 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* some number->text resolving which is time consuming */
|
|
|
|
if (flags & PROC_FILLGRP){
|
2016-06-18 03:47:45 +05:30
|
|
|
memcpy(t->egroup, pwcache_get_group(t->egid), sizeof t->egroup);
|
2003-09-20 13:59:55 +05:30
|
|
|
if(flags & PROC_FILLSTATUS) {
|
2016-06-18 03:47:45 +05:30
|
|
|
memcpy(t->rgroup, pwcache_get_group(t->rgid), sizeof t->rgroup);
|
|
|
|
memcpy(t->sgroup, pwcache_get_group(t->sgid), sizeof t->sgroup);
|
|
|
|
memcpy(t->fgroup, pwcache_get_group(t->fgid), sizeof t->fgroup);
|
2003-09-20 13:59:55 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-11 03:12:14 +05:30
|
|
|
#ifdef QUICK_THREADS
|
|
|
|
if (!p) {
|
|
|
|
if (flags & PROC_FILLMEM)
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
if (likely(file2str(path, "statm", &ub) != -1))
|
|
|
|
statm2proc(ub.buf, t);
|
2011-08-01 16:58:46 +05:30
|
|
|
|
2011-08-11 03:12:14 +05:30
|
|
|
if (flags & PROC_FILLSUPGRP)
|
|
|
|
supgrps_from_supgids(t);
|
|
|
|
#endif
|
2012-07-01 10:30:11 +05:30
|
|
|
if (unlikely(flags & PROC_FILLENV)) { // read /proc/#/task/#/environ
|
|
|
|
if (flags & PROC_EDITENVRCVT)
|
|
|
|
fill_environ_cvt(path, t);
|
|
|
|
else
|
|
|
|
t->environ = file2strvec(path, "environ");
|
2016-07-03 10:30:00 +05:30
|
|
|
}
|
2003-09-20 13:59:55 +05:30
|
|
|
|
2011-08-11 03:12:14 +05:30
|
|
|
if (flags & (PROC_FILLCOM|PROC_FILLARG)) { // read /proc/#/task/#/cmdline
|
|
|
|
if (flags & PROC_EDITCMDLCVT)
|
|
|
|
fill_cmdline_cvt(path, t);
|
|
|
|
else
|
|
|
|
t->cmdline = file2strvec(path, "cmdline");
|
2016-07-03 10:30:00 +05:30
|
|
|
}
|
2011-08-11 03:12:14 +05:30
|
|
|
|
2012-06-28 10:30:01 +05:30
|
|
|
if ((flags & PROC_FILLCGROUP)) { // read /proc/#/task/#/cgroup
|
2011-08-11 03:12:14 +05:30
|
|
|
if (flags & PROC_EDITCGRPCVT)
|
|
|
|
fill_cgroup_cvt(path, t);
|
|
|
|
else
|
|
|
|
t->cgroup = file2strvec(path, "cgroup");
|
2016-07-03 10:30:00 +05:30
|
|
|
}
|
2011-08-01 16:58:46 +05:30
|
|
|
|
2014-06-28 10:30:22 +05:30
|
|
|
if (unlikely(flags & PROC_FILLSYSTEMD)) // get sd-login.h stuff
|
|
|
|
sd2proc(t);
|
|
|
|
|
2015-06-13 10:30:00 +05:30
|
|
|
if (unlikely(flags & PROC_FILL_LXC)) // value the lxc name
|
|
|
|
t->lxcname = lxc_containers(path);
|
|
|
|
|
2011-08-11 03:12:14 +05:30
|
|
|
#ifdef QUICK_THREADS
|
|
|
|
} else {
|
|
|
|
t->size = p->size;
|
|
|
|
t->resident = p->resident;
|
|
|
|
t->share = p->share;
|
|
|
|
t->trs = p->trs;
|
|
|
|
t->lrs = p->lrs;
|
|
|
|
t->drs = p->drs;
|
|
|
|
t->dt = p->dt;
|
|
|
|
t->cmdline = p->cmdline; // better not free these until done with all threads!
|
|
|
|
t->environ = p->environ;
|
2016-07-03 10:30:00 +05:30
|
|
|
t->cgname = p->cgname;
|
2011-08-11 03:12:14 +05:30
|
|
|
t->cgroup = p->cgroup;
|
|
|
|
if (t->supgid) free(t->supgid);
|
|
|
|
t->supgid = p->supgid;
|
|
|
|
t->supgrp = p->supgrp;
|
2014-06-28 10:30:22 +05:30
|
|
|
t->sd_mach = p->sd_mach;
|
|
|
|
t->sd_ouid = p->sd_ouid;
|
|
|
|
t->sd_seat = p->sd_seat;
|
|
|
|
t->sd_sess = p->sd_sess;
|
|
|
|
t->sd_slice = p->sd_slice;
|
|
|
|
t->sd_unit = p->sd_unit;
|
|
|
|
t->sd_uunit = p->sd_uunit;
|
2015-06-13 10:30:00 +05:30
|
|
|
t->lxcname = p->lxcname;
|
2011-08-11 03:12:14 +05:30
|
|
|
MK_THREAD(t);
|
|
|
|
}
|
2003-09-20 13:59:55 +05:30
|
|
|
#endif
|
2011-08-01 16:58:46 +05:30
|
|
|
|
2011-08-11 03:12:14 +05:30
|
|
|
if (unlikely(flags & PROC_FILLOOM)) {
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
if (likely(file2str(path, "oom_score", &ub) != -1))
|
|
|
|
oomscore2proc(ub.buf, t);
|
|
|
|
if (likely(file2str(path, "oom_adj", &ub) != -1))
|
|
|
|
oomadj2proc(ub.buf, t);
|
2011-08-11 03:12:14 +05:30
|
|
|
}
|
2013-11-10 11:30:00 +05:30
|
|
|
|
|
|
|
if (unlikely(flags & PROC_FILLNS)) // read /proc/#/task/#/ns/*
|
|
|
|
ns2proc(path, t);
|
2003-09-29 09:39:52 +05:30
|
|
|
|
2003-09-20 13:59:55 +05:30
|
|
|
return t;
|
|
|
|
next_task:
|
|
|
|
return NULL;
|
2011-08-11 03:12:14 +05:30
|
|
|
#ifndef QUICK_THREADS
|
|
|
|
(void)p;
|
|
|
|
#endif
|
2003-09-20 13:59:55 +05:30
|
|
|
}
|
|
|
|
|
2003-09-18 03:28:32 +05:30
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// This finds processes in /proc in the traditional way.
|
|
|
|
// Return non-zero on success.
|
2003-09-20 13:59:55 +05:30
|
|
|
static int simple_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p) {
|
2014-07-06 19:51:01 +05:30
|
|
|
static struct dirent *ent; /* dirent handle */
|
2003-09-20 13:59:55 +05:30
|
|
|
char *restrict const path = PT->path;
|
2003-09-18 03:28:32 +05:30
|
|
|
for (;;) {
|
|
|
|
ent = readdir(PT->procfs);
|
2016-07-03 10:30:00 +05:30
|
|
|
if(unlikely(unlikely(!ent) || unlikely(!ent->d_name[0]))) return 0;
|
2011-08-11 03:12:14 +05:30
|
|
|
if(likely(likely(*ent->d_name > '0') && likely(*ent->d_name <= '9'))) break;
|
2003-09-18 03:28:32 +05:30
|
|
|
}
|
2003-09-20 13:59:55 +05:30
|
|
|
p->tgid = strtoul(ent->d_name, NULL, 10);
|
|
|
|
p->tid = p->tgid;
|
1970-01-01 05:30:00 +05:30
|
|
|
snprintf(path, PROCPATHLEN, "/proc/%s", ent->d_name);
|
2003-09-18 03:28:32 +05:30
|
|
|
return 1;
|
2002-02-02 04:17:29 +05:30
|
|
|
}
|
|
|
|
|
2003-09-20 13:59:55 +05:30
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// This finds tasks in /proc/*/task/ in the traditional way.
|
|
|
|
// Return non-zero on success.
|
|
|
|
static int simple_nexttid(PROCTAB *restrict const PT, const proc_t *restrict const p, proc_t *restrict const t, char *restrict const path) {
|
2014-07-06 19:51:01 +05:30
|
|
|
static struct dirent *ent; /* dirent handle */
|
2003-10-20 05:07:47 +05:30
|
|
|
if(PT->taskdir_user != p->tgid){
|
|
|
|
if(PT->taskdir){
|
|
|
|
closedir(PT->taskdir);
|
|
|
|
}
|
2003-09-20 13:59:55 +05:30
|
|
|
// use "path" as some tmp space
|
2003-10-21 06:21:36 +05:30
|
|
|
snprintf(path, PROCPATHLEN, "/proc/%d/task", p->tgid);
|
2003-09-20 13:59:55 +05:30
|
|
|
PT->taskdir = opendir(path);
|
|
|
|
if(!PT->taskdir) return 0;
|
2003-10-20 05:07:47 +05:30
|
|
|
PT->taskdir_user = p->tgid;
|
2003-09-20 13:59:55 +05:30
|
|
|
}
|
|
|
|
for (;;) {
|
|
|
|
ent = readdir(PT->taskdir);
|
2016-07-03 10:30:00 +05:30
|
|
|
if(unlikely(unlikely(!ent) || unlikely(!ent->d_name[0]))) return 0;
|
2011-08-11 03:12:14 +05:30
|
|
|
if(likely(likely(*ent->d_name > '0') && likely(*ent->d_name <= '9'))) break;
|
2003-09-20 13:59:55 +05:30
|
|
|
}
|
|
|
|
t->tid = strtoul(ent->d_name, NULL, 10);
|
|
|
|
t->tgid = p->tgid;
|
2011-08-11 03:12:14 +05:30
|
|
|
//t->ppid = p->ppid; // cover for kernel behavior? we want both actually...?
|
2003-10-21 06:21:36 +05:30
|
|
|
snprintf(path, PROCPATHLEN, "/proc/%d/task/%s", p->tgid, ent->d_name);
|
2003-09-20 13:59:55 +05:30
|
|
|
return 1;
|
|
|
|
}
|
2003-09-18 03:28:32 +05:30
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// This "finds" processes in a list that was given to openproc().
|
2003-09-20 13:59:55 +05:30
|
|
|
// Return non-zero on success. (tgid was handy)
|
|
|
|
static int listed_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p) {
|
|
|
|
char *restrict const path = PT->path;
|
|
|
|
pid_t tgid = *(PT->pids)++;
|
2011-08-11 03:12:14 +05:30
|
|
|
if(likely(tgid)){
|
2003-09-20 13:59:55 +05:30
|
|
|
snprintf(path, PROCPATHLEN, "/proc/%d", tgid);
|
|
|
|
p->tgid = tgid;
|
|
|
|
p->tid = tgid; // they match for leaders
|
2003-09-18 03:28:32 +05:30
|
|
|
}
|
2003-09-20 13:59:55 +05:30
|
|
|
return tgid;
|
2003-09-18 03:28:32 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
|
|
/* readproc: return a pointer to a proc_t filled with requested info about the
|
2002-02-02 04:17:29 +05:30
|
|
|
* next process available matching the restriction set. If no more such
|
|
|
|
* processes are available, return a null pointer (boolean false). Use the
|
|
|
|
* passed buffer instead of allocating space if it is non-NULL. */
|
|
|
|
|
|
|
|
/* This is optimized so that if a PID list is given, only those files are
|
|
|
|
* searched for in /proc. If other lists are given in addition to the PID list,
|
|
|
|
* the same logic can follow through as for the no-PID list case. This is
|
|
|
|
* fairly complex, but it does try to not to do any unnecessary work.
|
|
|
|
*/
|
2003-09-18 03:28:32 +05:30
|
|
|
proc_t* readproc(PROCTAB *restrict const PT, proc_t *restrict p) {
|
|
|
|
proc_t *ret;
|
|
|
|
proc_t *saved_p;
|
|
|
|
|
2005-01-24 09:07:41 +05:30
|
|
|
PT->did_fake=0;
|
2003-10-20 05:07:47 +05:30
|
|
|
// if (PT->taskdir) {
|
|
|
|
// closedir(PT->taskdir);
|
|
|
|
// PT->taskdir = NULL;
|
|
|
|
// PT->taskdir_user = -1;
|
|
|
|
// }
|
2003-09-20 13:59:55 +05:30
|
|
|
|
2003-09-18 03:28:32 +05:30
|
|
|
saved_p = p;
|
2011-12-03 04:47:02 +05:30
|
|
|
if(!p) p = xcalloc(sizeof *p);
|
2011-08-01 16:58:46 +05:30
|
|
|
else free_acquired(p, 1);
|
2003-09-18 03:28:32 +05:30
|
|
|
|
|
|
|
for(;;){
|
2003-09-20 13:59:55 +05:30
|
|
|
// fills in the path, plus p->tid and p->tgid
|
2011-08-11 03:12:14 +05:30
|
|
|
if (unlikely(!PT->finder(PT,p))) goto out;
|
2003-09-18 03:28:32 +05:30
|
|
|
|
|
|
|
// go read the process data
|
2003-09-20 13:59:55 +05:30
|
|
|
ret = PT->reader(PT,p);
|
2003-09-18 03:28:32 +05:30
|
|
|
if(ret) return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
if(!saved_p) free(p);
|
2003-09-20 13:59:55 +05:30
|
|
|
// FIXME: maybe set tid to -1 here, for "-" in display?
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// readtask: return a pointer to a proc_t filled with requested info about the
|
|
|
|
// next task available. If no more such tasks are available, return a null
|
|
|
|
// pointer (boolean false). Use the passed buffer instead of allocating
|
|
|
|
// space if it is non-NULL.
|
|
|
|
proc_t* readtask(PROCTAB *restrict const PT, const proc_t *restrict const p, proc_t *restrict t) {
|
2011-08-11 03:12:14 +05:30
|
|
|
char path[PROCPATHLEN]; // must hold /proc/2000222000/task/2000222000/cmdline
|
2003-09-20 13:59:55 +05:30
|
|
|
proc_t *ret;
|
|
|
|
proc_t *saved_t;
|
|
|
|
|
|
|
|
saved_t = t;
|
2011-12-03 04:47:02 +05:30
|
|
|
if(!t) t = xcalloc(sizeof *t);
|
2011-08-01 16:58:46 +05:30
|
|
|
else free_acquired(t, 1);
|
2003-09-20 13:59:55 +05:30
|
|
|
|
2003-12-13 22:21:40 +05:30
|
|
|
// 1. got to fake a thread for old kernels
|
2011-08-11 03:12:14 +05:30
|
|
|
#ifdef QUICK_THREADS
|
|
|
|
// 2. for single-threaded processes, this is faster (but must patch up stuff that differs!)
|
|
|
|
if(task_dir_missing || p->nlwp < 2){
|
|
|
|
#else
|
|
|
|
if(task_dir_missing){
|
|
|
|
#endif
|
2003-09-20 13:59:55 +05:30
|
|
|
if(PT->did_fake) goto out;
|
|
|
|
PT->did_fake=1;
|
|
|
|
memcpy(t,p,sizeof(proc_t));
|
2006-06-17 09:44:57 +05:30
|
|
|
// use the per-task pending, not per-tgid pending
|
|
|
|
#ifdef SIGNAL_STRING
|
2011-08-11 03:12:14 +05:30
|
|
|
memcpy(&t->signal, &t->_sigpnd, sizeof t->signal);
|
2006-06-17 09:44:57 +05:30
|
|
|
#else
|
2011-08-11 03:12:14 +05:30
|
|
|
t->signal = t->_sigpnd;
|
2006-06-17 09:44:57 +05:30
|
|
|
#endif
|
2011-08-11 03:12:14 +05:30
|
|
|
#ifdef QUICK_THREADS
|
|
|
|
MK_THREAD(t);
|
|
|
|
#else
|
1970-01-01 05:30:00 +05:30
|
|
|
t->environ = NULL;
|
|
|
|
t->cmdline = vectorize_this_str("n/a");
|
|
|
|
t->cgroup = NULL;
|
|
|
|
t->cgname = NULL;
|
|
|
|
t->supgid = NULL;
|
|
|
|
t->supgrp = NULL;
|
|
|
|
t->sd_mach = NULL;
|
|
|
|
t->sd_ouid = NULL;
|
|
|
|
t->sd_seat = NULL;
|
|
|
|
t->sd_sess = NULL;
|
|
|
|
t->sd_slice = NULL;
|
|
|
|
t->sd_unit = NULL;
|
|
|
|
t->sd_uunit = NULL;
|
2011-08-11 03:12:14 +05:30
|
|
|
#endif
|
2003-09-20 13:59:55 +05:30
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(;;){
|
|
|
|
// fills in the path, plus t->tid and t->tgid
|
2011-08-11 03:12:14 +05:30
|
|
|
if (unlikely(!PT->taskfinder(PT,p,t,path))) goto out; // simple_nexttid
|
2003-09-20 13:59:55 +05:30
|
|
|
|
|
|
|
// go read the task data
|
|
|
|
ret = PT->taskreader(PT,p,t,path); // simple_readtask
|
|
|
|
if(ret) return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
if(!saved_t) free(t);
|
2003-09-18 03:28:32 +05:30
|
|
|
return NULL;
|
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
|
2011-08-11 03:12:14 +05:30
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// readeither: return a pointer to a proc_t filled with requested info about
|
|
|
|
// the next unique process or task available. If no more are available,
|
|
|
|
// return a null pointer (boolean false). Use the passed buffer instead
|
|
|
|
// of allocating space if it is non-NULL.
|
2011-12-06 20:49:11 +05:30
|
|
|
proc_t* readeither (PROCTAB *restrict const PT, proc_t *restrict x) {
|
2011-08-11 03:12:14 +05:30
|
|
|
static proc_t skel_p; // skeleton proc_t, only uses tid + tgid
|
|
|
|
static proc_t *new_p; // for process/task transitions
|
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).
1970-01-01 05:30:00 +05:30
|
|
|
static int canary;
|
2011-08-11 03:12:14 +05:30
|
|
|
char path[PROCPATHLEN];
|
|
|
|
proc_t *saved_x, *ret;
|
|
|
|
|
|
|
|
saved_x = x;
|
2011-12-03 04:47:02 +05:30
|
|
|
if (!x) x = xcalloc(sizeof(*x));
|
2011-08-11 03:12:14 +05:30
|
|
|
else free_acquired(x,1);
|
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).
1970-01-01 05:30:00 +05:30
|
|
|
if (new_p) {
|
|
|
|
if (new_p->tid != canary) new_p = NULL;
|
|
|
|
goto next_task;
|
|
|
|
}
|
2011-08-11 03:12:14 +05:30
|
|
|
|
|
|
|
next_proc:
|
|
|
|
new_p = NULL;
|
|
|
|
for (;;) {
|
|
|
|
// fills in the PT->path, plus skel_p.tid and skel_p.tgid
|
|
|
|
if (!PT->finder(PT,&skel_p)) goto end_procs; // simple_nextpid
|
|
|
|
if (!task_dir_missing) break;
|
|
|
|
if ((ret = PT->reader(PT,x))) return ret; // simple_readproc
|
|
|
|
}
|
|
|
|
|
|
|
|
next_task:
|
2011-10-06 19:04:26 +05:30
|
|
|
// fills in our path, plus x->tid and x->tgid
|
|
|
|
if ((!(PT->taskfinder(PT,&skel_p,x,path))) // simple_nexttid
|
|
|
|
|| (!(ret = PT->taskreader(PT,new_p,x,path)))) { // simple_readtask
|
|
|
|
goto next_proc;
|
2011-08-11 03:12:14 +05:30
|
|
|
}
|
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).
1970-01-01 05:30:00 +05:30
|
|
|
if (!new_p) {
|
|
|
|
new_p = ret;
|
|
|
|
canary = new_p->tid;
|
|
|
|
}
|
2011-10-06 19:04:26 +05:30
|
|
|
return ret;
|
2011-08-11 03:12:14 +05:30
|
|
|
|
|
|
|
end_procs:
|
|
|
|
if (!saved_x) free(x);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-09-18 03:28:32 +05:30
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
2002-02-02 04:17:29 +05:30
|
|
|
|
2003-09-18 03:28:32 +05:30
|
|
|
// initiate a process table scan
|
|
|
|
PROCTAB* openproc(int flags, ...) {
|
|
|
|
va_list ap;
|
2003-09-20 13:59:55 +05:30
|
|
|
struct stat sbuf;
|
|
|
|
static int did_stat;
|
1970-01-01 05:30:00 +05:30
|
|
|
PROCTAB* PT = xcalloc(sizeof(PROCTAB));
|
2003-09-20 13:59:55 +05:30
|
|
|
|
2011-12-02 15:17:19 +05:30
|
|
|
if (!did_stat){
|
|
|
|
task_dir_missing = stat("/proc/self/task", &sbuf);
|
|
|
|
did_stat = 1;
|
2003-09-20 13:59:55 +05:30
|
|
|
}
|
|
|
|
PT->taskdir = NULL;
|
2003-10-20 05:07:47 +05:30
|
|
|
PT->taskdir_user = -1;
|
2003-09-20 13:59:55 +05:30
|
|
|
PT->taskfinder = simple_nexttid;
|
|
|
|
PT->taskreader = simple_readtask;
|
|
|
|
|
2003-09-18 03:28:32 +05:30
|
|
|
PT->reader = simple_readproc;
|
|
|
|
if (flags & PROC_PID){
|
2011-12-02 15:17:19 +05:30
|
|
|
PT->procfs = NULL;
|
|
|
|
PT->finder = listed_nextpid;
|
2003-09-18 03:28:32 +05:30
|
|
|
}else{
|
2011-12-02 15:17:19 +05:30
|
|
|
PT->procfs = opendir("/proc");
|
|
|
|
if (!PT->procfs) { free(PT); return NULL; }
|
|
|
|
PT->finder = simple_nextpid;
|
2002-12-21 11:52:00 +05:30
|
|
|
}
|
2003-09-18 03:28:32 +05:30
|
|
|
PT->flags = flags;
|
2002-02-02 04:17:29 +05:30
|
|
|
|
2011-12-02 15:17:19 +05:30
|
|
|
va_start(ap, flags);
|
2003-09-18 03:28:32 +05:30
|
|
|
if (flags & PROC_PID)
|
2011-12-02 15:17:19 +05:30
|
|
|
PT->pids = va_arg(ap, pid_t*);
|
|
|
|
else if (flags & PROC_UID){
|
|
|
|
PT->uids = va_arg(ap, uid_t*);
|
|
|
|
PT->nuid = va_arg(ap, int);
|
2002-10-02 17:40:39 +05:30
|
|
|
}
|
2011-12-02 15:17:19 +05:30
|
|
|
va_end(ap);
|
2002-02-02 04:17:29 +05:30
|
|
|
|
2011-12-02 15:17:19 +05:30
|
|
|
if (!src_buffer){
|
|
|
|
src_buffer = xmalloc(MAX_BUFSZ);
|
|
|
|
dst_buffer = xmalloc(MAX_BUFSZ);
|
|
|
|
}
|
2003-09-18 03:28:32 +05:30
|
|
|
return PT;
|
|
|
|
}
|
2002-10-02 17:40:39 +05:30
|
|
|
|
2003-09-18 03:28:32 +05:30
|
|
|
// terminate a process table scan
|
|
|
|
void closeproc(PROCTAB* PT) {
|
|
|
|
if (PT){
|
|
|
|
if (PT->procfs) closedir(PT->procfs);
|
2003-09-20 13:59:55 +05:30
|
|
|
if (PT->taskdir) closedir(PT->taskdir);
|
2003-10-20 05:07:47 +05:30
|
|
|
memset(PT,'#',sizeof(PROCTAB));
|
2003-09-18 03:28:32 +05:30
|
|
|
free(PT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-01 16:58:46 +05:30
|
|
|
// deallocate space allocated by readproc
|
2003-09-18 03:28:32 +05:30
|
|
|
void freeproc(proc_t* p) {
|
2011-08-01 16:58:46 +05:30
|
|
|
if (p) {
|
|
|
|
free_acquired(p, 0);
|
|
|
|
free(p);
|
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-09-18 03:28:32 +05:30
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
2002-02-02 04:17:29 +05:30
|
|
|
void look_up_our_self(proc_t *p) {
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
struct utlbuf_s ub = { NULL, 0 };
|
2003-05-31 20:48:13 +05:30
|
|
|
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
if(file2str("/proc/self", "stat", &ub) == -1){
|
2006-06-27 08:37:09 +05:30
|
|
|
fprintf(stderr, "Error, do this: mount -t proc proc /proc\n");
|
2003-05-31 20:48:13 +05:30
|
|
|
_exit(47);
|
|
|
|
}
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
stat2proc(ub.buf, p); // parse /proc/self/stat
|
|
|
|
free(ub.buf);
|
2002-02-02 04:17:29 +05:30
|
|
|
}
|
|
|
|
|
2003-01-15 16:22:39 +05:30
|
|
|
HIDDEN_ALIAS(readproc);
|
2003-10-16 09:00:41 +05:30
|
|
|
HIDDEN_ALIAS(readtask);
|
2011-08-11 03:12:14 +05:30
|
|
|
HIDDEN_ALIAS(readeither);
|
2002-02-02 04:17:29 +05:30
|
|
|
|
|
|
|
/* Convenient wrapper around openproc and readproc to slurp in the whole process
|
|
|
|
* table subset satisfying the constraints of flags and the optional PID list.
|
2003-07-03 10:50:19 +05:30
|
|
|
* Free allocated memory with exit(). Access via tab[N]->member. The pointer
|
|
|
|
* list is NULL terminated.
|
2002-02-02 04:17:29 +05:30
|
|
|
*/
|
|
|
|
proc_t** readproctab(int flags, ...) {
|
|
|
|
PROCTAB* PT = NULL;
|
|
|
|
proc_t** tab = NULL;
|
|
|
|
int n = 0;
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start(ap, flags); /* pass through args to openproc */
|
2002-10-22 11:42:12 +05:30
|
|
|
if (flags & PROC_UID) {
|
2002-02-02 04:17:29 +05:30
|
|
|
/* temporary variables to ensure that va_arg() instances
|
|
|
|
* are called in the right order
|
|
|
|
*/
|
|
|
|
uid_t* u;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
u = va_arg(ap, uid_t*);
|
|
|
|
i = va_arg(ap, int);
|
|
|
|
PT = openproc(flags, u, i);
|
|
|
|
}
|
2002-10-22 11:42:12 +05:30
|
|
|
else if (flags & PROC_PID)
|
2002-02-02 04:17:29 +05:30
|
|
|
PT = openproc(flags, va_arg(ap, void*)); /* assume ptr sizes same */
|
|
|
|
else
|
|
|
|
PT = openproc(flags);
|
|
|
|
va_end(ap);
|
2009-11-24 05:30:41 +05:30
|
|
|
if (!PT)
|
|
|
|
return 0;
|
2002-02-02 04:17:29 +05:30
|
|
|
do { /* read table: */
|
1970-01-01 05:30:00 +05:30
|
|
|
if (n < 0 || (size_t)n >= INT_MAX / sizeof(proc_t*)) {
|
|
|
|
xalloc_err_handler("integer overflow in %s (%s=%zu)", __func__, "n", (size_t)n);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
tab = xrealloc(tab, (n+1)*sizeof(proc_t*));/* realloc as we go, using */
|
2003-01-15 16:22:39 +05:30
|
|
|
tab[n] = readproc_direct(PT, NULL); /* final null to terminate */
|
2002-02-02 04:17:29 +05:30
|
|
|
} while (tab[n++]); /* stop when NULL reached */
|
|
|
|
closeproc(PT);
|
|
|
|
return tab;
|
|
|
|
}
|
2003-10-16 09:00:41 +05:30
|
|
|
|
1970-01-01 05:30:00 +05:30
|
|
|
#define grow_by_size(ptr, nmemb, over, size) do { \
|
|
|
|
if ((size_t)(nmemb) >= INT_MAX / 5) { \
|
|
|
|
xalloc_err_handler("integer overflow in %s (%s=%zu)", __func__, #nmemb, (size_t)(nmemb)); \
|
|
|
|
exit(EXIT_FAILURE); \
|
|
|
|
} \
|
|
|
|
(nmemb) = (nmemb) * 5 / 4 + (over); \
|
|
|
|
if ((size_t)(nmemb) >= SSIZE_MAX / (size)) { \
|
|
|
|
xalloc_err_handler("integer overflow in %s (%s=%zu)", __func__, #nmemb, (size_t)(nmemb)); \
|
|
|
|
exit(EXIT_FAILURE); \
|
|
|
|
} \
|
|
|
|
(ptr) = xrealloc((ptr), (nmemb) * (size)); \
|
|
|
|
} while (0)
|
|
|
|
|
2003-10-16 09:00:41 +05:30
|
|
|
// Try again, this time with threads and selection.
|
2003-10-20 05:07:47 +05:30
|
|
|
proc_data_t *readproctab2(int(*want_proc)(proc_t *buf), int(*want_task)(proc_t *buf), PROCTAB *restrict const PT) {
|
2011-08-11 03:12:14 +05:30
|
|
|
static proc_data_t pd;
|
2003-10-16 09:00:41 +05:30
|
|
|
proc_t** ptab = NULL;
|
1970-01-01 05:30:00 +05:30
|
|
|
size_t n_proc_alloc = 0;
|
|
|
|
size_t n_proc = 0;
|
2003-10-20 05:07:47 +05:30
|
|
|
|
|
|
|
proc_t** ttab = NULL;
|
1970-01-01 05:30:00 +05:30
|
|
|
size_t n_task_alloc = 0;
|
|
|
|
size_t n_task = 0;
|
2003-10-16 09:00:41 +05:30
|
|
|
|
2003-10-20 05:07:47 +05:30
|
|
|
proc_t* data = NULL;
|
1970-01-01 05:30:00 +05:30
|
|
|
size_t n_alloc = 0;
|
|
|
|
uintptr_t n_used = 0;
|
2003-10-16 09:00:41 +05:30
|
|
|
|
|
|
|
for(;;){
|
|
|
|
proc_t *tmp;
|
|
|
|
if(n_alloc == n_used){
|
|
|
|
//proc_t *old = data;
|
1970-01-01 05:30:00 +05:30
|
|
|
grow_by_size(data, n_alloc, 30, sizeof(proc_t));
|
2011-08-01 16:58:46 +05:30
|
|
|
memset(data+n_used, 0, sizeof(proc_t)*(n_alloc-n_used));
|
2003-10-16 09:00:41 +05:30
|
|
|
}
|
|
|
|
if(n_proc_alloc == n_proc){
|
|
|
|
//proc_t **old = ptab;
|
1970-01-01 05:30:00 +05:30
|
|
|
grow_by_size(ptab, n_proc_alloc, 30, sizeof(proc_t*));
|
2003-10-16 09:00:41 +05:30
|
|
|
}
|
|
|
|
tmp = readproc_direct(PT, data+n_used);
|
|
|
|
if(!tmp) break;
|
|
|
|
if(!want_proc(tmp)) continue;
|
2003-10-20 05:07:47 +05:30
|
|
|
ptab[n_proc++] = (proc_t*)(n_used++);
|
2003-10-16 09:00:41 +05:30
|
|
|
if(!( PT->flags & PROC_LOOSE_TASKS )) continue;
|
|
|
|
for(;;){
|
|
|
|
proc_t *t;
|
|
|
|
if(n_alloc == n_used){
|
2005-09-12 08:55:01 +05:30
|
|
|
proc_t *old = data;
|
1970-01-01 05:30:00 +05:30
|
|
|
grow_by_size(data, n_alloc, 30, sizeof(proc_t));
|
2011-08-01 16:58:46 +05:30
|
|
|
// have to move tmp too
|
|
|
|
tmp = data+(tmp-old);
|
1970-01-01 05:30:00 +05:30
|
|
|
memset(data+n_used, 0, sizeof(proc_t)*(n_alloc-n_used));
|
2003-10-16 09:00:41 +05:30
|
|
|
}
|
|
|
|
if(n_task_alloc == n_task){
|
|
|
|
//proc_t **old = ttab;
|
1970-01-01 05:30:00 +05:30
|
|
|
grow_by_size(ttab, n_task_alloc, 1, sizeof(proc_t*));
|
2003-10-16 09:00:41 +05:30
|
|
|
}
|
|
|
|
t = readtask_direct(PT, tmp, data+n_used);
|
|
|
|
if(!t) break;
|
|
|
|
if(!want_task(t)) continue;
|
2003-10-20 05:07:47 +05:30
|
|
|
ttab[n_task++] = (proc_t*)(n_used++);
|
2003-10-16 09:00:41 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-11 03:12:14 +05:30
|
|
|
pd.proc = ptab;
|
|
|
|
pd.task = ttab;
|
|
|
|
pd.nproc = n_proc;
|
|
|
|
pd.ntask = n_task;
|
2003-10-20 05:07:47 +05:30
|
|
|
if(PT->flags & PROC_LOOSE_TASKS){
|
2011-08-11 03:12:14 +05:30
|
|
|
pd.tab = ttab;
|
|
|
|
pd.n = n_task;
|
2003-10-16 09:00:41 +05:30
|
|
|
}else{
|
2011-08-11 03:12:14 +05:30
|
|
|
pd.tab = ptab;
|
|
|
|
pd.n = n_proc;
|
2003-10-16 09:00:41 +05:30
|
|
|
}
|
2003-10-20 05:07:47 +05:30
|
|
|
// change array indexes to pointers
|
1970-01-01 05:30:00 +05:30
|
|
|
while(n_proc--) ptab[n_proc] = data+(uintptr_t)(ptab[n_proc]);
|
|
|
|
while(n_task--) ttab[n_task] = data+(uintptr_t)(ttab[n_task]);
|
2003-10-16 09:00:41 +05:30
|
|
|
|
2011-08-11 03:12:14 +05:30
|
|
|
return &pd;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try try yet again, this time treating processes and threads the same...
|
|
|
|
proc_data_t *readproctab3 (int(*want_task)(proc_t *buf), PROCTAB *restrict const PT) {
|
|
|
|
static proc_data_t pd;
|
|
|
|
proc_t **tab = NULL;
|
1970-01-01 05:30:00 +05:30
|
|
|
size_t n_alloc = 0;
|
|
|
|
size_t n_used = 0;
|
2011-08-11 03:12:14 +05:30
|
|
|
proc_t *p = NULL;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
if (n_alloc == n_used) {
|
1970-01-01 05:30:00 +05:30
|
|
|
grow_by_size(tab, n_alloc, 30, sizeof(proc_t*));
|
2011-08-11 03:12:14 +05:30
|
|
|
}
|
|
|
|
// let this next guy allocate the necessary proc_t storage
|
|
|
|
// (or recycle it) since he can't tolerate realloc relocations
|
|
|
|
if (!(p = readeither_direct(PT,p))) break;
|
|
|
|
if (want_task(p)) {
|
|
|
|
tab[n_used++] = p;
|
|
|
|
p = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pd.tab = tab;
|
|
|
|
pd.n = n_used;
|
|
|
|
return &pd;
|
2003-10-16 09:00:41 +05:30
|
|
|
}
|
|
|
|
|
2004-01-27 01:31:56 +05:30
|
|
|
/*
|
|
|
|
* get_proc_stats - lookup a single tasks information and fill out a proc_t
|
|
|
|
*
|
|
|
|
* On failure, returns NULL. On success, returns 'p' and 'p' is a valid
|
|
|
|
* and filled out proc_t structure.
|
|
|
|
*/
|
2004-11-05 02:20:59 +05:30
|
|
|
proc_t * get_proc_stats(pid_t pid, proc_t *p) {
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
struct utlbuf_s ub = { NULL, 0 };
|
|
|
|
static char path[32];
|
|
|
|
struct stat statbuf;
|
|
|
|
|
1970-01-01 05:30:00 +05:30
|
|
|
snprintf(path, sizeof path, "/proc/%d", pid);
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
if (stat(path, &statbuf)) {
|
|
|
|
perror("stat");
|
|
|
|
return NULL;
|
|
|
|
}
|
2004-01-27 01:31:56 +05:30
|
|
|
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
if (file2str(path, "stat", &ub) >= 0)
|
|
|
|
stat2proc(ub.buf, p);
|
|
|
|
if (file2str(path, "statm", &ub) >= 0)
|
|
|
|
statm2proc(ub.buf, p);
|
|
|
|
if (file2str(path, "status", &ub) >= 0)
|
|
|
|
status2proc(ub.buf, p, 0);
|
2004-01-27 01:31:56 +05:30
|
|
|
|
library: utility buffers now immune to buffer overflow
A recent Debian bug report, dealing with release 3.2.8
and its even more restrictive buffer sizes (1024) used
in stat, statm and status reads via file2str calls, is
a reminder of what could yet happen to procps-ng. Size
needs are determined by kernel evolution and/or config
options so that bug could resurface even though buffer
size is currently 4 times the old procps-3.2.8 limits.
Those sizes were raised from 1024 to 4096 bytes in the
patch submitted by Eric Dumazet, and referenced below.
This patch makes libprocps immune to future changes in
the amount of stuff that is ultimately found in a proc
'stat', 'statm' or 'status' subdirectory. We now trade
the former static buffer of 4096 bytes for dynamically
allocated buffers whose size can be increased by need.
Even though this change is solely an internal one, and
in no way directly affects the API or the ABI, libtool
suggests that the LIBprocps_REVISION be raised. I hope
Craig remembers to do that just before a next release.
We don't want a repeat of the procps-ng-3.3.4 boo-boo,
but with no API/ABI impact that probably can't happen.
p.s. A big thanks to Jaromir Capik <jcapik@redhat.com>
who reviewed my original version and, of course, found
some of my trademark illogic + unnecessary code. After
his coaxing, he helped make this a much better commit.
Reference(s):
. procps-3.2.8
http://bugs.debian.org/702965
. allow large list of groups
commit 7933435584aa1fd75460f4c7715a3d4855d97c1c
Signed-off-by: Jim Warner <james.warner@comcast.net>
Reviewed by: Jaromir Capik <jcapik@redhat.com>
2013-03-23 10:30:00 +05:30
|
|
|
free(ub.buf);
|
|
|
|
return p;
|
2004-01-27 01:31:56 +05:30
|
|
|
}
|
2011-08-11 03:12:14 +05:30
|
|
|
|
|
|
|
#undef MK_THREAD
|
|
|
|
#undef IS_THREAD
|
2011-12-02 15:17:19 +05:30
|
|
|
#undef MAX_BUFSZ
|