If, in future, you ever want to track environment variable changes like this, (and without running ktrace(1) which requires you to select some process), you use the script below which uses dtrace(1). The script output is not as clean as the kdump(1) one, but, DTrace lets you scan all processes on the system.
Warning: I don't expect the method I've used--which involves trawling through the kernel's proc structure--to work on anything other than NetBSD. I have another, generic, version which works on FreeBSD (and should also on other OSes with DTrace), but, as explained in the script, that version doesn't work on PIE/PIC executables on NetBSD.
Enjoy.
#!/bin/sh
#
# env-trace.sh - Show environment variables of (new) programs using dtrace(1).
# Warning: this script is weird: it contains 3 languages: shell, awk & dtrace.
# Modify at your own peril.
set -eu
me=${0##*/}
PAT=""
usage()
{
printf '%s: Show enviroment variables of (new) programs using DTrace.\n' $me
printf 'Usage: %s [-h] -p STR\n' $me
printf '
-h This help message.
-p STR The string to search for in environment. Eg. "PATH="
Use "=" to show all environment vars.
'
}
while getopts hp: opts
do case $opts in
h) usage
exit 0
;;
p) PAT="$OPTARG"
;;
\?) usage 1>&2
exit 1
;;
esac
done
shift $((OPTIND - 1))
if [ -z "$PAT" ]
then printf 1>&2 '%s: ERROR: empty search string\n' $me
printf 1>&2 'Try "-h" for help.\n'
exit 1
fi
# Do NOT remove "exec"--it is required for proper functioning.
#
exec sed -n -e '/^\/\* ___DTRACE_CODE_START___ \*\/$/,/^\/\* ___DTRACE_CODE_END___\*\/$/p' $0 |
sudo dtrace -q -s /dev/stdin |
awk -v PAT=$PAT '
#
# Hex string -> ASCII char
# Adapted from the Gawk Manual at https://gnu.org/software/gawk/
#
function xtochr(str, c, i, k, n, ret)
{
n = length(str)
ret = 0
for (i = 1; i <= n; i++) {
c = substr(str, i, 1)
c = tolower(c)
# index() returns 0 if c not in string,
# includes c == "0"
k = index("123456789abcdef", c)
ret = ret * 16 + k
}
return ret
}
BEGIN {
str = ""
}
{
if ($0 == " 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef") {
next # skip tracemem() header
}
if ($0 !~ /^[[:blank:]]+[[:xdigit:]]+: ([[:xdigit:]]{2} ){1,16}[[:blank:]]+(.){1,16}$/) {
print # pass-through everything else
next
}
# Convert hex dump back into ASCII and search
# for the string we want.
#
for (i = 2; i <= NF; i++) {
if (i == 18) # skip ASCII component entirely
break;
c = xtochr($i)
if (c == 0) { # end-of-string marker
if (index(str, PAT) > 0)
printf("%s\n", str)
str = ""
}
str = str sprintf("%c", c)
}
}
'
/* ___DTRACE_CODE_START___ */
/*
* On NetBSD, the standard "syscall::execve:{entry,return}" probe stuff
* glitches occasionally when copying stuff from userspace for standard
* executables, and fails completely for position-independent executables.
* So, we the "proc" provider which is _highly_ kernel specific.
*/
proc:::create
/pid != $pid/
{
printf("%d %d %s", uid, pid, execname);
/* Copy `struct ps_strings' from userspace. */
pss = (struct ps_strings *)copyin(args[0]->p_psstrp, sizeof (struct ps_strings));
/* Copy env. ptr. array from userspace. */
envc = pss->ps_nenvstr; /* no. of env. strings */
printf(" envc=%d", envc);
envp = (uintptr_t)pss->ps_envstr;
addrs = (uintptr_t *)copyin(envp, envc * sizeof (uintptr_t));
/* Copy env. string array from userspace. */
first = addrs[0]; /* addr. of first env. string */
last = addrs[envc - 1]; /* addr. of last env. string */
s = copyinstr(last); /* copy last env. string from US */
n = strlen(s) + 1; /* must include '\0' at end */
len = (last - first) + n; /* actual size of env. strings */
printf(" len=%d", len);
buf = copyin(first, len);
/*
* stringof(copyin(buf, len)); followed by printf("%S\n");
* prints the whole buffer safely when the buffer is the one
* associated with read(2) and write(2), but, stringof()
* truncates at the first '\0' in our case, so we dump
* the buffer using tracemem() and munge it back into
* ASCII using awk(1).
*/
tracemem(buf, 5000, len);
printf("\n");
}
proc:::exec-success
/pid != $pid/
{
printf("%d %d executed=%s\n\n", uid, pid, execname);
}
proc:::exit
/pid != $pid/
{
}
/* ___DTRACE_CODE_END___ */