Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[tools/execsnoop] Try to get parent PID from current task's real parent. #1885

Merged
merged 4 commits into from
Jul 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion tests/python/test_tools_smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ def test_deadlock_detector(self):
# self.run_with_int("deadlock_detector.py $(pgrep -n bash)", timeout=10)
pass

@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
@skipUnless(kernel_version_ge(4,8), "requires kernel >= 4.8")
def test_execsnoop(self):
self.run_with_int("execsnoop.py")

Expand Down
29 changes: 25 additions & 4 deletions tools/execsnoop.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@

struct data_t {
u32 pid; // PID as in the userspace term (i.e. task->tgid in kernel)
u32 ppid; // Parent PID as in the userspace term (i.e task->real_parent->tgid in kernel)
char comm[TASK_COMM_LEN];
enum event_type type;
char argv[ARGSIZE];
Expand Down Expand Up @@ -105,7 +106,16 @@
{
// create data here and pass to submit_arg to save stack space (#555)
struct data_t data = {};
struct task_struct *task;

data.pid = bpf_get_current_pid_tgid() >> 32;

task = (struct task_struct *)bpf_get_current_task();
// Some kernels, like Ubuntu 4.13.0-generic, return 0
// as the real_parent->tgid.
// We use the get_ppid function as a fallback in those cases. (#1883)
data.ppid = task->real_parent->tgid;

bpf_get_current_comm(&data.comm, sizeof(data.comm));
data.type = EVENT_ARG;

Expand All @@ -128,7 +138,16 @@
int do_ret_sys_execve(struct pt_regs *ctx)
{
struct data_t data = {};
struct task_struct *task;

data.pid = bpf_get_current_pid_tgid() >> 32;

task = (struct task_struct *)bpf_get_current_task();
// Some kernels, like Ubuntu 4.13.0-generic, return 0
// as the real_parent->tgid.
// We use the get_ppid function as a fallback in those cases. (#1883)
data.ppid = task->real_parent->tgid;

bpf_get_current_comm(&data.comm, sizeof(data.comm));
data.type = EVENT_RET;
data.retval = PT_REGS_RC(ctx);
Expand Down Expand Up @@ -160,6 +179,7 @@
class Data(ct.Structure):
_fields_ = [
("pid", ct.c_uint),
("ppid", ct.c_uint),
("comm", ct.c_char * TASK_COMM_LEN),
("type", ct.c_int),
("argv", ct.c_char * ARGSIZE),
Expand All @@ -173,9 +193,10 @@ class EventType(object):
start_ts = time.time()
argv = defaultdict(list)

# TODO: This is best-effort PPID matching. Short-lived processes may exit
# before we get a chance to read the PPID. This should be replaced with
# fetching PPID via C when available (#364).
# This is best-effort PPID matching. Short-lived processes may exit
# before we get a chance to read the PPID.
# This is a fallback for when fetching the PPID from task->real_parent->tgip
# returns 0, which happens in some kernel versions.
def get_ppid(pid):
try:
with open("/proc/%d/status" % pid) as status:
Expand Down Expand Up @@ -211,7 +232,7 @@ def print_event(cpu, data, size):
if not skip:
if args.timestamp:
print("%-8.3f" % (time.time() - start_ts), end="")
ppid = get_ppid(event.pid)
ppid = event.ppid if event.ppid > 0 else get_ppid(event.pid)
ppid = b"%d" % ppid if ppid > 0 else b"?"
argv_text = b' '.join(argv[event.pid]).replace(b'\n', b'\\n')
printb(b"%-16s %-6d %-6s %3d %s" % (event.comm, event.pid,
Expand Down