Created
February 6, 2020 20:24
-
-
Save gsauthof/2691e13bbaec23af6a3931ceb139c325 to your computer and use it in GitHub Desktop.
Remove environment variable from /proc/$pid/environ under Linux
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Demonstrate how to remove an environment variable from /proc/$pid/environ, | |
under Linux. | |
This pseudo file is accessible by other processes with sufficient privileges | |
(i.e. same user or root) and exposes the original environment vector. | |
Removing sensitive variables from it can be part of a defense in depth | |
strategy (i.e. to make it harder for a casual attacker to access it). | |
*/ | |
/** {{{ MIT No Attribution | |
Copyright 2020 Georg Sauthoff <[email protected]> | |
Permission is hereby granted, free of charge, to any person | |
obtaining a copy of this software and associated documentation | |
files (the "Software"), to deal in the Software without | |
restriction, including without limitation the rights to use, | |
copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the | |
Software is furnished to do so. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | |
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | |
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
OTHER DEALINGS IN THE SOFTWARE. | |
cf. https://github.com/aws/mit-0 | |
}}} */ | |
#define _GNU_SOURCE | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <stdint.h> | |
#include <sys/types.h> | |
#include <unistd.h> | |
#include <sys/prctl.h> | |
static int get_mm_map(const char *filename, struct prctl_mm_map *m) | |
{ | |
// cf. proc(5) | |
const char fmt[] = | |
"%*d " // (1) pid | |
"%*s " // (2) comm | |
"%*c " // (3) state | |
"%*d " // (4) ppid | |
"%*d " // (5) pgrp | |
"%*d " // (6) session | |
"%*d " // (7) tty_nr | |
"%*d " // (8) tpgid | |
"%*u " // (9) flags | |
"%*u " // "%lu" // (10) minflt | |
"%*u " // "%lu" // (11) cminflt | |
"%*u " // "%lu" // (12) majflt | |
"%*u " // "%lu" // (13) cmajflt | |
"%*u " // "%lu" // (14) utime | |
"%*u " // "%lu" // (15) stime | |
"%*d " // "%ld" // (16) cutime | |
"%*d " // "%ld" // (17) cstime | |
"%*d " // "%ld" // (18) priority | |
"%*d " // "%ld" // (19) nice | |
"%*d " // "%ld" // (20) num_threads | |
"%*d " // "%ld" // (21) itrealvalue | |
"%*u " // "%llu" // (22) starttime | |
"%*u " // "%lu" // (23) vsize | |
"%*d " // "%ld" // (24) rss | |
"%*u " // "%lu" // (25) rsslim | |
/* 0 */ "%lu " // (26) start_code [PT] | |
/* 1 */ "%lu " // (27) end_code [PT] | |
/* 2 */ "%lu " // (28) start_stack [PT] | |
"%*u " // "%lu" // (29) kstkesp [PT] | |
"%*u " // "%lu" // (30) kstkeip [PT] | |
"%*u " // "%lu" // (31) signal | |
"%*u " // "%lu" // (32) blocked | |
"%*u " // "%lu" // (33) sigignore | |
"%*u " // "%lu" // (34) sigcatch | |
"%*u " // "%lu" // (35) wchan [PT] | |
"%*u " // "%lu" // (36) nswap | |
"%*u " // "%lu" // (37) cnswap | |
"%*d " // (38) exit_signal (since Linux 2.1.22) | |
"%*d " // (39) processor (since Linux 2.2.8) | |
"%*u " // (40) rt_priority (since Linux 2.5.19) | |
"%*u " // (41) policy (since Linux 2.5.19) | |
"%*u " // "%llu" // (42) delayacct_blkio_ticks (since Linux 2.6.18) | |
"%*u " // "%lu" // (43) guest_time (since Linux 2.6.24) | |
"%*d " // "%ld" // (44) cguest_time (since Linux 2.6.24) | |
/* 3 */ "%lu " // (45) start_data (since Linux 3.3) [PT] | |
/* 4 */ "%lu " // (46) end_data (since Linux 3.3) [PT] | |
/* 5 */ "%lu " // (47) start_brk (since Linux 3.3) [PT] | |
/* 6 */ "%lu " // (48) arg_start (since Linux 3.5) [PT] | |
/* 7 */ "%lu " // (49) arg_end (since Linux 3.5) [PT] | |
/* 8 */ "%lu " // (50) env_start (since Linux 3.5) [PT] | |
/* 9 */ "%lu " // (51) env_end (since Linux 3.5) [PT] | |
"%*d" // (52) exit_code (since Linux 3.5) [PT] | |
; | |
unsigned long start_code, end_code, start_stack, start_data, end_data, | |
start_brk, arg_start, arg_end, env_start, env_end; | |
FILE *f = fopen(filename, "r"); | |
if (!f) { | |
perror("fopen"); | |
return -1; | |
} | |
int r = fscanf(f, fmt, | |
&start_code, &end_code, &start_stack, | |
&start_data, &end_data, &start_brk, | |
&arg_start, &arg_end, &env_start, &env_end); | |
if (r != 10) { | |
fprintf(stderr, "parsing /proc/.../environ failed\n"); | |
return -1; | |
} | |
uintptr_t brk = (uintptr_t) sbrk(0); | |
// cf. /usr/include/linux/prctl.h | |
*m = (struct prctl_mm_map){0}; | |
m->start_code = start_code; | |
m->end_code = end_code; | |
m->start_data = start_data; | |
m->end_data = end_data; | |
m->start_brk = start_brk; | |
m->brk = brk; | |
m->start_stack = start_stack; | |
m->arg_start = arg_start; | |
m->arg_end = arg_end; | |
m->env_start = env_start; | |
m->env_end = env_end; | |
m->auxv_size = 0; | |
m->exe_fd = -1; | |
return 0; | |
} | |
static int filter_env(const char *begin, const char *end, const char *prefix, char **obegin, char **oend) | |
{ | |
size_t n = strlen(prefix); | |
char *o = malloc(end-begin); | |
if (!o) | |
return -1; | |
*obegin = o; | |
for (const char *p = begin; p != end; ) { | |
const char *e = memchr(p, 0, end-p); | |
if (e) { | |
++e; | |
} else { | |
e = end; | |
} | |
if (e-p < n || memcmp(prefix, p, n)) | |
o = mempcpy(o, p, e-p); | |
p = e; | |
} | |
*oend = o; | |
return 0; | |
} | |
int main(int argc, char **argv) | |
{ | |
char filename[256]; | |
int pid = getpid(); | |
snprintf(filename, sizeof filename - 1, "/proc/%d/stat", pid); | |
system("< /proc/$PPID/environ tr '\\0' '\\n' | sort"); | |
struct prctl_mm_map m; | |
int r = get_mm_map(filename, &m); | |
if (r) | |
return 1; | |
char *es = 0, *ee = 0; | |
r = filter_env((const char*)(uintptr_t)m.env_start, (const char*)(uintptr_t)m.env_end, "PASS=", &es, &ee); | |
if (r) { | |
fprintf(stderr, "filter failed\n"); | |
return 1; | |
} | |
m.env_start = (uintptr_t)es; | |
m.env_end = (uintptr_t)ee; | |
// int opt, arg2, arg3, arg4, arg5 | |
r = prctl(PR_SET_MM, PR_SET_MM_MAP, (unsigned long) &m, sizeof m, 0); | |
if (r == -1) { | |
perror("prctl"); | |
return 1; | |
} | |
system("< /proc/$PPID/environ tr '\\0' '\\n' | sort"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment