library: exploit linux-4.5 resident memory enhancement

Beginning with linux-4.5, the following new fields are
being added under that /proc/<pid>/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 1f8e41d019
Signed-off-by: Jim Warner <james.warner@comcast.net>
This commit is contained in:
Jim Warner 2016-04-13 00:00:00 -05:00 committed by Craig Small
parent b921e2e765
commit 8dc378f6a8
4 changed files with 95 additions and 69 deletions

View File

@ -242,6 +242,10 @@ REG_set(VM_EXE, ul_int, vm_exe)
REG_set(VM_LIB, ul_int, vm_lib) REG_set(VM_LIB, ul_int, vm_lib)
REG_set(VM_LOCK, ul_int, vm_lock) REG_set(VM_LOCK, ul_int, vm_lock)
REG_set(VM_RSS, ul_int, vm_rss) 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_SIZE, ul_int, vm_size)
REG_set(VM_STACK, ul_int, vm_stack) REG_set(VM_STACK, ul_int, vm_stack)
REG_set(VM_SWAP, ul_int, vm_swap) 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_LIB), f_status, NULL, QS(ul_int), 0, -1 },
{ RS(VM_LOCK), 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), 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_SIZE), f_status, NULL, QS(ul_int), 0, -1 },
{ RS(VM_STACK), 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 }, { RS(VM_SWAP), f_status, NULL, QS(ul_int), 0, -1 },

View File

@ -132,6 +132,10 @@ enum pids_item {
PROCPS_PIDS_VM_LIB, // ul_int PROCPS_PIDS_VM_LIB, // ul_int
PROCPS_PIDS_VM_LOCK, // ul_int PROCPS_PIDS_VM_LOCK, // ul_int
PROCPS_PIDS_VM_RSS, // 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_SIZE, // ul_int
PROCPS_PIDS_VM_STACK, // ul_int PROCPS_PIDS_VM_STACK, // ul_int
PROCPS_PIDS_VM_SWAP, // ul_int PROCPS_PIDS_VM_SWAP, // ul_int

View File

@ -113,7 +113,7 @@ static inline void free_acquired (proc_t *p, int reuse) {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
typedef struct status_table_struct { 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 unsigned char len; // name length
#ifdef LABEL_OFFSET #ifdef LABEL_OFFSET
long offset; // jump address offset long offset; // jump address offset
@ -129,8 +129,11 @@ typedef struct status_table_struct {
#endif #endif
#define NUL {"", 0, 0}, #define NUL {"", 0, 0},
#define GPERF_TABLE_SIZE 128
// Derived from: // Derived from:
// gperf -7 --language=ANSI-C --key-positions=1,3,4 -C -n -c <if-not-piped> // gperf -7 --language=ANSI-C --key-positions=1,3,4 -C -n -c <if-not-piped>
// ( --key-positions verified by omission & reported "Computed positions" )
// //
// Suggested method: // Suggested method:
// Grep this file for "case_", then strip those down to the name. // 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. // the F macro and replacing empty strings with the NUL define.
// //
// In the status_table_struct watch out for name size (grrr, expanding) // 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 // and the number of entries. Currently, the table is padded to 128
// must be padded out to 64 entries, maybe 128 in the future. // entries and we therefore mask with 127.
static void status2proc(char *S, proc_t *restrict P, int is_proc){ static void status2proc(char *S, proc_t *restrict P, int is_proc){
long Threads = 0; 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 // 128 entries because we trust the kernel to use ASCII names
static const unsigned char asso[] = static const unsigned char asso[] =
{ {
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
64, 64, 64, 64, 64, 64, 64, 64, 28, 64, 101, 101, 101, 101, 101, 101, 101, 101, 6, 101,
64, 64, 64, 64, 64, 64, 8, 25, 23, 25, 101, 101, 101, 101, 101, 45, 55, 25, 31, 50,
6, 25, 0, 3, 64, 64, 3, 64, 25, 64, 50, 10, 0, 35, 101, 101, 21, 101, 30, 101,
20, 1, 1, 5, 0, 30, 0, 0, 64, 64, 20, 36, 0, 5, 0, 40, 0, 0, 101, 101,
64, 64, 64, 64, 64, 64, 64, 3, 64, 0, 101, 101, 101, 101, 101, 101, 101, 30, 101, 15,
0, 18, 64, 10, 64, 10, 64, 64, 64, 20, 0, 1, 101, 10, 101, 10, 101, 101, 101, 25,
64, 20, 0, 64, 25, 64, 3, 15, 64, 0, 101, 40, 0, 101, 0, 50, 6, 40, 101, 1,
30, 64, 64, 64, 64, 64, 64, 64 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) F(VmHWM)
NUL NUL
F(VmLck)
NUL
F(VmSwap)
F(VmRSS)
NUL
F(VmStk)
NUL
F(Tgid)
F(State)
NUL
F(VmLib)
NUL
F(VmSize)
F(SigQ)
NUL
F(SigIgn)
NUL
F(VmPTE)
F(FDSize)
NUL
F(SigBlk)
NUL
F(ShdPnd)
F(VmData)
NUL
F(CapInh)
NUL
F(PPid)
NUL NUL
F(CapBnd)
NUL
F(SigPnd)
NUL NUL
F(VmPeak)
NUL
F(SigCgt)
NUL NUL
F(Threads) F(Threads)
NUL NUL NUL NUL
F(CapPrm) F(VmRSS)
NUL NUL F(VmSwap)
F(Pid) NUL NUL NUL
NUL F(Tgid)
F(CapEff) F(VmStk)
NUL NUL NUL NUL NUL
F(VmSize)
F(Gid) F(Gid)
NUL NUL NUL NUL
F(VmExe) F(VmPTE)
NUL NUL 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
F(SigCgt)
F(State)
NUL NUL NUL
F(CapPrm)
F(Uid) F(Uid)
NUL NUL NUL NUL
F(Groups) F(SigIgn)
NUL NUL F(SigQ)
NUL NUL NUL
F(RssShmem)
F(Name) 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)
}; };
#undef F #undef F
@ -248,7 +249,7 @@ ENTER(0x220);
// examine a field name (hash and compare) // examine a field name (hash and compare)
base: base:
if(unlikely(!*S)) break; 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, ':'); colon = strchr(S, ':');
if(unlikely(!colon)) break; if(unlikely(!colon)) break;
if(unlikely(colon[1]!='\t')) break; if(unlikely(colon[1]!='\t')) break;
@ -364,6 +365,15 @@ ENTER(0x220);
case_VmRSS: case_VmRSS:
P->vm_rss = strtol(S,&S,10); P->vm_rss = strtol(S,&S,10);
continue; 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: case_VmSize:
P->vm_size = strtol(S,&S,10); P->vm_size = strtol(S,&S,10);
continue; continue;
@ -439,6 +449,7 @@ ENTER(0x220);
LEAVE(0x220); LEAVE(0x220);
} }
#undef GPERF_TABLE_SIZE
static void supgrps_from_supgids (proc_t *p) { static void supgrps_from_supgids (proc_t *p) {
char *g, *s; char *g, *s;

View File

@ -117,6 +117,9 @@ typedef struct proc_t {
vm_size, // status equals 'size' (as kb) vm_size, // status equals 'size' (as kb)
vm_lock, // status locked pages (as kb) vm_lock, // status locked pages (as kb)
vm_rss, // status equals 'rss' and/or 'resident' (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_data, // status data only size (as kb)
vm_stack, // status stack 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) vm_swap, // status based on linux-2.6.34 "swap ents" (as kb)