procps/proc/readproc.c

1455 lines
46 KiB
C
Raw Normal View History

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
*
* 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
*/
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>
#include <dirent.h>
2002-02-02 04:17:29 +05:30
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <stdint.h>
#ifdef WITH_SYSTEMD
#include <systemd/sd-login.h>
#endif
#include "devname.h"
#include "escape.h"
#include "misc.h"
#include "pwcache.h"
#include "readproc.h"
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
#ifdef FALSE_THREADS
#define IS_THREAD(q) ( q->tid != q->tgid )
#endif
// 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;
2003-09-20 13:59:55 +05:30
static int task_dir_missing;
// free any additional dynamically acquired storage associated with a proc_t
static inline void free_acquired (proc_t *p) {
/*
* here we free those items that might exist even when not explicitly |
* requested by our caller. it is expected that pid.c will then free |
* any remaining dynamic memory which might be dangling off a proc_t. | */
if (p->cgname) free(p->cgname);
if (p->cgroup) free(p->cgroup);
if (p->cmd) free(p->cmd);
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);
if (p->supgid) free(p->supgid);
memset(p, '\0', sizeof(proc_t));
}
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 {
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
#define GPERF_TABLE_SIZE 128
2003-02-17 06:27:15 +05:30
// Derived from:
// gperf -7 --language=ANSI-C --key-positions=1,3,4 -C -n -c <if-not-piped>
// ( --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.
// 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'
// into our 'asso' array. Then convert the gperf 'wordlist' array
// 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
//
// In the status_table_struct watch out for name size (grrr, expanding)
// 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
static int 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;
// 128 entries because we trust the kernel to use ASCII names
2003-12-13 22:21:40 +05:30
static const unsigned char asso[] =
{
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
static const status_table_struct table[GPERF_TABLE_SIZE] = {
F(VmHWM)
F(Threads)
NUL NUL NUL
F(VmRSS)
F(VmSwap)
NUL NUL NUL
F(Tgid)
F(VmStk)
NUL NUL NUL
F(VmSize)
F(Gid)
NUL NUL NUL
F(VmPTE)
F(VmPeak)
NUL NUL NUL
F(ShdPnd)
F(Pid)
NUL NUL NUL
F(PPid)
F(VmLib)
NUL NUL NUL
F(SigPnd)
F(VmLck)
NUL NUL NUL
2003-12-13 22:21:40 +05:30
F(SigCgt)
F(State)
NUL NUL NUL
F(CapPrm)
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
F(CapEff)
NUL NUL NUL NUL
F(CapBnd)
NUL NUL NUL NUL
F(VmExe)
NUL NUL NUL NUL
F(Groups)
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(!S) break; // if no newline
2003-02-17 06:27:15 +05:30
S++;
// examine a field name (hash and compare)
base:
if(!*S) break;
if((!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(!colon) break;
if(colon[1]!='\t') break;
if(colon-S != entry.len) continue;
if(memcmp(entry.name,S,colon-S)) continue;
2003-02-17 06:27:15 +05:30
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
case_Name:
library: refactor 'escape' logic for newlib (2nd time) Much of what was represented in the commit message for the reference shown below was revisited in this patch. It also means that the assertion in the last paragraph of that message will only now be true with LANG unset. [ and forget all the bullshit about not altering any ] [ kernel supplied data. sometimes we must to avoid a ] [ corrupt display due to a string we can not decode. ] And while this commit still avoids the overhead of the 'mbrtowc', 'wcwidth' 'isprint, & 'iswprint' functions, we achieve all the benefits with simple table lookups. Plus such benefits are extended to additional strings. For example, both PIDS_EXE and PIDS_CMD fields are now also subject to being 'escaped'. If a program name did contain multibyte characters, potential truncation may corrupt it when it's squeezed into a 15/63 byte array. Now, all future users of this new library only need to deal with the disparities between string and printable lengths. Such strings themselves are always printable. [ the ps program now contains some unnecessary costs ] [ with the duplicated former 'escape' functions. But ] [ we retain that copied escape.c code for posterity. ] [ besides, in a one-shot guy it's of little concern. ] Note: Proper display of some multibyte strings was not possible at the linux console. It would seem a concept of zero length chars (like a 'combining acute accent') is not recognized. Thus the display becomes corrupted. But if utf8 decoding is disabled (via LANG=), then all callers will now see '?', restoring correct alignment. Reference(s): . Dec 2020, newlib 'escape' logic refactored commit a221b9084ae979e6fd073a83e7fbc46c44551f35 Signed-off-by: Jim Warner <james.warner@comcast.net>
2020-12-28 11:30:00 +05:30
{ char buf[64], raw[64];
unsigned u = 0;
library: refactor 'escape' logic for newlib (2nd time) Much of what was represented in the commit message for the reference shown below was revisited in this patch. It also means that the assertion in the last paragraph of that message will only now be true with LANG unset. [ and forget all the bullshit about not altering any ] [ kernel supplied data. sometimes we must to avoid a ] [ corrupt display due to a string we can not decode. ] And while this commit still avoids the overhead of the 'mbrtowc', 'wcwidth' 'isprint, & 'iswprint' functions, we achieve all the benefits with simple table lookups. Plus such benefits are extended to additional strings. For example, both PIDS_EXE and PIDS_CMD fields are now also subject to being 'escaped'. If a program name did contain multibyte characters, potential truncation may corrupt it when it's squeezed into a 15/63 byte array. Now, all future users of this new library only need to deal with the disparities between string and printable lengths. Such strings themselves are always printable. [ the ps program now contains some unnecessary costs ] [ with the duplicated former 'escape' functions. But ] [ we retain that copied escape.c code for posterity. ] [ besides, in a one-shot guy it's of little concern. ] Note: Proper display of some multibyte strings was not possible at the linux console. It would seem a concept of zero length chars (like a 'combining acute accent') is not recognized. Thus the display becomes corrupted. But if utf8 decoding is disabled (via LANG=), then all callers will now see '?', restoring correct alignment. Reference(s): . Dec 2020, newlib 'escape' logic refactored commit a221b9084ae979e6fd073a83e7fbc46c44551f35 Signed-off-by: Jim Warner <james.warner@comcast.net>
2020-12-28 11:30:00 +05:30
while(u < sizeof(raw) - 1u){
2003-02-17 06:27:15 +05:30
int c = *S++;
if(c=='\n') break;
if(c=='\0') break; // should never happen
if(c=='\\'){
2003-02-17 06:27:15 +05:30
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 '\\'
}
library: refactor 'escape' logic for newlib (2nd time) Much of what was represented in the commit message for the reference shown below was revisited in this patch. It also means that the assertion in the last paragraph of that message will only now be true with LANG unset. [ and forget all the bullshit about not altering any ] [ kernel supplied data. sometimes we must to avoid a ] [ corrupt display due to a string we can not decode. ] And while this commit still avoids the overhead of the 'mbrtowc', 'wcwidth' 'isprint, & 'iswprint' functions, we achieve all the benefits with simple table lookups. Plus such benefits are extended to additional strings. For example, both PIDS_EXE and PIDS_CMD fields are now also subject to being 'escaped'. If a program name did contain multibyte characters, potential truncation may corrupt it when it's squeezed into a 15/63 byte array. Now, all future users of this new library only need to deal with the disparities between string and printable lengths. Such strings themselves are always printable. [ the ps program now contains some unnecessary costs ] [ with the duplicated former 'escape' functions. But ] [ we retain that copied escape.c code for posterity. ] [ besides, in a one-shot guy it's of little concern. ] Note: Proper display of some multibyte strings was not possible at the linux console. It would seem a concept of zero length chars (like a 'combining acute accent') is not recognized. Thus the display becomes corrupted. But if utf8 decoding is disabled (via LANG=), then all callers will now see '?', restoring correct alignment. Reference(s): . Dec 2020, newlib 'escape' logic refactored commit a221b9084ae979e6fd073a83e7fbc46c44551f35 Signed-off-by: Jim Warner <james.warner@comcast.net>
2020-12-28 11:30:00 +05:30
raw[u++] = c;
2003-02-17 06:27:15 +05:30
}
library: refactor 'escape' logic for newlib (2nd time) Much of what was represented in the commit message for the reference shown below was revisited in this patch. It also means that the assertion in the last paragraph of that message will only now be true with LANG unset. [ and forget all the bullshit about not altering any ] [ kernel supplied data. sometimes we must to avoid a ] [ corrupt display due to a string we can not decode. ] And while this commit still avoids the overhead of the 'mbrtowc', 'wcwidth' 'isprint, & 'iswprint' functions, we achieve all the benefits with simple table lookups. Plus such benefits are extended to additional strings. For example, both PIDS_EXE and PIDS_CMD fields are now also subject to being 'escaped'. If a program name did contain multibyte characters, potential truncation may corrupt it when it's squeezed into a 15/63 byte array. Now, all future users of this new library only need to deal with the disparities between string and printable lengths. Such strings themselves are always printable. [ the ps program now contains some unnecessary costs ] [ with the duplicated former 'escape' functions. But ] [ we retain that copied escape.c code for posterity. ] [ besides, in a one-shot guy it's of little concern. ] Note: Proper display of some multibyte strings was not possible at the linux console. It would seem a concept of zero length chars (like a 'combining acute accent') is not recognized. Thus the display becomes corrupted. But if utf8 decoding is disabled (via LANG=), then all callers will now see '?', restoring correct alignment. Reference(s): . Dec 2020, newlib 'escape' logic refactored commit a221b9084ae979e6fd073a83e7fbc46c44551f35 Signed-off-by: Jim Warner <james.warner@comcast.net>
2020-12-28 11:30:00 +05:30
raw[u] = '\0';
#ifdef FALSE_THREADS
if (!IS_THREAD(P)) {
#endif
library: refactor 'escape' logic for newlib (2nd time) Much of what was represented in the commit message for the reference shown below was revisited in this patch. It also means that the assertion in the last paragraph of that message will only now be true with LANG unset. [ and forget all the bullshit about not altering any ] [ kernel supplied data. sometimes we must to avoid a ] [ corrupt display due to a string we can not decode. ] And while this commit still avoids the overhead of the 'mbrtowc', 'wcwidth' 'isprint, & 'iswprint' functions, we achieve all the benefits with simple table lookups. Plus such benefits are extended to additional strings. For example, both PIDS_EXE and PIDS_CMD fields are now also subject to being 'escaped'. If a program name did contain multibyte characters, potential truncation may corrupt it when it's squeezed into a 15/63 byte array. Now, all future users of this new library only need to deal with the disparities between string and printable lengths. Such strings themselves are always printable. [ the ps program now contains some unnecessary costs ] [ with the duplicated former 'escape' functions. But ] [ we retain that copied escape.c code for posterity. ] [ besides, in a one-shot guy it's of little concern. ] Note: Proper display of some multibyte strings was not possible at the linux console. It would seem a concept of zero length chars (like a 'combining acute accent') is not recognized. Thus the display becomes corrupted. But if utf8 decoding is disabled (via LANG=), then all callers will now see '?', restoring correct alignment. Reference(s): . Dec 2020, newlib 'escape' logic refactored commit a221b9084ae979e6fd073a83e7fbc46c44551f35 Signed-off-by: Jim Warner <james.warner@comcast.net>
2020-12-28 11:30:00 +05:30
if (!P->cmd) {
escape_str(buf, raw, sizeof(buf));
if (!(P->cmd = strdup(buf))) return 1;
}
#ifdef FALSE_THREADS
}
#endif
2003-02-18 09:21:03 +05:30
S--; // put back the '\n' or '\0'
2003-02-17 06:27:15 +05:30
continue;
}
case_ShdPnd:
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:
memcpy(P->_sigpnd, S, 16);
P->_sigpnd[16] = '\0';
2003-02-17 06:27:15 +05:30
continue;
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 = (unsigned long)strtol(S,&S,10);
2003-02-17 06:27:15 +05:30
continue;
case_VmExe:
P->vm_exe = (unsigned long)strtol(S,&S,10);
2003-02-17 06:27:15 +05:30
continue;
case_VmLck:
P->vm_lock = (unsigned long)strtol(S,&S,10);
2003-02-17 06:27:15 +05:30
continue;
case_VmLib:
P->vm_lib = (unsigned long)strtol(S,&S,10);
2003-02-17 06:27:15 +05:30
continue;
case_VmRSS:
P->vm_rss = (unsigned long)strtol(S,&S,10);
2003-02-17 06:27:15 +05:30
continue;
case_RssAnon: // subset of VmRSS, linux-4.5
P->vm_rss_anon = (unsigned long)strtol(S,&S,10);
continue;
case_RssFile: // subset of VmRSS, linux-4.5
P->vm_rss_file = (unsigned long)strtol(S,&S,10);
continue;
case_RssShmem: // subset of VmRSS, linux-4.5
P->vm_rss_shared = (unsigned long)strtol(S,&S,10);
continue;
2003-02-17 06:27:15 +05:30
case_VmSize:
P->vm_size = (unsigned long)strtol(S,&S,10);
2003-02-17 06:27:15 +05:30
continue;
case_VmStk:
P->vm_stack = (unsigned long)strtol(S,&S,10);
2003-02-17 06:27:15 +05:30
continue;
case_VmSwap: // Linux 2.6.34
P->vm_swap = (unsigned long)strtol(S,&S,10);
continue;
case_Groups:
{ char *ss = S, *nl = strchr(S, '\n');
size_t j;
#ifdef FALSE_THREADS
if (IS_THREAD(P)) continue;
#endif
while (' ' == *ss || '\t' == *ss) ss++;
if (ss >= nl) continue;
j = nl ? (size_t)(nl - ss) : strlen(ss);
if (j > 0 && j < INT_MAX) {
P->supgid = malloc(j+1); // +1 in case space disappears
if (!P->supgid)
return 1;
memcpy(P->supgid, ss, j);
if (' ' != P->supgid[--j]) ++j;
P->supgid[j] = '\0'; // whack the space or the newline
for ( ; j; j--)
if (' ' == P->supgid[j])
P->supgid[j] = ',';
library: standardize handling of cgroup, supgid Some inconsistencies have emerged during development of support for these relatively new proc_t fields. For example, a PROC_FILLCGROUP flag (via file2strvec) could return NULL in cgroup whereas PROC_EDITCGRPCVT (via fill_cgroup_cvt) *almost* guaranteed a return address (as is true for PROC_EDITCMDLCVT and cmdline). But even PROC_EDITCGRPCVT could return NULL if the kernel version was less than 2.6.24. Then with NULL ps would display a "-" while top would show "n/a". And while unlikely, with the PROC_FILLSTATUS flag (via status2proc) a NULL supgid address was theoretically possible and both ps and top would then show "n/a". This commit standardizes the following usage: . PROC_FILLSTATUS (via status2proc) guarantees a valid supgid address representing either a true comma delimited list or "-" . PROC_FILLCGROUP plus PROC_EDITCGRPCVT (via fill_cgroup_cvt) guarantees a cgroup single vector representing either a true control group hierarchy or "-" And as was true before, the following remains true: PROC_FILLCOM or PROC_FILLARG (via file2strvec) may return a NULL cmdline pointer . PROC_FILLCGROUP (via file2strvec) may return a NULL cgroup pointer . PROC_FILLCOM or PROC_FILLARG plus PROC_EDITCMDLCVT (via fill_cmdline_cvt) guarantees a cmdline single vector representing either a true command line or a bracketed program name . PROC_FILLSTATUS plus PROC_FILLSUPGRP (via supgrps_from_supgids) guarantees a valid supgrp address representing either a true comma delimited list or "-" Signed-off-by: Jim Warner <james.warner@comcast.net>
2012-06-28 10:30:01 +05:30
}
continue;
}
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
#if 0
2003-09-28 08:15:05 +05:30
// recent kernels supply per-tgid pending signals
if(is_proc && *ShdPnd){
memcpy(P->signal, ShdPnd, 16);
P->signal[16] = '\0';
2003-09-28 08:15:05 +05:30
}
#endif
// recent kernels supply per-tgid pending signals
if(!is_proc || !P->signal[0]){
memcpy(P->signal, P->_sigpnd, 16);
P->signal[16] = '\0';
}
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){
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{
P->nlwp = 1;
P->tgid = Pid;
P->tid = Pid;
2003-12-13 22:21:40 +05:30
}
#ifdef FALSE_THREADS
if (!IS_THREAD(P)) {
#endif
if (!P->supgid) {
P->supgid = strdup("-");
if (!P->supgid)
return 1;
}
#ifdef FALSE_THREADS
}
#endif
2003-02-17 06:27:15 +05:30
LEAVE(0x220);
return 0;
2003-02-17 06:27:15 +05:30
}
#undef GPERF_TABLE_SIZE
2003-02-17 06:27:15 +05:30
static int supgrps_from_supgids (proc_t *p) {
char *g, *s;
int t;
#ifdef FALSE_THREADS
if (IS_THREAD(p)) return 0;
#endif
if (!p->supgid || '-' == *p->supgid)
goto wrap_up;
s = p->supgid;
t = 0;
do {
const int max = P_G_SZ+2;
char *end = NULL;
gid_t gid;
int len;
while (',' == *s) ++s;
gid = strtol(s, &end, 10);
if (end <= s) break;
s = end;
g = pwcache_get_group(gid);
if ((t >= INT_MAX - max)
|| (!(p->supgrp = realloc(p->supgrp, t + max))))
return 1;
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;
} while (*s);
wrap_up:
if (!p->supgrp
&& !(p->supgrp = strdup("-")))
return 1;
return 0;
}
2003-02-17 06:27:15 +05:30
///////////////////////////////////////////////////////////////////////
static inline void oomscore2proc(const char* S, proc_t *restrict P)
{
sscanf(S, "%d", &P->oom_score);
}
static inline void oomadj2proc(const char* S, proc_t *restrict P)
{
sscanf(S, "%d", &P->oom_adj);
}
///////////////////////////////////////////////////////////////////////
static int sd2proc (proc_t *restrict p) {
#ifdef WITH_SYSTEMD
char buf[64];
uid_t uid;
if (0 > sd_pid_get_machine_name(p->tid, &p->sd_mach)) {
if (!(p->sd_mach = strdup("-")))
return 1;
}
if (0 > sd_pid_get_owner_uid(p->tid, &uid)) {
if (!(p->sd_ouid = strdup("-")))
return 1;
} else {
snprintf(buf, sizeof(buf), "%d", (int)uid);
if (!(p->sd_ouid = strdup(buf)))
return 1;
}
if (0 > sd_pid_get_session(p->tid, &p->sd_sess)) {
if (!(p->sd_sess = strdup("-")))
return 1;
if (!(p->sd_seat = strdup("-")))
return 1;
} else {
if (0 > sd_session_get_seat(p->sd_sess, &p->sd_seat))
if (!(p->sd_seat = strdup("-")))
return 1;
}
if (0 > sd_pid_get_slice(p->tid, &p->sd_slice))
if (!(p->sd_slice = strdup("-")))
return 1;
if (0 > sd_pid_get_unit(p->tid, &p->sd_unit))
if (!(p->sd_unit = strdup("-")))
return 1;
if (0 > sd_pid_get_user_unit(p->tid, &p->sd_uunit))
if (!(p->sd_uunit = strdup("-")))
return 1;
#else
if (!(p->sd_mach = strdup("?")))
return 1;
if (!(p->sd_ouid = strdup("?")))
return 1;
if (!(p->sd_seat = strdup("?")))
return 1;
if (!(p->sd_sess = strdup("?")))
return 1;
if (!(p->sd_slice = strdup("?")))
return 1;
if (!(p->sd_unit = strdup("?")))
return 1;
if (!(p->sd_uunit = strdup("?")))
return 1;
#endif
return 0;
}
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".
static int stat2proc (const char* S, proc_t *restrict P) {
library: refactor 'escape' logic for newlib (2nd time) Much of what was represented in the commit message for the reference shown below was revisited in this patch. It also means that the assertion in the last paragraph of that message will only now be true with LANG unset. [ and forget all the bullshit about not altering any ] [ kernel supplied data. sometimes we must to avoid a ] [ corrupt display due to a string we can not decode. ] And while this commit still avoids the overhead of the 'mbrtowc', 'wcwidth' 'isprint, & 'iswprint' functions, we achieve all the benefits with simple table lookups. Plus such benefits are extended to additional strings. For example, both PIDS_EXE and PIDS_CMD fields are now also subject to being 'escaped'. If a program name did contain multibyte characters, potential truncation may corrupt it when it's squeezed into a 15/63 byte array. Now, all future users of this new library only need to deal with the disparities between string and printable lengths. Such strings themselves are always printable. [ the ps program now contains some unnecessary costs ] [ with the duplicated former 'escape' functions. But ] [ we retain that copied escape.c code for posterity. ] [ besides, in a one-shot guy it's of little concern. ] Note: Proper display of some multibyte strings was not possible at the linux console. It would seem a concept of zero length chars (like a 'combining acute accent') is not recognized. Thus the display becomes corrupted. But if utf8 decoding is disabled (via LANG=), then all callers will now see '?', restoring correct alignment. Reference(s): . Dec 2020, newlib 'escape' logic refactored commit a221b9084ae979e6fd073a83e7fbc46c44551f35 Signed-off-by: Jim Warner <james.warner@comcast.net>
2020-12-28 11:30:00 +05:30
char buf[64], raw[64];
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
S = strchr(S, '(');
if (!S) return 0;
S++;
2002-12-21 11:52:00 +05:30
tmp = strrchr(S, ')');
if (!tmp || !tmp[1]) return 0;
#ifdef FALSE_THREADS
if (!IS_THREAD(P)) {
#endif
library: refactor 'escape' logic for newlib (2nd time) Much of what was represented in the commit message for the reference shown below was revisited in this patch. It also means that the assertion in the last paragraph of that message will only now be true with LANG unset. [ and forget all the bullshit about not altering any ] [ kernel supplied data. sometimes we must to avoid a ] [ corrupt display due to a string we can not decode. ] And while this commit still avoids the overhead of the 'mbrtowc', 'wcwidth' 'isprint, & 'iswprint' functions, we achieve all the benefits with simple table lookups. Plus such benefits are extended to additional strings. For example, both PIDS_EXE and PIDS_CMD fields are now also subject to being 'escaped'. If a program name did contain multibyte characters, potential truncation may corrupt it when it's squeezed into a 15/63 byte array. Now, all future users of this new library only need to deal with the disparities between string and printable lengths. Such strings themselves are always printable. [ the ps program now contains some unnecessary costs ] [ with the duplicated former 'escape' functions. But ] [ we retain that copied escape.c code for posterity. ] [ besides, in a one-shot guy it's of little concern. ] Note: Proper display of some multibyte strings was not possible at the linux console. It would seem a concept of zero length chars (like a 'combining acute accent') is not recognized. Thus the display becomes corrupted. But if utf8 decoding is disabled (via LANG=), then all callers will now see '?', restoring correct alignment. Reference(s): . Dec 2020, newlib 'escape' logic refactored commit a221b9084ae979e6fd073a83e7fbc46c44551f35 Signed-off-by: Jim Warner <james.warner@comcast.net>
2020-12-28 11:30:00 +05:30
if (!P->cmd) {
num = tmp - S;
memcpy(raw, S, num);
raw[num] = '\0';
escape_str(buf, raw, sizeof(buf));
if (!(P->cmd = strdup(buf))) return 1;
}
#ifdef FALSE_THREADS
}
#endif
2002-12-03 14:37:59 +05:30
S = tmp + 2; // skip ") "
sscanf(S,
"%c " // state
"%d %d %d %d %d " // ppid, pgrp, sid, tty_nr, tty_pgrp
"%lu %lu %lu %lu %lu " // flags, min_flt, cmin_flt, maj_flt, cmaj_flt
"%llu %llu %llu %llu " // utime, stime, cutime, cstime
"%d %d " // priority, nice
"%d " // num_threads
"%lu " // 'alarm' == it_real_value (obsolete, always 0)
"%llu " // start_time
"%lu " // vsize
"%lu " // rss
"%lu %lu %lu %lu %lu %lu " // rsslim, start_code, end_code, start_stack, esp, eip
"%*s %*s %*s %*s " // pending, blocked, sigign, sigcatch <=== DISCARDED
"%lu %*u %*u " // 0 (former wchan), 0, 0 <=== Placeholders only
"%d %d " // exit_signal, task_cpu
"%d %d " // rt_priority, policy (sched)
"%llu %llu %llu", // blkio_ticks, gtime, cgtime
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,
&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 */
&P->blkio_tics, &P->gtime, &P->cgtime
2002-02-02 04:17:29 +05:30
);
2003-12-13 22:21:40 +05:30
if(!P->nlwp){
P->nlwp = 1;
}
return 0;
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) {
sscanf(s, "%lu %lu %lu %lu %lu %lu %lu",
&P->size, &P->resident, &P->share,
&P->trs, &P->lrs, &P->drs, &P->dt);
2002-02-02 04:17:29 +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
static int file2str(const char *directory, const char *what, struct utlbuf_s *ub) {
#define buffGRW 1024
char path[PROCPATHLEN];
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
buffer will likely soon be used for another subdirectory anyway
( besides, with the calloc call we will never need 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';
else {
ub->buf = calloc(1, (ub->siz = buffGRW));
if (!ub->buf) return -1;
}
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;
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;
if (tot_read < ub->siz) break;
if (ub->siz >= INT_MAX - buffGRW) {
tot_read--;
break;
}
if (!(ub->buf = realloc(ub->buf, (ub->siz += buffGRW)))) {
close(fd);
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
};
ub->buf[tot_read] = '\0';
2002-02-02 04:17:29 +05:30
close(fd);
if (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;
#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) {
char buf[2048]; /* read buf bytes at a time */
0074-proc/readproc.c: Fix bugs and overflows in file2strvec(). Note: this is by far the most important and complex patch of the whole series, please review it carefully; thank you very much! For this patch, we decided to keep the original function's design and skeleton, to avoid regressions and behavior changes, while fixing the various bugs and overflows. And like the "Harden file2str()" patch, this patch does not fail when about to overflow, but truncates instead: there is information available about this process, so return it to the caller; also, we used INT_MAX as a limit, but a lower limit could be used. The easy changes: - Replace sprintf() with snprintf() (and check for truncation). - Replace "if (n == 0 && rbuf == 0)" with "if (n <= 0 && tot <= 0)" and do break instead of return: it simplifies the code (only one place to handle errors), and also guarantees that in the while loop either n or tot is > 0 (or both), even if n is reset to 0 when about to overflow. - Remove the "if (n < 0)" block in the while loop: it is (and was) dead code, since we enter the while loop only if n >= 0. - Rewrite the missing-null-terminator detection: in the original function, if the size of the file is a multiple of 2047, a null- terminator is appended even if the file is already null-terminated. - Replace "if (n <= 0 && !end_of_file)" with "if (n < 0 || tot <= 0)": originally, it was equivalent to "if (n < 0)", but we added "tot <= 0" to handle the first break of the while loop, and to guarantee that in the rest of the function tot is > 0. - Double-force ("belt and suspenders") the null-termination of rbuf: this is (and was) essential to the correctness of the function. - Replace the final "while" loop with a "for" loop that behaves just like the preceding "for" loop: in the original function, this would lead to unexpected results (for example, if rbuf is |\0|A|\0|, this would return the array {"",NULL} but should return {"","A",NULL}; and if rbuf is |A|\0|B| (should never happen because rbuf should be null- terminated), this would make room for two pointers in ret, but would write three pointers to ret). The hard changes: - Prevent the integer overflow of tot in the while loop, but unlike file2str(), file2strvec() cannot let tot grow until it almost reaches INT_MAX, because it needs more space for the pointers: this is why we introduced ARG_LEN, which also guarantees that we can add "align" and a few sizeof(char*)s to tot without overflowing. - Prevent the integer overflow of "tot + c + align": when INT_MAX is (almost) reached, we write the maximal safe amount of pointers to ret (ARG_LEN guarantees that there is always space for *ret = rbuf and the NULL terminator). ---------------------------- adapted for newlib branch . there were many formatting differences . i introduced several myself (especially comments) . stdlib 'realloc' used, not that home grown xrealloc . stdlib 'realloc' required extra 'return NULL' statement Signed-off-by: Jim Warner <james.warner@comcast.net>
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;
0074-proc/readproc.c: Fix bugs and overflows in file2strvec(). Note: this is by far the most important and complex patch of the whole series, please review it carefully; thank you very much! For this patch, we decided to keep the original function's design and skeleton, to avoid regressions and behavior changes, while fixing the various bugs and overflows. And like the "Harden file2str()" patch, this patch does not fail when about to overflow, but truncates instead: there is information available about this process, so return it to the caller; also, we used INT_MAX as a limit, but a lower limit could be used. The easy changes: - Replace sprintf() with snprintf() (and check for truncation). - Replace "if (n == 0 && rbuf == 0)" with "if (n <= 0 && tot <= 0)" and do break instead of return: it simplifies the code (only one place to handle errors), and also guarantees that in the while loop either n or tot is > 0 (or both), even if n is reset to 0 when about to overflow. - Remove the "if (n < 0)" block in the while loop: it is (and was) dead code, since we enter the while loop only if n >= 0. - Rewrite the missing-null-terminator detection: in the original function, if the size of the file is a multiple of 2047, a null- terminator is appended even if the file is already null-terminated. - Replace "if (n <= 0 && !end_of_file)" with "if (n < 0 || tot <= 0)": originally, it was equivalent to "if (n < 0)", but we added "tot <= 0" to handle the first break of the while loop, and to guarantee that in the rest of the function tot is > 0. - Double-force ("belt and suspenders") the null-termination of rbuf: this is (and was) essential to the correctness of the function. - Replace the final "while" loop with a "for" loop that behaves just like the preceding "for" loop: in the original function, this would lead to unexpected results (for example, if rbuf is |\0|A|\0|, this would return the array {"",NULL} but should return {"","A",NULL}; and if rbuf is |A|\0|B| (should never happen because rbuf should be null- terminated), this would make room for two pointers in ret, but would write three pointers to ret). The hard changes: - Prevent the integer overflow of tot in the while loop, but unlike file2str(), file2strvec() cannot let tot grow until it almost reaches INT_MAX, because it needs more space for the pointers: this is why we introduced ARG_LEN, which also guarantees that we can add "align" and a few sizeof(char*)s to tot without overflowing. - Prevent the integer overflow of "tot + c + align": when INT_MAX is (almost) reached, we write the maximal safe amount of pointers to ret (ARG_LEN guarantees that there is always space for *ret = rbuf and the NULL terminator). ---------------------------- adapted for newlib branch . there were many formatting differences . i introduced several myself (especially comments) . stdlib 'realloc' used, not that home grown xrealloc . stdlib 'realloc' required extra 'return NULL' statement Signed-off-by: Jim Warner <james.warner@comcast.net>
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);
0074-proc/readproc.c: Fix bugs and overflows in file2strvec(). Note: this is by far the most important and complex patch of the whole series, please review it carefully; thank you very much! For this patch, we decided to keep the original function's design and skeleton, to avoid regressions and behavior changes, while fixing the various bugs and overflows. And like the "Harden file2str()" patch, this patch does not fail when about to overflow, but truncates instead: there is information available about this process, so return it to the caller; also, we used INT_MAX as a limit, but a lower limit could be used. The easy changes: - Replace sprintf() with snprintf() (and check for truncation). - Replace "if (n == 0 && rbuf == 0)" with "if (n <= 0 && tot <= 0)" and do break instead of return: it simplifies the code (only one place to handle errors), and also guarantees that in the while loop either n or tot is > 0 (or both), even if n is reset to 0 when about to overflow. - Remove the "if (n < 0)" block in the while loop: it is (and was) dead code, since we enter the while loop only if n >= 0. - Rewrite the missing-null-terminator detection: in the original function, if the size of the file is a multiple of 2047, a null- terminator is appended even if the file is already null-terminated. - Replace "if (n <= 0 && !end_of_file)" with "if (n < 0 || tot <= 0)": originally, it was equivalent to "if (n < 0)", but we added "tot <= 0" to handle the first break of the while loop, and to guarantee that in the rest of the function tot is > 0. - Double-force ("belt and suspenders") the null-termination of rbuf: this is (and was) essential to the correctness of the function. - Replace the final "while" loop with a "for" loop that behaves just like the preceding "for" loop: in the original function, this would lead to unexpected results (for example, if rbuf is |\0|A|\0|, this would return the array {"",NULL} but should return {"","A",NULL}; and if rbuf is |A|\0|B| (should never happen because rbuf should be null- terminated), this would make room for two pointers in ret, but would write three pointers to ret). The hard changes: - Prevent the integer overflow of tot in the while loop, but unlike file2str(), file2strvec() cannot let tot grow until it almost reaches INT_MAX, because it needs more space for the pointers: this is why we introduced ARG_LEN, which also guarantees that we can add "align" and a few sizeof(char*)s to tot without overflowing. - Prevent the integer overflow of "tot + c + align": when INT_MAX is (almost) reached, we write the maximal safe amount of pointers to ret (ARG_LEN guarantees that there is always space for *ret = rbuf and the NULL terminator). ---------------------------- adapted for newlib branch . there were many formatting differences . i introduced several myself (especially comments) . stdlib 'realloc' used, not that home grown xrealloc . stdlib 'realloc' required extra 'return NULL' statement Signed-off-by: Jim Warner <james.warner@comcast.net>
1970-01-01 05:30:00 +05:30
if(fd==-1) return NULL;
2002-02-02 04:17:29 +05:30
/* read whole file into a memory buffer, allocating as we go */
while ((n = read(fd, buf, sizeof buf - 1)) >= 0) {
if (n < (int)(sizeof buf - 1))
end_of_file = 1;
0074-proc/readproc.c: Fix bugs and overflows in file2strvec(). Note: this is by far the most important and complex patch of the whole series, please review it carefully; thank you very much! For this patch, we decided to keep the original function's design and skeleton, to avoid regressions and behavior changes, while fixing the various bugs and overflows. And like the "Harden file2str()" patch, this patch does not fail when about to overflow, but truncates instead: there is information available about this process, so return it to the caller; also, we used INT_MAX as a limit, but a lower limit could be used. The easy changes: - Replace sprintf() with snprintf() (and check for truncation). - Replace "if (n == 0 && rbuf == 0)" with "if (n <= 0 && tot <= 0)" and do break instead of return: it simplifies the code (only one place to handle errors), and also guarantees that in the while loop either n or tot is > 0 (or both), even if n is reset to 0 when about to overflow. - Remove the "if (n < 0)" block in the while loop: it is (and was) dead code, since we enter the while loop only if n >= 0. - Rewrite the missing-null-terminator detection: in the original function, if the size of the file is a multiple of 2047, a null- terminator is appended even if the file is already null-terminated. - Replace "if (n <= 0 && !end_of_file)" with "if (n < 0 || tot <= 0)": originally, it was equivalent to "if (n < 0)", but we added "tot <= 0" to handle the first break of the while loop, and to guarantee that in the rest of the function tot is > 0. - Double-force ("belt and suspenders") the null-termination of rbuf: this is (and was) essential to the correctness of the function. - Replace the final "while" loop with a "for" loop that behaves just like the preceding "for" loop: in the original function, this would lead to unexpected results (for example, if rbuf is |\0|A|\0|, this would return the array {"",NULL} but should return {"","A",NULL}; and if rbuf is |A|\0|B| (should never happen because rbuf should be null- terminated), this would make room for two pointers in ret, but would write three pointers to ret). The hard changes: - Prevent the integer overflow of tot in the while loop, but unlike file2str(), file2strvec() cannot let tot grow until it almost reaches INT_MAX, because it needs more space for the pointers: this is why we introduced ARG_LEN, which also guarantees that we can add "align" and a few sizeof(char*)s to tot without overflowing. - Prevent the integer overflow of "tot + c + align": when INT_MAX is (almost) reached, we write the maximal safe amount of pointers to ret (ARG_LEN guarantees that there is always space for *ret = rbuf and the NULL terminator). ---------------------------- adapted for newlib branch . there were many formatting differences . i introduced several myself (especially comments) . stdlib 'realloc' used, not that home grown xrealloc . stdlib 'realloc' required extra 'return NULL' statement Signed-off-by: Jim Warner <james.warner@comcast.net>
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 */
}
/* 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 */
}
0074-proc/readproc.c: Fix bugs and overflows in file2strvec(). Note: this is by far the most important and complex patch of the whole series, please review it carefully; thank you very much! For this patch, we decided to keep the original function's design and skeleton, to avoid regressions and behavior changes, while fixing the various bugs and overflows. And like the "Harden file2str()" patch, this patch does not fail when about to overflow, but truncates instead: there is information available about this process, so return it to the caller; also, we used INT_MAX as a limit, but a lower limit could be used. The easy changes: - Replace sprintf() with snprintf() (and check for truncation). - Replace "if (n == 0 && rbuf == 0)" with "if (n <= 0 && tot <= 0)" and do break instead of return: it simplifies the code (only one place to handle errors), and also guarantees that in the while loop either n or tot is > 0 (or both), even if n is reset to 0 when about to overflow. - Remove the "if (n < 0)" block in the while loop: it is (and was) dead code, since we enter the while loop only if n >= 0. - Rewrite the missing-null-terminator detection: in the original function, if the size of the file is a multiple of 2047, a null- terminator is appended even if the file is already null-terminated. - Replace "if (n <= 0 && !end_of_file)" with "if (n < 0 || tot <= 0)": originally, it was equivalent to "if (n < 0)", but we added "tot <= 0" to handle the first break of the while loop, and to guarantee that in the rest of the function tot is > 0. - Double-force ("belt and suspenders") the null-termination of rbuf: this is (and was) essential to the correctness of the function. - Replace the final "while" loop with a "for" loop that behaves just like the preceding "for" loop: in the original function, this would lead to unexpected results (for example, if rbuf is |\0|A|\0|, this would return the array {"",NULL} but should return {"","A",NULL}; and if rbuf is |A|\0|B| (should never happen because rbuf should be null- terminated), this would make room for two pointers in ret, but would write three pointers to ret). The hard changes: - Prevent the integer overflow of tot in the while loop, but unlike file2str(), file2strvec() cannot let tot grow until it almost reaches INT_MAX, because it needs more space for the pointers: this is why we introduced ARG_LEN, which also guarantees that we can add "align" and a few sizeof(char*)s to tot without overflowing. - Prevent the integer overflow of "tot + c + align": when INT_MAX is (almost) reached, we write the maximal safe amount of pointers to ret (ARG_LEN guarantees that there is always space for *ret = rbuf and the NULL terminator). ---------------------------- adapted for newlib branch . there were many formatting differences . i introduced several myself (especially comments) . stdlib 'realloc' used, not that home grown xrealloc . stdlib 'realloc' required extra 'return NULL' statement Signed-off-by: Jim Warner <james.warner@comcast.net>
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 */
(n <= 0 && rbuf && rbuf[tot-1] != '\0'))) /* last read char not null */
buf[n++] = '\0'; /* so append null-terminator */
0074-proc/readproc.c: Fix bugs and overflows in file2strvec(). Note: this is by far the most important and complex patch of the whole series, please review it carefully; thank you very much! For this patch, we decided to keep the original function's design and skeleton, to avoid regressions and behavior changes, while fixing the various bugs and overflows. And like the "Harden file2str()" patch, this patch does not fail when about to overflow, but truncates instead: there is information available about this process, so return it to the caller; also, we used INT_MAX as a limit, but a lower limit could be used. The easy changes: - Replace sprintf() with snprintf() (and check for truncation). - Replace "if (n == 0 && rbuf == 0)" with "if (n <= 0 && tot <= 0)" and do break instead of return: it simplifies the code (only one place to handle errors), and also guarantees that in the while loop either n or tot is > 0 (or both), even if n is reset to 0 when about to overflow. - Remove the "if (n < 0)" block in the while loop: it is (and was) dead code, since we enter the while loop only if n >= 0. - Rewrite the missing-null-terminator detection: in the original function, if the size of the file is a multiple of 2047, a null- terminator is appended even if the file is already null-terminated. - Replace "if (n <= 0 && !end_of_file)" with "if (n < 0 || tot <= 0)": originally, it was equivalent to "if (n < 0)", but we added "tot <= 0" to handle the first break of the while loop, and to guarantee that in the rest of the function tot is > 0. - Double-force ("belt and suspenders") the null-termination of rbuf: this is (and was) essential to the correctness of the function. - Replace the final "while" loop with a "for" loop that behaves just like the preceding "for" loop: in the original function, this would lead to unexpected results (for example, if rbuf is |\0|A|\0|, this would return the array {"",NULL} but should return {"","A",NULL}; and if rbuf is |A|\0|B| (should never happen because rbuf should be null- terminated), this would make room for two pointers in ret, but would write three pointers to ret). The hard changes: - Prevent the integer overflow of tot in the while loop, but unlike file2str(), file2strvec() cannot let tot grow until it almost reaches INT_MAX, because it needs more space for the pointers: this is why we introduced ARG_LEN, which also guarantees that we can add "align" and a few sizeof(char*)s to tot without overflowing. - Prevent the integer overflow of "tot + c + align": when INT_MAX is (almost) reached, we write the maximal safe amount of pointers to ret (ARG_LEN guarantees that there is always space for *ret = rbuf and the NULL terminator). ---------------------------- adapted for newlib branch . there were many formatting differences . i introduced several myself (especially comments) . stdlib 'realloc' used, not that home grown xrealloc . stdlib 'realloc' required extra 'return NULL' statement Signed-off-by: Jim Warner <james.warner@comcast.net>
1970-01-01 05:30:00 +05:30
if (n <= 0) break; /* unneeded (end_of_file = 1) but avoid realloc */
rbuf = realloc(rbuf, tot + n); /* allocate more memory */
if (!rbuf) return NULL;
memcpy(rbuf + tot, buf, n); /* copy buffer into it */
tot += n; /* increment total byte ctr */
if (end_of_file)
break;
2002-02-02 04:17:29 +05:30
}
close(fd);
0074-proc/readproc.c: Fix bugs and overflows in file2strvec(). Note: this is by far the most important and complex patch of the whole series, please review it carefully; thank you very much! For this patch, we decided to keep the original function's design and skeleton, to avoid regressions and behavior changes, while fixing the various bugs and overflows. And like the "Harden file2str()" patch, this patch does not fail when about to overflow, but truncates instead: there is information available about this process, so return it to the caller; also, we used INT_MAX as a limit, but a lower limit could be used. The easy changes: - Replace sprintf() with snprintf() (and check for truncation). - Replace "if (n == 0 && rbuf == 0)" with "if (n <= 0 && tot <= 0)" and do break instead of return: it simplifies the code (only one place to handle errors), and also guarantees that in the while loop either n or tot is > 0 (or both), even if n is reset to 0 when about to overflow. - Remove the "if (n < 0)" block in the while loop: it is (and was) dead code, since we enter the while loop only if n >= 0. - Rewrite the missing-null-terminator detection: in the original function, if the size of the file is a multiple of 2047, a null- terminator is appended even if the file is already null-terminated. - Replace "if (n <= 0 && !end_of_file)" with "if (n < 0 || tot <= 0)": originally, it was equivalent to "if (n < 0)", but we added "tot <= 0" to handle the first break of the while loop, and to guarantee that in the rest of the function tot is > 0. - Double-force ("belt and suspenders") the null-termination of rbuf: this is (and was) essential to the correctness of the function. - Replace the final "while" loop with a "for" loop that behaves just like the preceding "for" loop: in the original function, this would lead to unexpected results (for example, if rbuf is |\0|A|\0|, this would return the array {"",NULL} but should return {"","A",NULL}; and if rbuf is |A|\0|B| (should never happen because rbuf should be null- terminated), this would make room for two pointers in ret, but would write three pointers to ret). The hard changes: - Prevent the integer overflow of tot in the while loop, but unlike file2str(), file2strvec() cannot let tot grow until it almost reaches INT_MAX, because it needs more space for the pointers: this is why we introduced ARG_LEN, which also guarantees that we can add "align" and a few sizeof(char*)s to tot without overflowing. - Prevent the integer overflow of "tot + c + align": when INT_MAX is (almost) reached, we write the maximal safe amount of pointers to ret (ARG_LEN guarantees that there is always space for *ret = rbuf and the NULL terminator). ---------------------------- adapted for newlib branch . there were many formatting differences . i introduced several myself (especially comments) . stdlib 'realloc' used, not that home grown xrealloc . stdlib 'realloc' required extra 'return NULL' statement Signed-off-by: Jim Warner <james.warner@comcast.net>
1970-01-01 05:30:00 +05:30
if (n < 0 || tot <= 0) { /* error, or nothing read */
if (rbuf) free(rbuf);
return NULL; /* read error */
2002-02-02 04:17:29 +05:30
}
0074-proc/readproc.c: Fix bugs and overflows in file2strvec(). Note: this is by far the most important and complex patch of the whole series, please review it carefully; thank you very much! For this patch, we decided to keep the original function's design and skeleton, to avoid regressions and behavior changes, while fixing the various bugs and overflows. And like the "Harden file2str()" patch, this patch does not fail when about to overflow, but truncates instead: there is information available about this process, so return it to the caller; also, we used INT_MAX as a limit, but a lower limit could be used. The easy changes: - Replace sprintf() with snprintf() (and check for truncation). - Replace "if (n == 0 && rbuf == 0)" with "if (n <= 0 && tot <= 0)" and do break instead of return: it simplifies the code (only one place to handle errors), and also guarantees that in the while loop either n or tot is > 0 (or both), even if n is reset to 0 when about to overflow. - Remove the "if (n < 0)" block in the while loop: it is (and was) dead code, since we enter the while loop only if n >= 0. - Rewrite the missing-null-terminator detection: in the original function, if the size of the file is a multiple of 2047, a null- terminator is appended even if the file is already null-terminated. - Replace "if (n <= 0 && !end_of_file)" with "if (n < 0 || tot <= 0)": originally, it was equivalent to "if (n < 0)", but we added "tot <= 0" to handle the first break of the while loop, and to guarantee that in the rest of the function tot is > 0. - Double-force ("belt and suspenders") the null-termination of rbuf: this is (and was) essential to the correctness of the function. - Replace the final "while" loop with a "for" loop that behaves just like the preceding "for" loop: in the original function, this would lead to unexpected results (for example, if rbuf is |\0|A|\0|, this would return the array {"",NULL} but should return {"","A",NULL}; and if rbuf is |A|\0|B| (should never happen because rbuf should be null- terminated), this would make room for two pointers in ret, but would write three pointers to ret). The hard changes: - Prevent the integer overflow of tot in the while loop, but unlike file2str(), file2strvec() cannot let tot grow until it almost reaches INT_MAX, because it needs more space for the pointers: this is why we introduced ARG_LEN, which also guarantees that we can add "align" and a few sizeof(char*)s to tot without overflowing. - Prevent the integer overflow of "tot + c + align": when INT_MAX is (almost) reached, we write the maximal safe amount of pointers to ret (ARG_LEN guarantees that there is always space for *ret = rbuf and the NULL terminator). ---------------------------- adapted for newlib branch . there were many formatting differences . i introduced several myself (especially comments) . stdlib 'realloc' used, not that home grown xrealloc . stdlib 'realloc' required extra 'return NULL' statement Signed-off-by: Jim Warner <james.warner@comcast.net>
1970-01-01 05:30:00 +05:30
rbuf[tot-1] = '\0'; /* belt and suspenders (the while loop did it, too) */
endbuf = rbuf + tot; /* count space for pointers */
2002-02-02 04:17:29 +05:30
align = (sizeof(char*)-1) - ((tot + sizeof(char*)-1) & (sizeof(char*)-1));
0074-proc/readproc.c: Fix bugs and overflows in file2strvec(). Note: this is by far the most important and complex patch of the whole series, please review it carefully; thank you very much! For this patch, we decided to keep the original function's design and skeleton, to avoid regressions and behavior changes, while fixing the various bugs and overflows. And like the "Harden file2str()" patch, this patch does not fail when about to overflow, but truncates instead: there is information available about this process, so return it to the caller; also, we used INT_MAX as a limit, but a lower limit could be used. The easy changes: - Replace sprintf() with snprintf() (and check for truncation). - Replace "if (n == 0 && rbuf == 0)" with "if (n <= 0 && tot <= 0)" and do break instead of return: it simplifies the code (only one place to handle errors), and also guarantees that in the while loop either n or tot is > 0 (or both), even if n is reset to 0 when about to overflow. - Remove the "if (n < 0)" block in the while loop: it is (and was) dead code, since we enter the while loop only if n >= 0. - Rewrite the missing-null-terminator detection: in the original function, if the size of the file is a multiple of 2047, a null- terminator is appended even if the file is already null-terminated. - Replace "if (n <= 0 && !end_of_file)" with "if (n < 0 || tot <= 0)": originally, it was equivalent to "if (n < 0)", but we added "tot <= 0" to handle the first break of the while loop, and to guarantee that in the rest of the function tot is > 0. - Double-force ("belt and suspenders") the null-termination of rbuf: this is (and was) essential to the correctness of the function. - Replace the final "while" loop with a "for" loop that behaves just like the preceding "for" loop: in the original function, this would lead to unexpected results (for example, if rbuf is |\0|A|\0|, this would return the array {"",NULL} but should return {"","A",NULL}; and if rbuf is |A|\0|B| (should never happen because rbuf should be null- terminated), this would make room for two pointers in ret, but would write three pointers to ret). The hard changes: - Prevent the integer overflow of tot in the while loop, but unlike file2str(), file2strvec() cannot let tot grow until it almost reaches INT_MAX, because it needs more space for the pointers: this is why we introduced ARG_LEN, which also guarantees that we can add "align" and a few sizeof(char*)s to tot without overflowing. - Prevent the integer overflow of "tot + c + align": when INT_MAX is (almost) reached, we write the maximal safe amount of pointers to ret (ARG_LEN guarantees that there is always space for *ret = rbuf and the NULL terminator). ---------------------------- adapted for newlib branch . there were many formatting differences . i introduced several myself (especially comments) . stdlib 'realloc' used, not that home grown xrealloc . stdlib 'realloc' required extra 'return NULL' statement Signed-off-by: Jim Warner <james.warner@comcast.net>
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;
c += sizeof(char*);
0074-proc/readproc.c: Fix bugs and overflows in file2strvec(). Note: this is by far the most important and complex patch of the whole series, please review it carefully; thank you very much! For this patch, we decided to keep the original function's design and skeleton, to avoid regressions and behavior changes, while fixing the various bugs and overflows. And like the "Harden file2str()" patch, this patch does not fail when about to overflow, but truncates instead: there is information available about this process, so return it to the caller; also, we used INT_MAX as a limit, but a lower limit could be used. The easy changes: - Replace sprintf() with snprintf() (and check for truncation). - Replace "if (n == 0 && rbuf == 0)" with "if (n <= 0 && tot <= 0)" and do break instead of return: it simplifies the code (only one place to handle errors), and also guarantees that in the while loop either n or tot is > 0 (or both), even if n is reset to 0 when about to overflow. - Remove the "if (n < 0)" block in the while loop: it is (and was) dead code, since we enter the while loop only if n >= 0. - Rewrite the missing-null-terminator detection: in the original function, if the size of the file is a multiple of 2047, a null- terminator is appended even if the file is already null-terminated. - Replace "if (n <= 0 && !end_of_file)" with "if (n < 0 || tot <= 0)": originally, it was equivalent to "if (n < 0)", but we added "tot <= 0" to handle the first break of the while loop, and to guarantee that in the rest of the function tot is > 0. - Double-force ("belt and suspenders") the null-termination of rbuf: this is (and was) essential to the correctness of the function. - Replace the final "while" loop with a "for" loop that behaves just like the preceding "for" loop: in the original function, this would lead to unexpected results (for example, if rbuf is |\0|A|\0|, this would return the array {"",NULL} but should return {"","A",NULL}; and if rbuf is |A|\0|B| (should never happen because rbuf should be null- terminated), this would make room for two pointers in ret, but would write three pointers to ret). The hard changes: - Prevent the integer overflow of tot in the while loop, but unlike file2str(), file2strvec() cannot let tot grow until it almost reaches INT_MAX, because it needs more space for the pointers: this is why we introduced ARG_LEN, which also guarantees that we can add "align" and a few sizeof(char*)s to tot without overflowing. - Prevent the integer overflow of "tot + c + align": when INT_MAX is (almost) reached, we write the maximal safe amount of pointers to ret (ARG_LEN guarantees that there is always space for *ret = rbuf and the NULL terminator). ---------------------------- adapted for newlib branch . there were many formatting differences . i introduced several myself (especially comments) . stdlib 'realloc' used, not that home grown xrealloc . stdlib 'realloc' required extra 'return NULL' statement Signed-off-by: Jim Warner <james.warner@comcast.net>
1970-01-01 05:30:00 +05:30
}
if (*p == '\n')
*p = 0;
}
2002-02-02 04:17:29 +05:30
rbuf = realloc(rbuf, tot + c + align); /* make room for ptrs AT END */
if (!rbuf) return NULL;
endbuf = rbuf + tot; /* addr just past data buf */
q = ret = (char**) (endbuf+align); /* ==> free(*ret) to dealloc */
0074-proc/readproc.c: Fix bugs and overflows in file2strvec(). Note: this is by far the most important and complex patch of the whole series, please review it carefully; thank you very much! For this patch, we decided to keep the original function's design and skeleton, to avoid regressions and behavior changes, while fixing the various bugs and overflows. And like the "Harden file2str()" patch, this patch does not fail when about to overflow, but truncates instead: there is information available about this process, so return it to the caller; also, we used INT_MAX as a limit, but a lower limit could be used. The easy changes: - Replace sprintf() with snprintf() (and check for truncation). - Replace "if (n == 0 && rbuf == 0)" with "if (n <= 0 && tot <= 0)" and do break instead of return: it simplifies the code (only one place to handle errors), and also guarantees that in the while loop either n or tot is > 0 (or both), even if n is reset to 0 when about to overflow. - Remove the "if (n < 0)" block in the while loop: it is (and was) dead code, since we enter the while loop only if n >= 0. - Rewrite the missing-null-terminator detection: in the original function, if the size of the file is a multiple of 2047, a null- terminator is appended even if the file is already null-terminated. - Replace "if (n <= 0 && !end_of_file)" with "if (n < 0 || tot <= 0)": originally, it was equivalent to "if (n < 0)", but we added "tot <= 0" to handle the first break of the while loop, and to guarantee that in the rest of the function tot is > 0. - Double-force ("belt and suspenders") the null-termination of rbuf: this is (and was) essential to the correctness of the function. - Replace the final "while" loop with a "for" loop that behaves just like the preceding "for" loop: in the original function, this would lead to unexpected results (for example, if rbuf is |\0|A|\0|, this would return the array {"",NULL} but should return {"","A",NULL}; and if rbuf is |A|\0|B| (should never happen because rbuf should be null- terminated), this would make room for two pointers in ret, but would write three pointers to ret). The hard changes: - Prevent the integer overflow of tot in the while loop, but unlike file2str(), file2strvec() cannot let tot grow until it almost reaches INT_MAX, because it needs more space for the pointers: this is why we introduced ARG_LEN, which also guarantees that we can add "align" and a few sizeof(char*)s to tot without overflowing. - Prevent the integer overflow of "tot + c + align": when INT_MAX is (almost) reached, we write the maximal safe amount of pointers to ret (ARG_LEN guarantees that there is always space for *ret = rbuf and the NULL terminator). ---------------------------- adapted for newlib branch . there were many formatting differences . i introduced several myself (especially comments) . stdlib 'realloc' used, not that home grown xrealloc . stdlib 'realloc' required extra 'return NULL' statement Signed-off-by: Jim Warner <james.warner@comcast.net>
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 */
}
}
*q = 0; /* null ptr list terminator */
2002-02-02 04:17:29 +05:30
return ret;
}
enhanced libproc cgroup/cmdline support, exploited by top Library Changes . added PROC_EDITCMDLCVT flag . added an internal (static) fill_cmdline_cvt function: - reads and "escapes" /proc/#/cmdline - returns result as a single string in a single vector - callers are guaranteed a cmdline (no more NULL) . added vectorize_this_str function, exploited by fill_cgroup_cvt, fill_cmdline_cvt . generalized read_cmdline function as read_unvectored, now exploited by fill_cgroup_cvt, fill_cmdline_cvt, read_cmdline ( cgroup and cmdline no longer need be converted to string ) ( vectors before being transformed to final representation ) . fixed bug regarding skipped group numbers (when enabled) . escape_str made responsible for all single byte translation with distinction between control chars + other unprintable . added escaped_copy function for already escaped strings . reorganized parts of proc_t to restore formatting standards ( displacement changes shouldn't matter with new version # ) . former ZAP_SUSEONLY #define now OOMEM_ENABLE . added to library.map: escaped_copy; read_cmdline Top Program Changes . exploited the new PROC_EDITCMDLCVT provision . eliminated now obsolete #include "proc/escape.h" . changed the P_WCH display format if no kernel symbol table . fixed very old bug in lflgs for out-of-view sort fields . former ZAP_SUSEONLY #define now OOMEM_ENABLE Ps Program Changes . exploited the new PROC_EDITCMDLCVT provision . exploited the new escaped_copy function . consolidated pr_args and pr_comm into pr_argcom Signed-off-by: Jan Görig <jgorig@redhat.com>
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:
// PROC_EDITCGRPCVT, PROC_EDITCMDLCVT and PROC_EDITENVRCVT
static int read_unvectored(char *restrict const dst, unsigned sz, const char* whom, const char *what, char sep) {
char path[PROCPATHLEN];
int fd, len;
2002-12-03 14:48:27 +05:30
unsigned n = 0;
enhanced libproc cgroup/cmdline support, exploited by top Library Changes . added PROC_EDITCMDLCVT flag . added an internal (static) fill_cmdline_cvt function: - reads and "escapes" /proc/#/cmdline - returns result as a single string in a single vector - callers are guaranteed a cmdline (no more NULL) . added vectorize_this_str function, exploited by fill_cgroup_cvt, fill_cmdline_cvt . generalized read_cmdline function as read_unvectored, now exploited by fill_cgroup_cvt, fill_cmdline_cvt, read_cmdline ( cgroup and cmdline no longer need be converted to string ) ( vectors before being transformed to final representation ) . fixed bug regarding skipped group numbers (when enabled) . escape_str made responsible for all single byte translation with distinction between control chars + other unprintable . added escaped_copy function for already escaped strings . reorganized parts of proc_t to restore formatting standards ( displacement changes shouldn't matter with new version # ) . former ZAP_SUSEONLY #define now OOMEM_ENABLE . added to library.map: escaped_copy; read_cmdline Top Program Changes . exploited the new PROC_EDITCMDLCVT provision . eliminated now obsolete #include "proc/escape.h" . changed the P_WCH display format if no kernel symbol table . fixed very old bug in lflgs for out-of-view sort fields . former ZAP_SUSEONLY #define now OOMEM_ENABLE Ps Program Changes . exploited the new PROC_EDITCMDLCVT provision . exploited the new escaped_copy function . consolidated pr_args and pr_comm into pr_argcom Signed-off-by: Jan Görig <jgorig@redhat.com>
2011-05-18 14:03:44 +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;
fd = open(path, O_RDONLY);
2002-12-03 14:48:27 +05:30
if(fd==-1) return 0;
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;
}
if(r<=0) break; // EOF
2002-12-03 14:37:59 +05:30
n += r;
enhanced libproc cgroup/cmdline support, exploited by top Library Changes . added PROC_EDITCMDLCVT flag . added an internal (static) fill_cmdline_cvt function: - reads and "escapes" /proc/#/cmdline - returns result as a single string in a single vector - callers are guaranteed a cmdline (no more NULL) . added vectorize_this_str function, exploited by fill_cgroup_cvt, fill_cmdline_cvt . generalized read_cmdline function as read_unvectored, now exploited by fill_cgroup_cvt, fill_cmdline_cvt, read_cmdline ( cgroup and cmdline no longer need be converted to string ) ( vectors before being transformed to final representation ) . fixed bug regarding skipped group numbers (when enabled) . escape_str made responsible for all single byte translation with distinction between control chars + other unprintable . added escaped_copy function for already escaped strings . reorganized parts of proc_t to restore formatting standards ( displacement changes shouldn't matter with new version # ) . former ZAP_SUSEONLY #define now OOMEM_ENABLE . added to library.map: escaped_copy; read_cmdline Top Program Changes . exploited the new PROC_EDITCMDLCVT provision . eliminated now obsolete #include "proc/escape.h" . changed the P_WCH display format if no kernel symbol table . fixed very old bug in lflgs for out-of-view sort fields . former ZAP_SUSEONLY #define now OOMEM_ENABLE Ps Program Changes . exploited the new PROC_EDITCMDLCVT provision . exploited the new escaped_copy function . consolidated pr_args and pr_comm into pr_argcom Signed-off-by: Jan Görig <jgorig@redhat.com>
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
}
close(fd);
2002-12-03 14:37:59 +05:30
if(n){
unsigned i = n;
while(i && dst[i-1]=='\0') --i; // skip trailing zeroes
enhanced libproc cgroup/cmdline support, exploited by top Library Changes . added PROC_EDITCMDLCVT flag . added an internal (static) fill_cmdline_cvt function: - reads and "escapes" /proc/#/cmdline - returns result as a single string in a single vector - callers are guaranteed a cmdline (no more NULL) . added vectorize_this_str function, exploited by fill_cgroup_cvt, fill_cmdline_cvt . generalized read_cmdline function as read_unvectored, now exploited by fill_cgroup_cvt, fill_cmdline_cvt, read_cmdline ( cgroup and cmdline no longer need be converted to string ) ( vectors before being transformed to final representation ) . fixed bug regarding skipped group numbers (when enabled) . escape_str made responsible for all single byte translation with distinction between control chars + other unprintable . added escaped_copy function for already escaped strings . reorganized parts of proc_t to restore formatting standards ( displacement changes shouldn't matter with new version # ) . former ZAP_SUSEONLY #define now OOMEM_ENABLE . added to library.map: escaped_copy; read_cmdline Top Program Changes . exploited the new PROC_EDITCMDLCVT provision . eliminated now obsolete #include "proc/escape.h" . changed the P_WCH display format if no kernel symbol table . fixed very old bug in lflgs for out-of-view sort fields . former ZAP_SUSEONLY #define now OOMEM_ENABLE Ps Program Changes . exploited the new PROC_EDITCMDLCVT provision . exploited the new escaped_copy function . consolidated pr_args and pr_comm into pr_argcom Signed-off-by: Jan Görig <jgorig@redhat.com>
2011-05-18 14:03:44 +05:30
while(i--)
if(dst[i]=='\n' || dst[i]=='\0') dst[i]=sep;
if(dst[n-1]==' ') dst[n-1]='\0';
2002-12-03 14:37:59 +05:30
}
enhanced libproc cgroup/cmdline support, exploited by top Library Changes . added PROC_EDITCMDLCVT flag . added an internal (static) fill_cmdline_cvt function: - reads and "escapes" /proc/#/cmdline - returns result as a single string in a single vector - callers are guaranteed a cmdline (no more NULL) . added vectorize_this_str function, exploited by fill_cgroup_cvt, fill_cmdline_cvt . generalized read_cmdline function as read_unvectored, now exploited by fill_cgroup_cvt, fill_cmdline_cvt, read_cmdline ( cgroup and cmdline no longer need be converted to string ) ( vectors before being transformed to final representation ) . fixed bug regarding skipped group numbers (when enabled) . escape_str made responsible for all single byte translation with distinction between control chars + other unprintable . added escaped_copy function for already escaped strings . reorganized parts of proc_t to restore formatting standards ( displacement changes shouldn't matter with new version # ) . former ZAP_SUSEONLY #define now OOMEM_ENABLE . added to library.map: escaped_copy; read_cmdline Top Program Changes . exploited the new PROC_EDITCMDLCVT provision . eliminated now obsolete #include "proc/escape.h" . changed the P_WCH display format if no kernel symbol table . fixed very old bug in lflgs for out-of-view sort fields . former ZAP_SUSEONLY #define now OOMEM_ENABLE Ps Program Changes . exploited the new PROC_EDITCMDLCVT provision . exploited the new escaped_copy function . consolidated pr_args and pr_comm into pr_argcom Signed-off-by: Jan Görig <jgorig@redhat.com>
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
char** vectorize_this_str (const char* src) {
#define pSZ (sizeof(char*))
char *cpy, **vec;
size_t adj, tot;
tot = strlen(src) + 1; // prep for our vectors
if (tot < 1 || tot >= INT_MAX) tot = INT_MAX-1; // integer overflow?
adj = (pSZ-1) - ((tot + pSZ-1) & (pSZ-1)); // calc alignment bytes
cpy = calloc(1, tot + adj + (2 * pSZ)); // get new larger buffer
if (!cpy) return NULL; // oops, looks like ENOMEM
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
}
// This littl' guy just serves those true vectorized fields
// ( when a /proc source field didn't exist )
static int vectorize_dash_rc (char*** vec) {
if (!(*vec = vectorize_this_str("-")))
return 1;
return 0;
}
library: eliminated a final potential NULL, <PIDS> api In that reference below a specific systemd problem was fixed in the commit shown. However lurking deep within the <pids> interface was yet one final case where NULL could be returned, involving 'strv' and the following: . a user requested both a single string vector (always returned as a normal string) & the vectorized version, as with PROCPS_PIDS_CMDLINE and PROCPS_PIDS_CMDLINE_V. . a user simply duplicated some vectorized enum items. The root of that NULL problem is the fact those single string vectors shared the same proc_t field with their true vectorized version. So while multiple occurrences for most strings could be satisfied with strdup versus the normal ownership usurpation, those true vectorized fields could not be quite so easily copied/duplicated. Thus newlib chose to return a NULL result.strv pointer under either of the above scenarios (which perhaps was just a user boo-boo in the first place). In any event, the NULL was a potential for true string vectors only. Now, since newlib is the sole caller into the readproc module, separate fields have been created for what are just normal strings (never vectorized) and those which remain the true vectorized versions. And, former flags which only worked if combined, now act as stand alone. Thus, both PROCPS_PIDS_CMDLINE & PROCPS_PIDS_CMDLINE_V can be used simultaneously (as they should have been). Also with this patch, items which a user duplicates in the stack (beyond the first such item) will return the the string "[ duplicate ENUM_ID ]". This practice will apply to both single strings and true vectorized ones. In addition to informing users of their error, it will also mean potential NULLs need now never be a concern. Reference(s); http://www.freelists.org/post/procps/systemd-binary-vs-library commit 0580a7b4c67d0297629d37281b4f690894429626 Signed-off-by: Jim Warner <james.warner@comcast.net>
2016-05-19 10:30:00 +05:30
// This routine reads a 'cgroup' for the designated proc_t and
// guarantees the caller a valid proc_t.cgroup pointer.
static int fill_cgroup_cvt (const char* directory, proc_t *restrict p) {
#define vMAX ( MAX_BUFSZ - (int)(dst - dst_buffer) )
library: eliminated a final potential NULL, <PIDS> api In that reference below a specific systemd problem was fixed in the commit shown. However lurking deep within the <pids> interface was yet one final case where NULL could be returned, involving 'strv' and the following: . a user requested both a single string vector (always returned as a normal string) & the vectorized version, as with PROCPS_PIDS_CMDLINE and PROCPS_PIDS_CMDLINE_V. . a user simply duplicated some vectorized enum items. The root of that NULL problem is the fact those single string vectors shared the same proc_t field with their true vectorized version. So while multiple occurrences for most strings could be satisfied with strdup versus the normal ownership usurpation, those true vectorized fields could not be quite so easily copied/duplicated. Thus newlib chose to return a NULL result.strv pointer under either of the above scenarios (which perhaps was just a user boo-boo in the first place). In any event, the NULL was a potential for true string vectors only. Now, since newlib is the sole caller into the readproc module, separate fields have been created for what are just normal strings (never vectorized) and those which remain the true vectorized versions. And, former flags which only worked if combined, now act as stand alone. Thus, both PROCPS_PIDS_CMDLINE & PROCPS_PIDS_CMDLINE_V can be used simultaneously (as they should have been). Also with this patch, items which a user duplicates in the stack (beyond the first such item) will return the the string "[ duplicate ENUM_ID ]". This practice will apply to both single strings and true vectorized ones. In addition to informing users of their error, it will also mean potential NULLs need now never be a concern. Reference(s); http://www.freelists.org/post/procps/systemd-binary-vs-library commit 0580a7b4c67d0297629d37281b4f690894429626 Signed-off-by: Jim Warner <james.warner@comcast.net>
2016-05-19 10:30:00 +05:30
char *src, *dst, *grp, *eob, *name;
library: refactor 'escape' logic for newlib essentials This new library provides callers with pure strings or string vectors. It is up to those callers to deal with potential utf8 multibyte characters and any difference between strlen and the corresponding printable widths. So, it makes no sense for the library to go to all the trouble of invoking those rather expensive 'mbrtowc' & 'wcwidth' functions to ultimately yield total 'cells'. Thus, this patch will eliminate all the code and parms that are involved with such possible multibyte issues. [ Along the way we'll lose the ability to substitute ] [ '?' for an invalid/unprintable multibyte sequence. ] [ We will, however, replace ctrl chars with the '?'. ] [ This presents no problem for that ps program since ] [ it now duplicates all of the original escape code. ] [ And, we'll no longer be executing that code twice! ] [ As for the top program, it takes the position that ] [ it is wrong to alter kernel supplied data. So with ] [ potential invalid/unprintable stuff, he'll rely on ] [ terminal emulators to properly handle such issues! ] [ Besides, even using a proper multibyte string, not ] [ all terminals generate the proper printable width. ] [ This is especially true when it comes to an emoji. ] [ And should callers chose not to be portable to all ] [ locales by calling setlocale(LC_ALL, ""), they can ] [ expect to see lots of "?", regardless of what this ] [ library fixes in a faulty multibyte string anyway. ] Signed-off-by: Jim Warner <james.warner@comcast.net>
2020-12-24 11:30:00 +05:30
int tot, x, len;
enhanced libproc cgroup/cmdline support, exploited by top Library Changes . added PROC_EDITCMDLCVT flag . added an internal (static) fill_cmdline_cvt function: - reads and "escapes" /proc/#/cmdline - returns result as a single string in a single vector - callers are guaranteed a cmdline (no more NULL) . added vectorize_this_str function, exploited by fill_cgroup_cvt, fill_cmdline_cvt . generalized read_cmdline function as read_unvectored, now exploited by fill_cgroup_cvt, fill_cmdline_cvt, read_cmdline ( cgroup and cmdline no longer need be converted to string ) ( vectors before being transformed to final representation ) . fixed bug regarding skipped group numbers (when enabled) . escape_str made responsible for all single byte translation with distinction between control chars + other unprintable . added escaped_copy function for already escaped strings . reorganized parts of proc_t to restore formatting standards ( displacement changes shouldn't matter with new version # ) . former ZAP_SUSEONLY #define now OOMEM_ENABLE . added to library.map: escaped_copy; read_cmdline Top Program Changes . exploited the new PROC_EDITCMDLCVT provision . eliminated now obsolete #include "proc/escape.h" . changed the P_WCH display format if no kernel symbol table . fixed very old bug in lflgs for out-of-view sort fields . former ZAP_SUSEONLY #define now OOMEM_ENABLE Ps Program Changes . exploited the new PROC_EDITCMDLCVT provision . exploited the new escaped_copy function . consolidated pr_args and pr_comm into pr_argcom Signed-off-by: Jan Görig <jgorig@redhat.com>
2011-05-18 14:03:44 +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) {
enhanced libproc cgroup/cmdline support, exploited by top Library Changes . added PROC_EDITCMDLCVT flag . added an internal (static) fill_cmdline_cvt function: - reads and "escapes" /proc/#/cmdline - returns result as a single string in a single vector - callers are guaranteed a cmdline (no more NULL) . added vectorize_this_str function, exploited by fill_cgroup_cvt, fill_cmdline_cvt . generalized read_cmdline function as read_unvectored, now exploited by fill_cgroup_cvt, fill_cmdline_cvt, read_cmdline ( cgroup and cmdline no longer need be converted to string ) ( vectors before being transformed to final representation ) . fixed bug regarding skipped group numbers (when enabled) . escape_str made responsible for all single byte translation with distinction between control chars + other unprintable . added escaped_copy function for already escaped strings . reorganized parts of proc_t to restore formatting standards ( displacement changes shouldn't matter with new version # ) . former ZAP_SUSEONLY #define now OOMEM_ENABLE . added to library.map: escaped_copy; read_cmdline Top Program Changes . exploited the new PROC_EDITCMDLCVT provision . eliminated now obsolete #include "proc/escape.h" . changed the P_WCH display format if no kernel symbol table . fixed very old bug in lflgs for out-of-view sort fields . former ZAP_SUSEONLY #define now OOMEM_ENABLE Ps Program Changes . exploited the new PROC_EDITCMDLCVT provision . exploited the new escaped_copy function . consolidated pr_args and pr_comm into pr_argcom Signed-off-by: Jan Görig <jgorig@redhat.com>
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
if (vMAX <= 1) break;
len = snprintf(dst, vMAX, "%s", (dst > dst_buffer) ? "," : "");
if (len < 0 || len >= vMAX) break;
dst += len;
library: refactor 'escape' logic for newlib essentials This new library provides callers with pure strings or string vectors. It is up to those callers to deal with potential utf8 multibyte characters and any difference between strlen and the corresponding printable widths. So, it makes no sense for the library to go to all the trouble of invoking those rather expensive 'mbrtowc' & 'wcwidth' functions to ultimately yield total 'cells'. Thus, this patch will eliminate all the code and parms that are involved with such possible multibyte issues. [ Along the way we'll lose the ability to substitute ] [ '?' for an invalid/unprintable multibyte sequence. ] [ We will, however, replace ctrl chars with the '?'. ] [ This presents no problem for that ps program since ] [ it now duplicates all of the original escape code. ] [ And, we'll no longer be executing that code twice! ] [ As for the top program, it takes the position that ] [ it is wrong to alter kernel supplied data. So with ] [ potential invalid/unprintable stuff, he'll rely on ] [ terminal emulators to properly handle such issues! ] [ Besides, even using a proper multibyte string, not ] [ all terminals generate the proper printable width. ] [ This is especially true when it comes to an emoji. ] [ And should callers chose not to be portable to all ] [ locales by calling setlocale(LC_ALL, ""), they can ] [ expect to see lots of "?", regardless of what this ] [ library fixes in a faulty multibyte string anyway. ] Signed-off-by: Jim Warner <james.warner@comcast.net>
2020-12-24 11:30:00 +05:30
dst += escape_str(dst, grp, vMAX);
enhanced libproc cgroup/cmdline support, exploited by top Library Changes . added PROC_EDITCMDLCVT flag . added an internal (static) fill_cmdline_cvt function: - reads and "escapes" /proc/#/cmdline - returns result as a single string in a single vector - callers are guaranteed a cmdline (no more NULL) . added vectorize_this_str function, exploited by fill_cgroup_cvt, fill_cmdline_cvt . generalized read_cmdline function as read_unvectored, now exploited by fill_cgroup_cvt, fill_cmdline_cvt, read_cmdline ( cgroup and cmdline no longer need be converted to string ) ( vectors before being transformed to final representation ) . fixed bug regarding skipped group numbers (when enabled) . escape_str made responsible for all single byte translation with distinction between control chars + other unprintable . added escaped_copy function for already escaped strings . reorganized parts of proc_t to restore formatting standards ( displacement changes shouldn't matter with new version # ) . former ZAP_SUSEONLY #define now OOMEM_ENABLE . added to library.map: escaped_copy; read_cmdline Top Program Changes . exploited the new PROC_EDITCMDLCVT provision . eliminated now obsolete #include "proc/escape.h" . changed the P_WCH display format if no kernel symbol table . fixed very old bug in lflgs for out-of-view sort fields . former ZAP_SUSEONLY #define now OOMEM_ENABLE Ps Program Changes . exploited the new PROC_EDITCMDLCVT provision . exploited the new escaped_copy function . consolidated pr_args and pr_comm into pr_argcom Signed-off-by: Jan Görig <jgorig@redhat.com>
2011-05-18 14:03:44 +05:30
}
if (!(p->cgroup = strdup(dst_buffer[0] ? dst_buffer : "-")))
return 1;
library: eliminated a final potential NULL, <PIDS> api In that reference below a specific systemd problem was fixed in the commit shown. However lurking deep within the <pids> interface was yet one final case where NULL could be returned, involving 'strv' and the following: . a user requested both a single string vector (always returned as a normal string) & the vectorized version, as with PROCPS_PIDS_CMDLINE and PROCPS_PIDS_CMDLINE_V. . a user simply duplicated some vectorized enum items. The root of that NULL problem is the fact those single string vectors shared the same proc_t field with their true vectorized version. So while multiple occurrences for most strings could be satisfied with strdup versus the normal ownership usurpation, those true vectorized fields could not be quite so easily copied/duplicated. Thus newlib chose to return a NULL result.strv pointer under either of the above scenarios (which perhaps was just a user boo-boo in the first place). In any event, the NULL was a potential for true string vectors only. Now, since newlib is the sole caller into the readproc module, separate fields have been created for what are just normal strings (never vectorized) and those which remain the true vectorized versions. And, former flags which only worked if combined, now act as stand alone. Thus, both PROCPS_PIDS_CMDLINE & PROCPS_PIDS_CMDLINE_V can be used simultaneously (as they should have been). Also with this patch, items which a user duplicates in the stack (beyond the first such item) will return the the string "[ duplicate ENUM_ID ]". This practice will apply to both single strings and true vectorized ones. In addition to informing users of their error, it will also mean potential NULLs need now never be a concern. Reference(s); http://www.freelists.org/post/procps/systemd-binary-vs-library commit 0580a7b4c67d0297629d37281b4f690894429626 Signed-off-by: Jim Warner <james.warner@comcast.net>
2016-05-19 10:30:00 +05:30
name = strstr(p->cgroup, ":name=");
if (name && *(name+6)) name += 6; else name = p->cgroup;
if (!(p->cgname = strdup(name)))
return 1;
return 0;
#undef vMAX
}
// This routine reads a 'cmdline' for the designated proc_t, "escapes"
library: eliminated a final potential NULL, <PIDS> api In that reference below a specific systemd problem was fixed in the commit shown. However lurking deep within the <pids> interface was yet one final case where NULL could be returned, involving 'strv' and the following: . a user requested both a single string vector (always returned as a normal string) & the vectorized version, as with PROCPS_PIDS_CMDLINE and PROCPS_PIDS_CMDLINE_V. . a user simply duplicated some vectorized enum items. The root of that NULL problem is the fact those single string vectors shared the same proc_t field with their true vectorized version. So while multiple occurrences for most strings could be satisfied with strdup versus the normal ownership usurpation, those true vectorized fields could not be quite so easily copied/duplicated. Thus newlib chose to return a NULL result.strv pointer under either of the above scenarios (which perhaps was just a user boo-boo in the first place). In any event, the NULL was a potential for true string vectors only. Now, since newlib is the sole caller into the readproc module, separate fields have been created for what are just normal strings (never vectorized) and those which remain the true vectorized versions. And, former flags which only worked if combined, now act as stand alone. Thus, both PROCPS_PIDS_CMDLINE & PROCPS_PIDS_CMDLINE_V can be used simultaneously (as they should have been). Also with this patch, items which a user duplicates in the stack (beyond the first such item) will return the the string "[ duplicate ENUM_ID ]". This practice will apply to both single strings and true vectorized ones. In addition to informing users of their error, it will also mean potential NULLs need now never be a concern. Reference(s); http://www.freelists.org/post/procps/systemd-binary-vs-library commit 0580a7b4c67d0297629d37281b4f690894429626 Signed-off-by: Jim Warner <james.warner@comcast.net>
2016-05-19 10:30:00 +05:30
// the result into a single string while guaranteeing the caller a
// valid proc_t.cmdline pointer.
static int fill_cmdline_cvt (const char* directory, proc_t *restrict p) {
enhanced libproc cgroup/cmdline support, exploited by top Library Changes . added PROC_EDITCMDLCVT flag . added an internal (static) fill_cmdline_cvt function: - reads and "escapes" /proc/#/cmdline - returns result as a single string in a single vector - callers are guaranteed a cmdline (no more NULL) . added vectorize_this_str function, exploited by fill_cgroup_cvt, fill_cmdline_cvt . generalized read_cmdline function as read_unvectored, now exploited by fill_cgroup_cvt, fill_cmdline_cvt, read_cmdline ( cgroup and cmdline no longer need be converted to string ) ( vectors before being transformed to final representation ) . fixed bug regarding skipped group numbers (when enabled) . escape_str made responsible for all single byte translation with distinction between control chars + other unprintable . added escaped_copy function for already escaped strings . reorganized parts of proc_t to restore formatting standards ( displacement changes shouldn't matter with new version # ) . former ZAP_SUSEONLY #define now OOMEM_ENABLE . added to library.map: escaped_copy; read_cmdline Top Program Changes . exploited the new PROC_EDITCMDLCVT provision . eliminated now obsolete #include "proc/escape.h" . changed the P_WCH display format if no kernel symbol table . fixed very old bug in lflgs for out-of-view sort fields . former ZAP_SUSEONLY #define now OOMEM_ENABLE Ps Program Changes . exploited the new PROC_EDITCMDLCVT provision . exploited the new escaped_copy function . consolidated pr_args and pr_comm into pr_argcom Signed-off-by: Jan Görig <jgorig@redhat.com>
2011-05-18 14:03:44 +05:30
#define uFLG ( ESC_BRACKETS | ESC_DEFUNCT )
if (read_unvectored(src_buffer, MAX_BUFSZ, directory, "cmdline", ' '))
library: refactor 'escape' logic for newlib essentials This new library provides callers with pure strings or string vectors. It is up to those callers to deal with potential utf8 multibyte characters and any difference between strlen and the corresponding printable widths. So, it makes no sense for the library to go to all the trouble of invoking those rather expensive 'mbrtowc' & 'wcwidth' functions to ultimately yield total 'cells'. Thus, this patch will eliminate all the code and parms that are involved with such possible multibyte issues. [ Along the way we'll lose the ability to substitute ] [ '?' for an invalid/unprintable multibyte sequence. ] [ We will, however, replace ctrl chars with the '?'. ] [ This presents no problem for that ps program since ] [ it now duplicates all of the original escape code. ] [ And, we'll no longer be executing that code twice! ] [ As for the top program, it takes the position that ] [ it is wrong to alter kernel supplied data. So with ] [ potential invalid/unprintable stuff, he'll rely on ] [ terminal emulators to properly handle such issues! ] [ Besides, even using a proper multibyte string, not ] [ all terminals generate the proper printable width. ] [ This is especially true when it comes to an emoji. ] [ And should callers chose not to be portable to all ] [ locales by calling setlocale(LC_ALL, ""), they can ] [ expect to see lots of "?", regardless of what this ] [ library fixes in a faulty multibyte string anyway. ] Signed-off-by: Jim Warner <james.warner@comcast.net>
2020-12-24 11:30:00 +05:30
escape_str(dst_buffer, src_buffer, MAX_BUFSZ);
enhanced libproc cgroup/cmdline support, exploited by top Library Changes . added PROC_EDITCMDLCVT flag . added an internal (static) fill_cmdline_cvt function: - reads and "escapes" /proc/#/cmdline - returns result as a single string in a single vector - callers are guaranteed a cmdline (no more NULL) . added vectorize_this_str function, exploited by fill_cgroup_cvt, fill_cmdline_cvt . generalized read_cmdline function as read_unvectored, now exploited by fill_cgroup_cvt, fill_cmdline_cvt, read_cmdline ( cgroup and cmdline no longer need be converted to string ) ( vectors before being transformed to final representation ) . fixed bug regarding skipped group numbers (when enabled) . escape_str made responsible for all single byte translation with distinction between control chars + other unprintable . added escaped_copy function for already escaped strings . reorganized parts of proc_t to restore formatting standards ( displacement changes shouldn't matter with new version # ) . former ZAP_SUSEONLY #define now OOMEM_ENABLE . added to library.map: escaped_copy; read_cmdline Top Program Changes . exploited the new PROC_EDITCMDLCVT provision . eliminated now obsolete #include "proc/escape.h" . changed the P_WCH display format if no kernel symbol table . fixed very old bug in lflgs for out-of-view sort fields . former ZAP_SUSEONLY #define now OOMEM_ENABLE Ps Program Changes . exploited the new PROC_EDITCMDLCVT provision . exploited the new escaped_copy function . consolidated pr_args and pr_comm into pr_argcom Signed-off-by: Jan Görig <jgorig@redhat.com>
2011-05-18 14:03:44 +05:30
else
library: refactor 'escape' logic for newlib essentials This new library provides callers with pure strings or string vectors. It is up to those callers to deal with potential utf8 multibyte characters and any difference between strlen and the corresponding printable widths. So, it makes no sense for the library to go to all the trouble of invoking those rather expensive 'mbrtowc' & 'wcwidth' functions to ultimately yield total 'cells'. Thus, this patch will eliminate all the code and parms that are involved with such possible multibyte issues. [ Along the way we'll lose the ability to substitute ] [ '?' for an invalid/unprintable multibyte sequence. ] [ We will, however, replace ctrl chars with the '?'. ] [ This presents no problem for that ps program since ] [ it now duplicates all of the original escape code. ] [ And, we'll no longer be executing that code twice! ] [ As for the top program, it takes the position that ] [ it is wrong to alter kernel supplied data. So with ] [ potential invalid/unprintable stuff, he'll rely on ] [ terminal emulators to properly handle such issues! ] [ Besides, even using a proper multibyte string, not ] [ all terminals generate the proper printable width. ] [ This is especially true when it comes to an emoji. ] [ And should callers chose not to be portable to all ] [ locales by calling setlocale(LC_ALL, ""), they can ] [ expect to see lots of "?", regardless of what this ] [ library fixes in a faulty multibyte string anyway. ] Signed-off-by: Jim Warner <james.warner@comcast.net>
2020-12-24 11:30:00 +05:30
escape_command(dst_buffer, p, MAX_BUFSZ, uFLG);
library: eliminated a final potential NULL, <PIDS> api In that reference below a specific systemd problem was fixed in the commit shown. However lurking deep within the <pids> interface was yet one final case where NULL could be returned, involving 'strv' and the following: . a user requested both a single string vector (always returned as a normal string) & the vectorized version, as with PROCPS_PIDS_CMDLINE and PROCPS_PIDS_CMDLINE_V. . a user simply duplicated some vectorized enum items. The root of that NULL problem is the fact those single string vectors shared the same proc_t field with their true vectorized version. So while multiple occurrences for most strings could be satisfied with strdup versus the normal ownership usurpation, those true vectorized fields could not be quite so easily copied/duplicated. Thus newlib chose to return a NULL result.strv pointer under either of the above scenarios (which perhaps was just a user boo-boo in the first place). In any event, the NULL was a potential for true string vectors only. Now, since newlib is the sole caller into the readproc module, separate fields have been created for what are just normal strings (never vectorized) and those which remain the true vectorized versions. And, former flags which only worked if combined, now act as stand alone. Thus, both PROCPS_PIDS_CMDLINE & PROCPS_PIDS_CMDLINE_V can be used simultaneously (as they should have been). Also with this patch, items which a user duplicates in the stack (beyond the first such item) will return the the string "[ duplicate ENUM_ID ]". This practice will apply to both single strings and true vectorized ones. In addition to informing users of their error, it will also mean potential NULLs need now never be a concern. Reference(s); http://www.freelists.org/post/procps/systemd-binary-vs-library commit 0580a7b4c67d0297629d37281b4f690894429626 Signed-off-by: Jim Warner <james.warner@comcast.net>
2016-05-19 10:30:00 +05:30
p->cmdline = strdup(dst_buffer[0] ? dst_buffer : "?");
if (!p->cmdline)
return 1;
return 0;
enhanced libproc cgroup/cmdline support, exploited by top Library Changes . added PROC_EDITCMDLCVT flag . added an internal (static) fill_cmdline_cvt function: - reads and "escapes" /proc/#/cmdline - returns result as a single string in a single vector - callers are guaranteed a cmdline (no more NULL) . added vectorize_this_str function, exploited by fill_cgroup_cvt, fill_cmdline_cvt . generalized read_cmdline function as read_unvectored, now exploited by fill_cgroup_cvt, fill_cmdline_cvt, read_cmdline ( cgroup and cmdline no longer need be converted to string ) ( vectors before being transformed to final representation ) . fixed bug regarding skipped group numbers (when enabled) . escape_str made responsible for all single byte translation with distinction between control chars + other unprintable . added escaped_copy function for already escaped strings . reorganized parts of proc_t to restore formatting standards ( displacement changes shouldn't matter with new version # ) . former ZAP_SUSEONLY #define now OOMEM_ENABLE . added to library.map: escaped_copy; read_cmdline Top Program Changes . exploited the new PROC_EDITCMDLCVT provision . eliminated now obsolete #include "proc/escape.h" . changed the P_WCH display format if no kernel symbol table . fixed very old bug in lflgs for out-of-view sort fields . former ZAP_SUSEONLY #define now OOMEM_ENABLE Ps Program Changes . exploited the new PROC_EDITCMDLCVT provision . exploited the new escaped_copy function . consolidated pr_args and pr_comm into pr_argcom Signed-off-by: Jan Görig <jgorig@redhat.com>
2011-05-18 14:03:44 +05:30
#undef uFLG
}
// This routine reads an 'environ' for the designated proc_t and
// guarantees the caller a valid proc_t.environ pointer.
static int fill_environ_cvt (const char* directory, proc_t *restrict p) {
dst_buffer[0] = '\0';
if (read_unvectored(src_buffer, MAX_BUFSZ, directory, "environ", ' '))
library: refactor 'escape' logic for newlib essentials This new library provides callers with pure strings or string vectors. It is up to those callers to deal with potential utf8 multibyte characters and any difference between strlen and the corresponding printable widths. So, it makes no sense for the library to go to all the trouble of invoking those rather expensive 'mbrtowc' & 'wcwidth' functions to ultimately yield total 'cells'. Thus, this patch will eliminate all the code and parms that are involved with such possible multibyte issues. [ Along the way we'll lose the ability to substitute ] [ '?' for an invalid/unprintable multibyte sequence. ] [ We will, however, replace ctrl chars with the '?'. ] [ This presents no problem for that ps program since ] [ it now duplicates all of the original escape code. ] [ And, we'll no longer be executing that code twice! ] [ As for the top program, it takes the position that ] [ it is wrong to alter kernel supplied data. So with ] [ potential invalid/unprintable stuff, he'll rely on ] [ terminal emulators to properly handle such issues! ] [ Besides, even using a proper multibyte string, not ] [ all terminals generate the proper printable width. ] [ This is especially true when it comes to an emoji. ] [ And should callers chose not to be portable to all ] [ locales by calling setlocale(LC_ALL, ""), they can ] [ expect to see lots of "?", regardless of what this ] [ library fixes in a faulty multibyte string anyway. ] Signed-off-by: Jim Warner <james.warner@comcast.net>
2020-12-24 11:30:00 +05:30
escape_str(dst_buffer, src_buffer, MAX_BUFSZ);
library: eliminated a final potential NULL, <PIDS> api In that reference below a specific systemd problem was fixed in the commit shown. However lurking deep within the <pids> interface was yet one final case where NULL could be returned, involving 'strv' and the following: . a user requested both a single string vector (always returned as a normal string) & the vectorized version, as with PROCPS_PIDS_CMDLINE and PROCPS_PIDS_CMDLINE_V. . a user simply duplicated some vectorized enum items. The root of that NULL problem is the fact those single string vectors shared the same proc_t field with their true vectorized version. So while multiple occurrences for most strings could be satisfied with strdup versus the normal ownership usurpation, those true vectorized fields could not be quite so easily copied/duplicated. Thus newlib chose to return a NULL result.strv pointer under either of the above scenarios (which perhaps was just a user boo-boo in the first place). In any event, the NULL was a potential for true string vectors only. Now, since newlib is the sole caller into the readproc module, separate fields have been created for what are just normal strings (never vectorized) and those which remain the true vectorized versions. And, former flags which only worked if combined, now act as stand alone. Thus, both PROCPS_PIDS_CMDLINE & PROCPS_PIDS_CMDLINE_V can be used simultaneously (as they should have been). Also with this patch, items which a user duplicates in the stack (beyond the first such item) will return the the string "[ duplicate ENUM_ID ]". This practice will apply to both single strings and true vectorized ones. In addition to informing users of their error, it will also mean potential NULLs need now never be a concern. Reference(s); http://www.freelists.org/post/procps/systemd-binary-vs-library commit 0580a7b4c67d0297629d37281b4f690894429626 Signed-off-by: Jim Warner <james.warner@comcast.net>
2016-05-19 10:30:00 +05:30
p->environ = strdup(dst_buffer[0] ? dst_buffer : "-");
if (!p->environ)
return 1;
return 0;
}
// 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 char *lxc_containers (const char *path) {
static struct utlbuf_s ub = { NULL, 0 }; // util buffer for whole cgroup
static char lxc_none[] = "-";
static char lxc_oops[] = "?"; // used when memory alloc fails
/*
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) {
/* ouch, the next defaults could be changed at lxc ./configure time
( and a changed 'lxc.cgroup.pattern' is only available to root ) */
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
const char *delim;
char *p1;
if ((p1 = strstr(ub.buf, (delim = lxc_delm1)))
|| ((p1 = strstr(ub.buf, (delim = lxc_delm2)))
|| ((p1 = strstr(ub.buf, (delim = lxc_delm3)))))) {
static struct lxc_ele {
struct lxc_ele *next;
char *name;
} *anchor = NULL;
struct lxc_ele *ele = anchor;
int delim_len = strlen(delim);
char *p2;
if ((p2 = strchr(p1, '\n'))) // isolate a controller's line
*p2 = '\0';
do { // deal with nested containers
p2 = p1 + delim_len;
p1 = strstr(p2, delim);
} 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;
}
if (!(ele = (struct lxc_ele *)malloc(sizeof(struct lxc_ele))))
return lxc_oops;
if (!(ele->name = strdup(p2))) {
free(ele);
return lxc_oops;
}
ele->next = anchor; // push the new container name
anchor = ele;
return ele->name; // return a new container name
}
}
return lxc_none;
}
// Provide the user id at login (or -1 if not available)
static int login_uid (const char *path) {
char buf[PROCPATHLEN];
int fd, id, in;
id = -1;
snprintf(buf, sizeof(buf), "%s/loginuid", path);
if ((fd = open(buf, O_RDONLY, 0)) != -1) {
in = read(fd, buf, sizeof(buf) - 1);
close(fd);
if (in > 0) {
buf[in] = '\0';
id = atoi(buf);
}
}
return id;
}
static char *readlink_exe (const char *path){
char buf[PROCPATHLEN];
int in;
snprintf(buf, sizeof(buf), "%s/exe", path);
library: refactor 'escape' logic for newlib (2nd time) Much of what was represented in the commit message for the reference shown below was revisited in this patch. It also means that the assertion in the last paragraph of that message will only now be true with LANG unset. [ and forget all the bullshit about not altering any ] [ kernel supplied data. sometimes we must to avoid a ] [ corrupt display due to a string we can not decode. ] And while this commit still avoids the overhead of the 'mbrtowc', 'wcwidth' 'isprint, & 'iswprint' functions, we achieve all the benefits with simple table lookups. Plus such benefits are extended to additional strings. For example, both PIDS_EXE and PIDS_CMD fields are now also subject to being 'escaped'. If a program name did contain multibyte characters, potential truncation may corrupt it when it's squeezed into a 15/63 byte array. Now, all future users of this new library only need to deal with the disparities between string and printable lengths. Such strings themselves are always printable. [ the ps program now contains some unnecessary costs ] [ with the duplicated former 'escape' functions. But ] [ we retain that copied escape.c code for posterity. ] [ besides, in a one-shot guy it's of little concern. ] Note: Proper display of some multibyte strings was not possible at the linux console. It would seem a concept of zero length chars (like a 'combining acute accent') is not recognized. Thus the display becomes corrupted. But if utf8 decoding is disabled (via LANG=), then all callers will now see '?', restoring correct alignment. Reference(s): . Dec 2020, newlib 'escape' logic refactored commit a221b9084ae979e6fd073a83e7fbc46c44551f35 Signed-off-by: Jim Warner <james.warner@comcast.net>
2020-12-28 11:30:00 +05:30
in = (int)readlink(buf, src_buffer, MAX_BUFSZ-1);
if (in > 0) {
library: refactor 'escape' logic for newlib (2nd time) Much of what was represented in the commit message for the reference shown below was revisited in this patch. It also means that the assertion in the last paragraph of that message will only now be true with LANG unset. [ and forget all the bullshit about not altering any ] [ kernel supplied data. sometimes we must to avoid a ] [ corrupt display due to a string we can not decode. ] And while this commit still avoids the overhead of the 'mbrtowc', 'wcwidth' 'isprint, & 'iswprint' functions, we achieve all the benefits with simple table lookups. Plus such benefits are extended to additional strings. For example, both PIDS_EXE and PIDS_CMD fields are now also subject to being 'escaped'. If a program name did contain multibyte characters, potential truncation may corrupt it when it's squeezed into a 15/63 byte array. Now, all future users of this new library only need to deal with the disparities between string and printable lengths. Such strings themselves are always printable. [ the ps program now contains some unnecessary costs ] [ with the duplicated former 'escape' functions. But ] [ we retain that copied escape.c code for posterity. ] [ besides, in a one-shot guy it's of little concern. ] Note: Proper display of some multibyte strings was not possible at the linux console. It would seem a concept of zero length chars (like a 'combining acute accent') is not recognized. Thus the display becomes corrupted. But if utf8 decoding is disabled (via LANG=), then all callers will now see '?', restoring correct alignment. Reference(s): . Dec 2020, newlib 'escape' logic refactored commit a221b9084ae979e6fd073a83e7fbc46c44551f35 Signed-off-by: Jim Warner <james.warner@comcast.net>
2020-12-28 11:30:00 +05:30
src_buffer[in] = '\0';
escape_str(dst_buffer, src_buffer, MAX_BUFSZ);
return strdup(dst_buffer);
}
return strdup("-");
}
///////////////////////////////////////////////////////////////////////
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; \
} )
2002-02-02 04:17:29 +05:30
/* 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; \
} )
2002-02-02 04:17:29 +05:30
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
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;
int rc = 0;
2002-02-02 04:17:29 +05:30
if (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))
goto next_proc; /* not one of the requested uids */
2002-02-02 04:17:29 +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
if (flags & PROC_FILLSTAT) { // read /proc/#/stat
if (file2str(path, "stat", &ub) == -1)
goto next_proc;
rc += stat2proc(ub.buf, p);
2002-12-09 00:21:56 +05:30
}
2002-02-02 04:17:29 +05:30
if (flags & PROC_FILLMEM) { // read /proc/#/statm
if (file2str(path, "statm", &ub) != -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
statm2proc(ub.buf, p);
}
2002-02-02 04:17:29 +05:30
if (flags & PROC_FILLSTATUS) { // read /proc/#/status
if (file2str(path, "status", &ub) != -1){
rc += status2proc(ub.buf, p, 1);
if (flags & (PROC_FILL_SUPGRP & ~PROC_FILLSTATUS))
rc += supgrps_from_supgids(p);
if (flags & (PROC_FILL_OUSERS & ~PROC_FILLSTATUS)) {
p->ruser = pwcache_get_user(p->ruid);
p->suser = pwcache_get_user(p->suid);
p->fuser = pwcache_get_user(p->fuid);
}
if (flags & (PROC_FILL_OGROUPS & ~PROC_FILLSTATUS)) {
p->rgroup = pwcache_get_group(p->rgid);
p->sgroup = pwcache_get_group(p->sgid);
p->fgroup = pwcache_get_group(p->fgid);
}
}
2002-02-02 04:17:29 +05:30
}
// if multithreaded, some values are crap
if(p->nlwp > 1){
p->wchan = ~0ul;
}
/* some number->text resolving which is time consuming */
/* ( names are cached, so memcpy to arrays was silly ) */
if (flags & PROC_FILLUSR)
p->euser = pwcache_get_user(p->euid);
if (flags & PROC_FILLGRP)
p->egroup = pwcache_get_group(p->egid);
2002-02-02 04:17:29 +05:30
library: eliminated a final potential NULL, <PIDS> api In that reference below a specific systemd problem was fixed in the commit shown. However lurking deep within the <pids> interface was yet one final case where NULL could be returned, involving 'strv' and the following: . a user requested both a single string vector (always returned as a normal string) & the vectorized version, as with PROCPS_PIDS_CMDLINE and PROCPS_PIDS_CMDLINE_V. . a user simply duplicated some vectorized enum items. The root of that NULL problem is the fact those single string vectors shared the same proc_t field with their true vectorized version. So while multiple occurrences for most strings could be satisfied with strdup versus the normal ownership usurpation, those true vectorized fields could not be quite so easily copied/duplicated. Thus newlib chose to return a NULL result.strv pointer under either of the above scenarios (which perhaps was just a user boo-boo in the first place). In any event, the NULL was a potential for true string vectors only. Now, since newlib is the sole caller into the readproc module, separate fields have been created for what are just normal strings (never vectorized) and those which remain the true vectorized versions. And, former flags which only worked if combined, now act as stand alone. Thus, both PROCPS_PIDS_CMDLINE & PROCPS_PIDS_CMDLINE_V can be used simultaneously (as they should have been). Also with this patch, items which a user duplicates in the stack (beyond the first such item) will return the the string "[ duplicate ENUM_ID ]". This practice will apply to both single strings and true vectorized ones. In addition to informing users of their error, it will also mean potential NULLs need now never be a concern. Reference(s); http://www.freelists.org/post/procps/systemd-binary-vs-library commit 0580a7b4c67d0297629d37281b4f690894429626 Signed-off-by: Jim Warner <james.warner@comcast.net>
2016-05-19 10:30:00 +05:30
if (flags & PROC_FILLENV) // read /proc/#/environ
if (!(p->environ_v = file2strvec(path, "environ")))
rc += vectorize_dash_rc(&p->environ_v);
library: eliminated a final potential NULL, <PIDS> api In that reference below a specific systemd problem was fixed in the commit shown. However lurking deep within the <pids> interface was yet one final case where NULL could be returned, involving 'strv' and the following: . a user requested both a single string vector (always returned as a normal string) & the vectorized version, as with PROCPS_PIDS_CMDLINE and PROCPS_PIDS_CMDLINE_V. . a user simply duplicated some vectorized enum items. The root of that NULL problem is the fact those single string vectors shared the same proc_t field with their true vectorized version. So while multiple occurrences for most strings could be satisfied with strdup versus the normal ownership usurpation, those true vectorized fields could not be quite so easily copied/duplicated. Thus newlib chose to return a NULL result.strv pointer under either of the above scenarios (which perhaps was just a user boo-boo in the first place). In any event, the NULL was a potential for true string vectors only. Now, since newlib is the sole caller into the readproc module, separate fields have been created for what are just normal strings (never vectorized) and those which remain the true vectorized versions. And, former flags which only worked if combined, now act as stand alone. Thus, both PROCPS_PIDS_CMDLINE & PROCPS_PIDS_CMDLINE_V can be used simultaneously (as they should have been). Also with this patch, items which a user duplicates in the stack (beyond the first such item) will return the the string "[ duplicate ENUM_ID ]". This practice will apply to both single strings and true vectorized ones. In addition to informing users of their error, it will also mean potential NULLs need now never be a concern. Reference(s); http://www.freelists.org/post/procps/systemd-binary-vs-library commit 0580a7b4c67d0297629d37281b4f690894429626 Signed-off-by: Jim Warner <james.warner@comcast.net>
2016-05-19 10:30:00 +05:30
if (flags & PROC_EDITENVRCVT)
rc += fill_environ_cvt(path, p);
enhanced libproc cgroup/cmdline support, exploited by top Library Changes . added PROC_EDITCMDLCVT flag . added an internal (static) fill_cmdline_cvt function: - reads and "escapes" /proc/#/cmdline - returns result as a single string in a single vector - callers are guaranteed a cmdline (no more NULL) . added vectorize_this_str function, exploited by fill_cgroup_cvt, fill_cmdline_cvt . generalized read_cmdline function as read_unvectored, now exploited by fill_cgroup_cvt, fill_cmdline_cvt, read_cmdline ( cgroup and cmdline no longer need be converted to string ) ( vectors before being transformed to final representation ) . fixed bug regarding skipped group numbers (when enabled) . escape_str made responsible for all single byte translation with distinction between control chars + other unprintable . added escaped_copy function for already escaped strings . reorganized parts of proc_t to restore formatting standards ( displacement changes shouldn't matter with new version # ) . former ZAP_SUSEONLY #define now OOMEM_ENABLE . added to library.map: escaped_copy; read_cmdline Top Program Changes . exploited the new PROC_EDITCMDLCVT provision . eliminated now obsolete #include "proc/escape.h" . changed the P_WCH display format if no kernel symbol table . fixed very old bug in lflgs for out-of-view sort fields . former ZAP_SUSEONLY #define now OOMEM_ENABLE Ps Program Changes . exploited the new PROC_EDITCMDLCVT provision . exploited the new escaped_copy function . consolidated pr_args and pr_comm into pr_argcom Signed-off-by: Jan Görig <jgorig@redhat.com>
2011-05-18 14:03:44 +05:30
library: eliminated a final potential NULL, <PIDS> api In that reference below a specific systemd problem was fixed in the commit shown. However lurking deep within the <pids> interface was yet one final case where NULL could be returned, involving 'strv' and the following: . a user requested both a single string vector (always returned as a normal string) & the vectorized version, as with PROCPS_PIDS_CMDLINE and PROCPS_PIDS_CMDLINE_V. . a user simply duplicated some vectorized enum items. The root of that NULL problem is the fact those single string vectors shared the same proc_t field with their true vectorized version. So while multiple occurrences for most strings could be satisfied with strdup versus the normal ownership usurpation, those true vectorized fields could not be quite so easily copied/duplicated. Thus newlib chose to return a NULL result.strv pointer under either of the above scenarios (which perhaps was just a user boo-boo in the first place). In any event, the NULL was a potential for true string vectors only. Now, since newlib is the sole caller into the readproc module, separate fields have been created for what are just normal strings (never vectorized) and those which remain the true vectorized versions. And, former flags which only worked if combined, now act as stand alone. Thus, both PROCPS_PIDS_CMDLINE & PROCPS_PIDS_CMDLINE_V can be used simultaneously (as they should have been). Also with this patch, items which a user duplicates in the stack (beyond the first such item) will return the the string "[ duplicate ENUM_ID ]". This practice will apply to both single strings and true vectorized ones. In addition to informing users of their error, it will also mean potential NULLs need now never be a concern. Reference(s); http://www.freelists.org/post/procps/systemd-binary-vs-library commit 0580a7b4c67d0297629d37281b4f690894429626 Signed-off-by: Jim Warner <james.warner@comcast.net>
2016-05-19 10:30:00 +05:30
if (flags & PROC_FILLARG) // read /proc/#/cmdline
if (!(p->cmdline_v = file2strvec(path, "cmdline")))
rc += vectorize_dash_rc(&p->cmdline_v);
library: eliminated a final potential NULL, <PIDS> api In that reference below a specific systemd problem was fixed in the commit shown. However lurking deep within the <pids> interface was yet one final case where NULL could be returned, involving 'strv' and the following: . a user requested both a single string vector (always returned as a normal string) & the vectorized version, as with PROCPS_PIDS_CMDLINE and PROCPS_PIDS_CMDLINE_V. . a user simply duplicated some vectorized enum items. The root of that NULL problem is the fact those single string vectors shared the same proc_t field with their true vectorized version. So while multiple occurrences for most strings could be satisfied with strdup versus the normal ownership usurpation, those true vectorized fields could not be quite so easily copied/duplicated. Thus newlib chose to return a NULL result.strv pointer under either of the above scenarios (which perhaps was just a user boo-boo in the first place). In any event, the NULL was a potential for true string vectors only. Now, since newlib is the sole caller into the readproc module, separate fields have been created for what are just normal strings (never vectorized) and those which remain the true vectorized versions. And, former flags which only worked if combined, now act as stand alone. Thus, both PROCPS_PIDS_CMDLINE & PROCPS_PIDS_CMDLINE_V can be used simultaneously (as they should have been). Also with this patch, items which a user duplicates in the stack (beyond the first such item) will return the the string "[ duplicate ENUM_ID ]". This practice will apply to both single strings and true vectorized ones. In addition to informing users of their error, it will also mean potential NULLs need now never be a concern. Reference(s); http://www.freelists.org/post/procps/systemd-binary-vs-library commit 0580a7b4c67d0297629d37281b4f690894429626 Signed-off-by: Jim Warner <james.warner@comcast.net>
2016-05-19 10:30:00 +05:30
if (flags & PROC_EDITCMDLCVT)
rc += fill_cmdline_cvt(path, p);
library: eliminated a final potential NULL, <PIDS> api In that reference below a specific systemd problem was fixed in the commit shown. However lurking deep within the <pids> interface was yet one final case where NULL could be returned, involving 'strv' and the following: . a user requested both a single string vector (always returned as a normal string) & the vectorized version, as with PROCPS_PIDS_CMDLINE and PROCPS_PIDS_CMDLINE_V. . a user simply duplicated some vectorized enum items. The root of that NULL problem is the fact those single string vectors shared the same proc_t field with their true vectorized version. So while multiple occurrences for most strings could be satisfied with strdup versus the normal ownership usurpation, those true vectorized fields could not be quite so easily copied/duplicated. Thus newlib chose to return a NULL result.strv pointer under either of the above scenarios (which perhaps was just a user boo-boo in the first place). In any event, the NULL was a potential for true string vectors only. Now, since newlib is the sole caller into the readproc module, separate fields have been created for what are just normal strings (never vectorized) and those which remain the true vectorized versions. And, former flags which only worked if combined, now act as stand alone. Thus, both PROCPS_PIDS_CMDLINE & PROCPS_PIDS_CMDLINE_V can be used simultaneously (as they should have been). Also with this patch, items which a user duplicates in the stack (beyond the first such item) will return the the string "[ duplicate ENUM_ID ]". This practice will apply to both single strings and true vectorized ones. In addition to informing users of their error, it will also mean potential NULLs need now never be a concern. Reference(s); http://www.freelists.org/post/procps/systemd-binary-vs-library commit 0580a7b4c67d0297629d37281b4f690894429626 Signed-off-by: Jim Warner <james.warner@comcast.net>
2016-05-19 10:30:00 +05:30
if ((flags & PROC_FILLCGROUP)) // read /proc/#/cgroup
if (!(p->cgroup_v = file2strvec(path, "cgroup")))
rc += vectorize_dash_rc(&p->cgroup_v);
library: eliminated a final potential NULL, <PIDS> api In that reference below a specific systemd problem was fixed in the commit shown. However lurking deep within the <pids> interface was yet one final case where NULL could be returned, involving 'strv' and the following: . a user requested both a single string vector (always returned as a normal string) & the vectorized version, as with PROCPS_PIDS_CMDLINE and PROCPS_PIDS_CMDLINE_V. . a user simply duplicated some vectorized enum items. The root of that NULL problem is the fact those single string vectors shared the same proc_t field with their true vectorized version. So while multiple occurrences for most strings could be satisfied with strdup versus the normal ownership usurpation, those true vectorized fields could not be quite so easily copied/duplicated. Thus newlib chose to return a NULL result.strv pointer under either of the above scenarios (which perhaps was just a user boo-boo in the first place). In any event, the NULL was a potential for true string vectors only. Now, since newlib is the sole caller into the readproc module, separate fields have been created for what are just normal strings (never vectorized) and those which remain the true vectorized versions. And, former flags which only worked if combined, now act as stand alone. Thus, both PROCPS_PIDS_CMDLINE & PROCPS_PIDS_CMDLINE_V can be used simultaneously (as they should have been). Also with this patch, items which a user duplicates in the stack (beyond the first such item) will return the the string "[ duplicate ENUM_ID ]". This practice will apply to both single strings and true vectorized ones. In addition to informing users of their error, it will also mean potential NULLs need now never be a concern. Reference(s); http://www.freelists.org/post/procps/systemd-binary-vs-library commit 0580a7b4c67d0297629d37281b4f690894429626 Signed-off-by: Jim Warner <james.warner@comcast.net>
2016-05-19 10:30:00 +05:30
if (flags & PROC_EDITCGRPCVT)
rc += fill_cgroup_cvt(path, p);
enhanced libproc cgroup/cmdline support, exploited by top Library Changes . added PROC_EDITCMDLCVT flag . added an internal (static) fill_cmdline_cvt function: - reads and "escapes" /proc/#/cmdline - returns result as a single string in a single vector - callers are guaranteed a cmdline (no more NULL) . added vectorize_this_str function, exploited by fill_cgroup_cvt, fill_cmdline_cvt . generalized read_cmdline function as read_unvectored, now exploited by fill_cgroup_cvt, fill_cmdline_cvt, read_cmdline ( cgroup and cmdline no longer need be converted to string ) ( vectors before being transformed to final representation ) . fixed bug regarding skipped group numbers (when enabled) . escape_str made responsible for all single byte translation with distinction between control chars + other unprintable . added escaped_copy function for already escaped strings . reorganized parts of proc_t to restore formatting standards ( displacement changes shouldn't matter with new version # ) . former ZAP_SUSEONLY #define now OOMEM_ENABLE . added to library.map: escaped_copy; read_cmdline Top Program Changes . exploited the new PROC_EDITCMDLCVT provision . eliminated now obsolete #include "proc/escape.h" . changed the P_WCH display format if no kernel symbol table . fixed very old bug in lflgs for out-of-view sort fields . former ZAP_SUSEONLY #define now OOMEM_ENABLE Ps Program Changes . exploited the new PROC_EDITCMDLCVT provision . exploited the new escaped_copy function . consolidated pr_args and pr_comm into pr_argcom Signed-off-by: Jan Görig <jgorig@redhat.com>
2011-05-18 14:03:44 +05:30
if (flags & PROC_FILLOOM) {
if (file2str(path, "oom_score", &ub) != -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
oomscore2proc(ub.buf, p);
if (file2str(path, "oom_score_adj", &ub) != -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
oomadj2proc(ub.buf, p);
enhanced libproc cgroup/cmdline support, exploited by top Library Changes . added PROC_EDITCMDLCVT flag . added an internal (static) fill_cmdline_cvt function: - reads and "escapes" /proc/#/cmdline - returns result as a single string in a single vector - callers are guaranteed a cmdline (no more NULL) . added vectorize_this_str function, exploited by fill_cgroup_cvt, fill_cmdline_cvt . generalized read_cmdline function as read_unvectored, now exploited by fill_cgroup_cvt, fill_cmdline_cvt, read_cmdline ( cgroup and cmdline no longer need be converted to string ) ( vectors before being transformed to final representation ) . fixed bug regarding skipped group numbers (when enabled) . escape_str made responsible for all single byte translation with distinction between control chars + other unprintable . added escaped_copy function for already escaped strings . reorganized parts of proc_t to restore formatting standards ( displacement changes shouldn't matter with new version # ) . former ZAP_SUSEONLY #define now OOMEM_ENABLE . added to library.map: escaped_copy; read_cmdline Top Program Changes . exploited the new PROC_EDITCMDLCVT provision . eliminated now obsolete #include "proc/escape.h" . changed the P_WCH display format if no kernel symbol table . fixed very old bug in lflgs for out-of-view sort fields . former ZAP_SUSEONLY #define now OOMEM_ENABLE Ps Program Changes . exploited the new PROC_EDITCMDLCVT provision . exploited the new escaped_copy function . consolidated pr_args and pr_comm into pr_argcom Signed-off-by: Jan Görig <jgorig@redhat.com>
2011-05-18 14:03:44 +05:30
}
if (flags & PROC_FILLNS) // read /proc/#/ns/*
procps_ns_read_pid(p->tid, &(p->ns));
if (flags & PROC_FILLSYSTEMD) // get sd-login.h stuff
rc += sd2proc(p);
if (flags & PROC_FILL_LXC) // value the lxc name
p->lxcname = lxc_containers(path);
if (flags & PROC_FILL_LUID) // value the login user id
p->luid = login_uid(path);
if (flags & PROC_FILL_EXE) {
if (!(p->exe = readlink_exe(path)))
rc += 1;
}
if (rc == 0) return p;
errno = ENOMEM;
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.
// t is the POSIX thread (task group member, generally not the leader)
2003-09-20 13:59:55 +05:30
// path is a path to the task, with some room to spare.
static proc_t* simple_readtask(PROCTAB *restrict const PT, 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
static struct stat sb; // stat() buffer
2003-09-20 13:59:55 +05:30
unsigned flags = PT->flags;
int rc = 0;
2003-09-20 13:59:55 +05:30
if (stat(path, &sb) == -1) /* no such dirent (anymore) */
goto next_task;
2003-09-20 13:59:55 +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
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
if (flags & PROC_FILLSTAT) { // read /proc/#/task/#/stat
if (file2str(path, "stat", &ub) == -1)
goto next_task;
rc += stat2proc(ub.buf, t);
2003-09-20 13:59:55 +05:30
}
if (flags & PROC_FILLMEM) { // read /proc/#/task/#statm
if (file2str(path, "statm", &ub) != -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
statm2proc(ub.buf, t);
}
if (flags & PROC_FILLSTATUS) { // read /proc/#/task/#/status
if (file2str(path, "status", &ub) != -1) {
rc += status2proc(ub.buf, t, 0);
if (flags & (PROC_FILL_SUPGRP & ~PROC_FILLSTATUS))
rc += supgrps_from_supgids(t);
if (flags & (PROC_FILL_OUSERS & ~PROC_FILLSTATUS)) {
t->ruser = pwcache_get_user(t->ruid);
t->suser = pwcache_get_user(t->suid);
t->fuser = pwcache_get_user(t->fuid);
}
if (flags & (PROC_FILL_OGROUPS & ~PROC_FILLSTATUS)) {
t->rgroup = pwcache_get_group(t->rgid);
t->sgroup = pwcache_get_group(t->sgid);
t->fgroup = pwcache_get_group(t->fgid);
}
}
2003-09-20 13:59:55 +05:30
}
/* some number->text resolving which is time consuming */
/* ( names are cached, so memcpy to arrays was silly ) */
if (flags & PROC_FILLUSR)
t->euser = pwcache_get_user(t->euid);
if (flags & PROC_FILLGRP)
t->egroup = pwcache_get_group(t->egid);
2003-09-20 13:59:55 +05:30
#ifdef FALSE_THREADS
if (!IS_THREAD(t)) {
#endif
if (flags & PROC_FILLARG) // read /proc/#/task/#/cmdline
if (!(t->cmdline_v = file2strvec(path, "cmdline")))
rc += vectorize_dash_rc(&t->cmdline_v);
if (flags & PROC_EDITCMDLCVT)
rc += fill_cmdline_cvt(path, t);
library: eliminated a final potential NULL, <PIDS> api In that reference below a specific systemd problem was fixed in the commit shown. However lurking deep within the <pids> interface was yet one final case where NULL could be returned, involving 'strv' and the following: . a user requested both a single string vector (always returned as a normal string) & the vectorized version, as with PROCPS_PIDS_CMDLINE and PROCPS_PIDS_CMDLINE_V. . a user simply duplicated some vectorized enum items. The root of that NULL problem is the fact those single string vectors shared the same proc_t field with their true vectorized version. So while multiple occurrences for most strings could be satisfied with strdup versus the normal ownership usurpation, those true vectorized fields could not be quite so easily copied/duplicated. Thus newlib chose to return a NULL result.strv pointer under either of the above scenarios (which perhaps was just a user boo-boo in the first place). In any event, the NULL was a potential for true string vectors only. Now, since newlib is the sole caller into the readproc module, separate fields have been created for what are just normal strings (never vectorized) and those which remain the true vectorized versions. And, former flags which only worked if combined, now act as stand alone. Thus, both PROCPS_PIDS_CMDLINE & PROCPS_PIDS_CMDLINE_V can be used simultaneously (as they should have been). Also with this patch, items which a user duplicates in the stack (beyond the first such item) will return the the string "[ duplicate ENUM_ID ]". This practice will apply to both single strings and true vectorized ones. In addition to informing users of their error, it will also mean potential NULLs need now never be a concern. Reference(s); http://www.freelists.org/post/procps/systemd-binary-vs-library commit 0580a7b4c67d0297629d37281b4f690894429626 Signed-off-by: Jim Warner <james.warner@comcast.net>
2016-05-19 10:30:00 +05:30
if (flags & PROC_FILLENV) // read /proc/#/task/#/environ
if (!(t->environ_v = file2strvec(path, "environ")))
rc += vectorize_dash_rc(&t->environ_v);
if (flags & PROC_EDITENVRCVT)
rc += fill_environ_cvt(path, t);
if ((flags & PROC_FILLCGROUP)) // read /proc/#/task/#/cgroup
if (!(t->cgroup_v = file2strvec(path, "cgroup")))
rc += vectorize_dash_rc(&t->cgroup_v);
if (flags & PROC_EDITCGRPCVT)
rc += fill_cgroup_cvt(path, t);
if (flags & PROC_FILLSYSTEMD) // get sd-login.h stuff
rc += sd2proc(t);
if (flags & PROC_FILL_EXE) {
if (!(t->exe = readlink_exe(path)))
rc += 1;
}
#ifdef FALSE_THREADS
}
2003-09-20 13:59:55 +05:30
#endif
if (flags & PROC_FILLOOM) {
if (file2str(path, "oom_score", &ub) != -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
oomscore2proc(ub.buf, t);
if (file2str(path, "oom_score_adj", &ub) != -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
oomadj2proc(ub.buf, t);
}
if (flags & PROC_FILLNS) // read /proc/#/task/#/ns/*
procps_ns_read_pid(t->tid, &(t->ns));
2003-09-29 09:39:52 +05:30
if (flags & PROC_FILL_LXC)
t->lxcname = lxc_containers(path);
if (flags & PROC_FILL_LUID)
t->luid = login_uid(path);
if (rc == 0) return t;
errno = ENOMEM;
2003-09-20 13:59:55 +05:30
next_task:
return NULL;
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) {
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);
if(!ent || !ent->d_name[0]) return 0;
if(*ent->d_name > '0' && *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;
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) {
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);
if(!ent || !ent->d_name[0]) return 0;
if(*ent->d_name > '0' && *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;
//t->ppid = p->ppid; // cover for kernel behavior? we want both actually...?
snprintf(path, PROCPATHLEN, "/proc/%d/task/%.10s", p->tgid, ent->d_name);
2003-09-20 13:59:55 +05:30
return 1;
}
2003-09-18 03:28:32 +05:30
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)++;
if(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
}
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;
free_acquired(p);
2003-09-18 03:28:32 +05:30
for(;;){
if (errno == ENOMEM) goto out;
2003-09-20 13:59:55 +05:30
// fills in the path, plus p->tid and p->tgid
if (!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:
2003-09-20 13:59:55 +05:30
return NULL;
}
2002-02-02 04:17:29 +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.
proc_t* readeither (PROCTAB *restrict const PT, proc_t *restrict x) {
static proc_t skel_p; // skeleton proc_t, only uses tid + tgid
static proc_t *new_p; // for process/task transitions
0084-proc/readproc.c: Work around a design flaw in readeither(). readeither() caches (in new_p) a pointer to the proc_t of a task-group leader, but readeither()'s callers can do pretty much anything with the proc_t structure passed to and/or returned by this function. For example, they can 1/ free it or 2/ recycle it (by passing it to readeither() as x). 1/ leads to a use-after-free, and 2/ leads to unexpected behavior when taskreader()/simple_readtask() is called with new_p equal to x (this is not a theoretical flaw: 2/ happens in readproctab3() when want_task() returns false and p is a group leader). As a workaround, we keep a copy of new_p's first member (tid) in static storage, and the next times we enter readeither() we check this "canary" against the tid in new_p: if they differ, we reset new_p to NULL, which forces the allocation of a new proc_t (the new "leader", or reference). This always detects 2/ (because free_acquired(x,1) memsets x and hence new_p); always detects 1/ if freed via free_acquired() and/or freeproc() (very likely, otherwise memory may be leaked); probably detects 1/ even if freed directly via free() (because the canary is the first member of proc_t, likely to be overwritten by free()); but can not detect 1/ if free() does not write to new_p's chunk at all. Moreover, accessing new_p->tid to check the canary in case 1/ is itself a use-after-free, so a better long-term solution should be implemented at some point (we wanted to avoid intrusive and backward-incompatible changes in this library function, hence this imperfect workaround). ---------------------------- adapted for newlib branch . adapted via 'patch' (rejected due to 'xcalloc' ref) . with loss of both readproctab functions, most no longer true Signed-off-by: Jim Warner <james.warner@comcast.net>
1970-01-01 05:30:00 +05:30
static int canary;
char path[PROCPATHLEN];
proc_t *ret;
free_acquired(x);
0084-proc/readproc.c: Work around a design flaw in readeither(). readeither() caches (in new_p) a pointer to the proc_t of a task-group leader, but readeither()'s callers can do pretty much anything with the proc_t structure passed to and/or returned by this function. For example, they can 1/ free it or 2/ recycle it (by passing it to readeither() as x). 1/ leads to a use-after-free, and 2/ leads to unexpected behavior when taskreader()/simple_readtask() is called with new_p equal to x (this is not a theoretical flaw: 2/ happens in readproctab3() when want_task() returns false and p is a group leader). As a workaround, we keep a copy of new_p's first member (tid) in static storage, and the next times we enter readeither() we check this "canary" against the tid in new_p: if they differ, we reset new_p to NULL, which forces the allocation of a new proc_t (the new "leader", or reference). This always detects 2/ (because free_acquired(x,1) memsets x and hence new_p); always detects 1/ if freed via free_acquired() and/or freeproc() (very likely, otherwise memory may be leaked); probably detects 1/ even if freed directly via free() (because the canary is the first member of proc_t, likely to be overwritten by free()); but can not detect 1/ if free() does not write to new_p's chunk at all. Moreover, accessing new_p->tid to check the canary in case 1/ is itself a use-after-free, so a better long-term solution should be implemented at some point (we wanted to avoid intrusive and backward-incompatible changes in this library function, hence this imperfect workaround). ---------------------------- adapted for newlib branch . adapted via 'patch' (rejected due to 'xcalloc' ref) . with loss of both readproctab functions, most no longer true Signed-off-by: Jim Warner <james.warner@comcast.net>
1970-01-01 05:30:00 +05:30
if (new_p) {
if (new_p->tid != canary) new_p = NULL;
goto next_task;
}
next_proc:
new_p = NULL;
for (;;) {
if (errno == ENOMEM) goto end_procs;
// 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,x,path)))) { // simple_readtask
2011-10-06 19:04:26 +05:30
goto next_proc;
}
0084-proc/readproc.c: Work around a design flaw in readeither(). readeither() caches (in new_p) a pointer to the proc_t of a task-group leader, but readeither()'s callers can do pretty much anything with the proc_t structure passed to and/or returned by this function. For example, they can 1/ free it or 2/ recycle it (by passing it to readeither() as x). 1/ leads to a use-after-free, and 2/ leads to unexpected behavior when taskreader()/simple_readtask() is called with new_p equal to x (this is not a theoretical flaw: 2/ happens in readproctab3() when want_task() returns false and p is a group leader). As a workaround, we keep a copy of new_p's first member (tid) in static storage, and the next times we enter readeither() we check this "canary" against the tid in new_p: if they differ, we reset new_p to NULL, which forces the allocation of a new proc_t (the new "leader", or reference). This always detects 2/ (because free_acquired(x,1) memsets x and hence new_p); always detects 1/ if freed via free_acquired() and/or freeproc() (very likely, otherwise memory may be leaked); probably detects 1/ even if freed directly via free() (because the canary is the first member of proc_t, likely to be overwritten by free()); but can not detect 1/ if free() does not write to new_p's chunk at all. Moreover, accessing new_p->tid to check the canary in case 1/ is itself a use-after-free, so a better long-term solution should be implemented at some point (we wanted to avoid intrusive and backward-incompatible changes in this library function, hence this imperfect workaround). ---------------------------- adapted for newlib branch . adapted via 'patch' (rejected due to 'xcalloc' ref) . with loss of both readproctab functions, most no longer true Signed-off-by: Jim Warner <james.warner@comcast.net>
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;
end_procs:
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(unsigned flags, ...) {
2003-09-18 03:28:32 +05:30
va_list ap;
2003-09-20 13:59:55 +05:30
struct stat sbuf;
static int did_stat;
PROCTAB* PT = calloc(1, sizeof(PROCTAB));
2003-09-20 13:59:55 +05:30
if (!PT)
return NULL;
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){
PT->procfs = NULL;
PT->finder = listed_nextpid;
2003-09-18 03:28:32 +05:30
}else{
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
va_start(ap, flags);
2003-09-18 03:28:32 +05:30
if (flags & PROC_PID)
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);
}
va_end(ap);
2002-02-02 04:17:29 +05:30
if (!src_buffer
&& !(src_buffer = malloc(MAX_BUFSZ)))
return NULL;
if (!dst_buffer
&& !(dst_buffer = malloc(MAX_BUFSZ)))
return NULL;
2003-09-18 03:28:32 +05:30
return PT;
}
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);
}
}
2002-02-02 04:17:29 +05:30
2003-09-18 03:28:32 +05:30
//////////////////////////////////////////////////////////////////////////////////
int 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 };
int rc = 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){
fprintf(stderr, "Error, do this: mount -t proc proc /proc\n");
2003-05-31 20:48:13 +05:30
_exit(47);
}
rc = stat2proc(ub.buf, p); // parse /proc/self/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
free(ub.buf);
return !rc;
2002-02-02 04:17:29 +05:30
}
#undef IS_THREAD
#undef MAX_BUFSZ