From 8dc378f6a86f0a0e77d1cda11506c7a6b957743c Mon Sep 17 00:00:00 2001 From: Jim Warner Date: Wed, 13 Apr 2016 00:00:00 -0500 Subject: [PATCH] library: exploit linux-4.5 resident memory enhancement Beginning with linux-4.5, the following new fields are being added under that /proc//status pseudo file: . RssAnon - size of resident anonymous memory . RssFile - size of resident file mappings . RssShmem - size of resident shared memory This patch just represents the initial library and top support, sharing a commit message with 2 more patches. p.s. locked resident memory support was also added but isn't directly related to the kernel 4.5 enhancements. Reference(s): commit 1f8e41d01966ef337bc252bffb181d0acc0c8751 Signed-off-by: Jim Warner --- proc/pids.c | 8 +++ proc/pids.h | 4 ++ proc/readproc.c | 133 ++++++++++++++++++++++++++---------------------- proc/readproc.h | 3 ++ 4 files changed, 87 insertions(+), 61 deletions(-) diff --git a/proc/pids.c b/proc/pids.c index aa587987..19a142e7 100644 --- a/proc/pids.c +++ b/proc/pids.c @@ -242,6 +242,10 @@ REG_set(VM_EXE, ul_int, vm_exe) REG_set(VM_LIB, ul_int, vm_lib) REG_set(VM_LOCK, ul_int, vm_lock) REG_set(VM_RSS, ul_int, vm_rss) +REG_set(VM_RSS_ANON, ul_int, vm_rss_anon) +REG_set(VM_RSS_FILE, ul_int, vm_rss_file) +REG_set(VM_RSS_LOCKED, ul_int, vm_lock) +REG_set(VM_RSS_SHARED, ul_int, vm_rss_shared) REG_set(VM_SIZE, ul_int, vm_size) REG_set(VM_STACK, ul_int, vm_stack) REG_set(VM_SWAP, ul_int, vm_swap) @@ -493,6 +497,10 @@ static struct { { RS(VM_LIB), f_status, NULL, QS(ul_int), 0, -1 }, { RS(VM_LOCK), f_status, NULL, QS(ul_int), 0, -1 }, { RS(VM_RSS), f_status, NULL, QS(ul_int), 0, -1 }, + { RS(VM_RSS_ANON), f_status, NULL, QS(ul_int), 0, -1 }, + { RS(VM_RSS_FILE), f_status, NULL, QS(ul_int), 0, -1 }, + { RS(VM_RSS_LOCKED), f_status, NULL, QS(ul_int), 0, -1 }, + { RS(VM_RSS_SHARED), f_status, NULL, QS(ul_int), 0, -1 }, { RS(VM_SIZE), f_status, NULL, QS(ul_int), 0, -1 }, { RS(VM_STACK), f_status, NULL, QS(ul_int), 0, -1 }, { RS(VM_SWAP), f_status, NULL, QS(ul_int), 0, -1 }, diff --git a/proc/pids.h b/proc/pids.h index f32e1031..630e9e86 100644 --- a/proc/pids.h +++ b/proc/pids.h @@ -132,6 +132,10 @@ enum pids_item { PROCPS_PIDS_VM_LIB, // ul_int PROCPS_PIDS_VM_LOCK, // ul_int PROCPS_PIDS_VM_RSS, // ul_int + PROCPS_PIDS_VM_RSS_ANON, // ul_int + PROCPS_PIDS_VM_RSS_FILE, // ul_int + PROCPS_PIDS_VM_RSS_LOCKED, // ul_int + PROCPS_PIDS_VM_RSS_SHARED, // ul_int PROCPS_PIDS_VM_SIZE, // ul_int PROCPS_PIDS_VM_STACK, // ul_int PROCPS_PIDS_VM_SWAP, // ul_int diff --git a/proc/readproc.c b/proc/readproc.c index 0d2eb7cb..380047f2 100644 --- a/proc/readproc.c +++ b/proc/readproc.c @@ -113,7 +113,7 @@ static inline void free_acquired (proc_t *p, int reuse) { /////////////////////////////////////////////////////////////////////////// typedef struct status_table_struct { - unsigned char name[7]; // /proc/*/status field name + unsigned char name[8]; // /proc/*/status field name unsigned char len; // name length #ifdef LABEL_OFFSET long offset; // jump address offset @@ -129,8 +129,11 @@ typedef struct status_table_struct { #endif #define NUL {"", 0, 0}, +#define GPERF_TABLE_SIZE 128 + // Derived from: // gperf -7 --language=ANSI-C --key-positions=1,3,4 -C -n -c +// ( --key-positions verified by omission & reported "Computed positions" ) // // Suggested method: // Grep this file for "case_", then strip those down to the name. @@ -144,8 +147,8 @@ typedef struct status_table_struct { // the F macro and replacing empty strings with the NUL define. // // In the status_table_struct watch out for name size (grrr, expanding) -// and the number of entries (we mask with 63 for now). The table -// must be padded out to 64 entries, maybe 128 in the future. +// and the number of entries. Currently, the table is padded to 128 +// entries and we therefore mask with 127. static void status2proc(char *S, proc_t *restrict P, int is_proc){ long Threads = 0; @@ -155,78 +158,76 @@ static void status2proc(char *S, proc_t *restrict P, int is_proc){ // 128 entries because we trust the kernel to use ASCII names static const unsigned char asso[] = { - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 28, 64, - 64, 64, 64, 64, 64, 64, 8, 25, 23, 25, - 6, 25, 0, 3, 64, 64, 3, 64, 25, 64, - 20, 1, 1, 5, 0, 30, 0, 0, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 3, 64, 0, - 0, 18, 64, 10, 64, 10, 64, 64, 64, 20, - 64, 20, 0, 64, 25, 64, 3, 15, 64, 0, - 30, 64, 64, 64, 64, 64, 64, 64 + 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 }; - static const status_table_struct table[] = { + static const status_table_struct table[GPERF_TABLE_SIZE] = { F(VmHWM) - NUL NUL - F(VmLck) - NUL - F(VmSwap) + F(Threads) + NUL NUL NUL F(VmRSS) - NUL - F(VmStk) - NUL + F(VmSwap) + NUL NUL NUL F(Tgid) - F(State) - NUL - F(VmLib) - NUL + F(VmStk) + NUL NUL NUL F(VmSize) - F(SigQ) - NUL - F(SigIgn) - NUL + F(Gid) + NUL NUL NUL F(VmPTE) - F(FDSize) - NUL - F(SigBlk) - NUL + F(VmPeak) + NUL NUL NUL F(ShdPnd) - F(VmData) - NUL - F(CapInh) - NUL + F(Pid) + NUL NUL NUL F(PPid) - NUL NUL - F(CapBnd) - NUL + F(VmLib) + NUL NUL NUL F(SigPnd) - NUL NUL - F(VmPeak) - NUL + F(VmLck) + NUL NUL NUL F(SigCgt) - NUL NUL - F(Threads) - NUL + F(State) + NUL NUL NUL F(CapPrm) - NUL NUL - F(Pid) - NUL + 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 - F(Gid) - NUL + NUL NUL NUL NUL + F(CapBnd) + NUL NUL NUL NUL F(VmExe) - NUL NUL - F(Uid) - NUL + NUL NUL NUL NUL F(Groups) - NUL NUL - F(Name) + NUL NUL NUL NUL + F(RssAnon) + NUL NUL NUL NUL + F(RssFile) }; #undef F @@ -248,7 +249,7 @@ ENTER(0x220); // examine a field name (hash and compare) base: if(unlikely(!*S)) break; - entry = table[63 & (asso[(int)S[3]] + asso[(int)S[2]] + asso[(int)S[0]])]; + entry = table[(GPERF_TABLE_SIZE -1) & (asso[(int)S[3]] + asso[(int)S[2]] + asso[(int)S[0]])]; colon = strchr(S, ':'); if(unlikely(!colon)) break; if(unlikely(colon[1]!='\t')) break; @@ -364,6 +365,15 @@ ENTER(0x220); case_VmRSS: P->vm_rss = strtol(S,&S,10); continue; + case_RssAnon: // subset of VmRSS, linux-4.5 + P->vm_rss_anon = strtol(S,&S,10); + continue; + case_RssFile: // subset of VmRSS, linux-4.5 + P->vm_rss_file = strtol(S,&S,10); + continue; + case_RssShmem: // subset of VmRSS, linux-4.5 + P->vm_rss_shared = strtol(S,&S,10); + continue; case_VmSize: P->vm_size = strtol(S,&S,10); continue; @@ -439,6 +449,7 @@ ENTER(0x220); LEAVE(0x220); } +#undef GPERF_TABLE_SIZE static void supgrps_from_supgids (proc_t *p) { char *g, *s; diff --git a/proc/readproc.h b/proc/readproc.h index 80924716..10160b40 100644 --- a/proc/readproc.h +++ b/proc/readproc.h @@ -117,6 +117,9 @@ typedef struct proc_t { vm_size, // status equals 'size' (as kb) vm_lock, // status locked pages (as kb) vm_rss, // status equals 'rss' and/or 'resident' (as kb) + vm_rss_anon, // status the 'anonymous' portion of vm_rss (as kb) + vm_rss_file, // status the 'file-backed' portion of vm_rss (as kb) + vm_rss_shared, // status the 'shared' portion of vm_rss (as kb) vm_data, // status data only size (as kb) vm_stack, // status stack only size (as kb) vm_swap, // status based on linux-2.6.34 "swap ents" (as kb) -- 2.40.0