xref: /aosp_15_r20/external/bcc/tools/mountsnoop.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python
2*387f9dfdSAndroid Build Coastguard Worker#
3*387f9dfdSAndroid Build Coastguard Worker# mountsnoop Trace mount() and umount syscalls.
4*387f9dfdSAndroid Build Coastguard Worker#            For Linux, uses BCC, eBPF. Embedded C.
5*387f9dfdSAndroid Build Coastguard Worker#
6*387f9dfdSAndroid Build Coastguard Worker# USAGE: mountsnoop [-h]
7*387f9dfdSAndroid Build Coastguard Worker#
8*387f9dfdSAndroid Build Coastguard Worker# Copyright (c) 2016 Facebook, Inc.
9*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
10*387f9dfdSAndroid Build Coastguard Worker#
11*387f9dfdSAndroid Build Coastguard Worker# 14-Oct-2016   Omar Sandoval   Created this.
12*387f9dfdSAndroid Build Coastguard Worker
13*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function
14*387f9dfdSAndroid Build Coastguard Workerimport argparse
15*387f9dfdSAndroid Build Coastguard Workerimport bcc
16*387f9dfdSAndroid Build Coastguard Workerfrom bcc.containers import filter_by_containers
17*387f9dfdSAndroid Build Coastguard Workerimport ctypes
18*387f9dfdSAndroid Build Coastguard Workerimport errno
19*387f9dfdSAndroid Build Coastguard Workerimport functools
20*387f9dfdSAndroid Build Coastguard Workerimport sys
21*387f9dfdSAndroid Build Coastguard Worker
22*387f9dfdSAndroid Build Coastguard Worker
23*387f9dfdSAndroid Build Coastguard Workerbpf_text = r"""
24*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h>
25*387f9dfdSAndroid Build Coastguard Worker#include <linux/sched.h>
26*387f9dfdSAndroid Build Coastguard Worker
27*387f9dfdSAndroid Build Coastguard Worker#include <linux/nsproxy.h>
28*387f9dfdSAndroid Build Coastguard Worker#include <linux/ns_common.h>
29*387f9dfdSAndroid Build Coastguard Worker
30*387f9dfdSAndroid Build Coastguard Worker/*
31*387f9dfdSAndroid Build Coastguard Worker * XXX: struct mnt_namespace is defined in fs/mount.h, which is private to the
32*387f9dfdSAndroid Build Coastguard Worker * VFS and not installed in any kernel-devel packages. So, let's duplicate the
33*387f9dfdSAndroid Build Coastguard Worker * important part of the definition. There are actually more members in the
34*387f9dfdSAndroid Build Coastguard Worker * real struct, but we don't need them, and they're more likely to change.
35*387f9dfdSAndroid Build Coastguard Worker *
36*387f9dfdSAndroid Build Coastguard Worker * To add support for --selector option, we need to call filter_by_containers().
37*387f9dfdSAndroid Build Coastguard Worker * But this function adds code which defines struct mnt_namespace.
38*387f9dfdSAndroid Build Coastguard Worker * To avoid having this structure twice, we define MNT_NAMESPACE_DEFINED in
39*387f9dfdSAndroid Build Coastguard Worker * filter_by_containers(), then here we check if macro is already defined before
40*387f9dfdSAndroid Build Coastguard Worker * adding struct definition.
41*387f9dfdSAndroid Build Coastguard Worker */
42*387f9dfdSAndroid Build Coastguard Worker#ifndef MNT_NAMESPACE_DEFINED
43*387f9dfdSAndroid Build Coastguard Workerstruct mnt_namespace {
44*387f9dfdSAndroid Build Coastguard Worker    // This field was removed in https://github.com/torvalds/linux/commit/1a7b8969e664d6af328f00fe6eb7aabd61a71d13
45*387f9dfdSAndroid Build Coastguard Worker    #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0)
46*387f9dfdSAndroid Build Coastguard Worker    atomic_t count;
47*387f9dfdSAndroid Build Coastguard Worker    #endif
48*387f9dfdSAndroid Build Coastguard Worker    struct ns_common ns;
49*387f9dfdSAndroid Build Coastguard Worker};
50*387f9dfdSAndroid Build Coastguard Worker#endif /* !MNT_NAMESPACE_DEFINED */
51*387f9dfdSAndroid Build Coastguard Worker
52*387f9dfdSAndroid Build Coastguard Worker/*
53*387f9dfdSAndroid Build Coastguard Worker * XXX: this could really use first-class string support in BPF. target is a
54*387f9dfdSAndroid Build Coastguard Worker * NUL-terminated path up to PATH_MAX in length. source and type are
55*387f9dfdSAndroid Build Coastguard Worker * NUL-terminated strings up to PAGE_SIZE in length. data is a weird case: it's
56*387f9dfdSAndroid Build Coastguard Worker * almost always a NUL-terminated string, but for some filesystems (e.g., older
57*387f9dfdSAndroid Build Coastguard Worker * NFS variants), it's a binary structure with plenty of NUL bytes, so the
58*387f9dfdSAndroid Build Coastguard Worker * kernel always copies up to PAGE_SIZE bytes, stopping when it hits a fault.
59*387f9dfdSAndroid Build Coastguard Worker *
60*387f9dfdSAndroid Build Coastguard Worker * The best we can do with the existing BPF helpers is to copy as much of each
61*387f9dfdSAndroid Build Coastguard Worker * argument as we can. Our stack space is limited, and we need to leave some
62*387f9dfdSAndroid Build Coastguard Worker * headroom for the rest of the function, so this should be a decent value.
63*387f9dfdSAndroid Build Coastguard Worker */
64*387f9dfdSAndroid Build Coastguard Worker#define MAX_STR_LEN 412
65*387f9dfdSAndroid Build Coastguard Worker
66*387f9dfdSAndroid Build Coastguard Workerenum event_type {
67*387f9dfdSAndroid Build Coastguard Worker    EVENT_MOUNT,
68*387f9dfdSAndroid Build Coastguard Worker    EVENT_MOUNT_SOURCE,
69*387f9dfdSAndroid Build Coastguard Worker    EVENT_MOUNT_TARGET,
70*387f9dfdSAndroid Build Coastguard Worker    EVENT_MOUNT_TYPE,
71*387f9dfdSAndroid Build Coastguard Worker    EVENT_MOUNT_DATA,
72*387f9dfdSAndroid Build Coastguard Worker    EVENT_MOUNT_RET,
73*387f9dfdSAndroid Build Coastguard Worker    EVENT_UMOUNT,
74*387f9dfdSAndroid Build Coastguard Worker    EVENT_UMOUNT_TARGET,
75*387f9dfdSAndroid Build Coastguard Worker    EVENT_UMOUNT_RET,
76*387f9dfdSAndroid Build Coastguard Worker};
77*387f9dfdSAndroid Build Coastguard Worker
78*387f9dfdSAndroid Build Coastguard Workerstruct data_t {
79*387f9dfdSAndroid Build Coastguard Worker    enum event_type type;
80*387f9dfdSAndroid Build Coastguard Worker    pid_t pid, tgid;
81*387f9dfdSAndroid Build Coastguard Worker    union {
82*387f9dfdSAndroid Build Coastguard Worker        /* EVENT_MOUNT, EVENT_UMOUNT */
83*387f9dfdSAndroid Build Coastguard Worker        struct {
84*387f9dfdSAndroid Build Coastguard Worker            /* current->nsproxy->mnt_ns->ns.inum */
85*387f9dfdSAndroid Build Coastguard Worker            unsigned int mnt_ns;
86*387f9dfdSAndroid Build Coastguard Worker            char comm[TASK_COMM_LEN];
87*387f9dfdSAndroid Build Coastguard Worker            char pcomm[TASK_COMM_LEN];
88*387f9dfdSAndroid Build Coastguard Worker            pid_t ppid;
89*387f9dfdSAndroid Build Coastguard Worker            unsigned long flags;
90*387f9dfdSAndroid Build Coastguard Worker        } enter;
91*387f9dfdSAndroid Build Coastguard Worker        /*
92*387f9dfdSAndroid Build Coastguard Worker         * EVENT_MOUNT_SOURCE, EVENT_MOUNT_TARGET, EVENT_MOUNT_TYPE,
93*387f9dfdSAndroid Build Coastguard Worker         * EVENT_MOUNT_DATA, EVENT_UMOUNT_TARGET
94*387f9dfdSAndroid Build Coastguard Worker         */
95*387f9dfdSAndroid Build Coastguard Worker        char str[MAX_STR_LEN];
96*387f9dfdSAndroid Build Coastguard Worker        /* EVENT_MOUNT_RET, EVENT_UMOUNT_RET */
97*387f9dfdSAndroid Build Coastguard Worker        int retval;
98*387f9dfdSAndroid Build Coastguard Worker    };
99*387f9dfdSAndroid Build Coastguard Worker};
100*387f9dfdSAndroid Build Coastguard Worker
101*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(events);
102*387f9dfdSAndroid Build Coastguard Worker
103*387f9dfdSAndroid Build Coastguard Workerint syscall__mount(struct pt_regs *ctx, char __user *source,
104*387f9dfdSAndroid Build Coastguard Worker                      char __user *target, char __user *type,
105*387f9dfdSAndroid Build Coastguard Worker                      unsigned long flags, char __user *data)
106*387f9dfdSAndroid Build Coastguard Worker{
107*387f9dfdSAndroid Build Coastguard Worker    struct data_t event = {};
108*387f9dfdSAndroid Build Coastguard Worker    struct task_struct *task;
109*387f9dfdSAndroid Build Coastguard Worker    struct nsproxy *nsproxy;
110*387f9dfdSAndroid Build Coastguard Worker    struct mnt_namespace *mnt_ns;
111*387f9dfdSAndroid Build Coastguard Worker
112*387f9dfdSAndroid Build Coastguard Worker    if (container_should_be_filtered()) {
113*387f9dfdSAndroid Build Coastguard Worker        return 0;
114*387f9dfdSAndroid Build Coastguard Worker    }
115*387f9dfdSAndroid Build Coastguard Worker
116*387f9dfdSAndroid Build Coastguard Worker    event.pid = bpf_get_current_pid_tgid() & 0xffffffff;
117*387f9dfdSAndroid Build Coastguard Worker    event.tgid = bpf_get_current_pid_tgid() >> 32;
118*387f9dfdSAndroid Build Coastguard Worker
119*387f9dfdSAndroid Build Coastguard Worker    event.type = EVENT_MOUNT;
120*387f9dfdSAndroid Build Coastguard Worker    bpf_get_current_comm(event.enter.comm, sizeof(event.enter.comm));
121*387f9dfdSAndroid Build Coastguard Worker    event.enter.flags = flags;
122*387f9dfdSAndroid Build Coastguard Worker    task = (struct task_struct *)bpf_get_current_task();
123*387f9dfdSAndroid Build Coastguard Worker    event.enter.ppid = task->real_parent->tgid;
124*387f9dfdSAndroid Build Coastguard Worker    bpf_probe_read_kernel_str(&event.enter.pcomm, TASK_COMM_LEN, task->real_parent->comm);
125*387f9dfdSAndroid Build Coastguard Worker    nsproxy = task->nsproxy;
126*387f9dfdSAndroid Build Coastguard Worker    mnt_ns = nsproxy->mnt_ns;
127*387f9dfdSAndroid Build Coastguard Worker    event.enter.mnt_ns = mnt_ns->ns.inum;
128*387f9dfdSAndroid Build Coastguard Worker    events.perf_submit(ctx, &event, sizeof(event));
129*387f9dfdSAndroid Build Coastguard Worker
130*387f9dfdSAndroid Build Coastguard Worker    event.type = EVENT_MOUNT_SOURCE;
131*387f9dfdSAndroid Build Coastguard Worker    __builtin_memset(event.str, 0, sizeof(event.str));
132*387f9dfdSAndroid Build Coastguard Worker    bpf_probe_read_user(event.str, sizeof(event.str), source);
133*387f9dfdSAndroid Build Coastguard Worker    events.perf_submit(ctx, &event, sizeof(event));
134*387f9dfdSAndroid Build Coastguard Worker
135*387f9dfdSAndroid Build Coastguard Worker    event.type = EVENT_MOUNT_TARGET;
136*387f9dfdSAndroid Build Coastguard Worker    __builtin_memset(event.str, 0, sizeof(event.str));
137*387f9dfdSAndroid Build Coastguard Worker    bpf_probe_read_user(event.str, sizeof(event.str), target);
138*387f9dfdSAndroid Build Coastguard Worker    events.perf_submit(ctx, &event, sizeof(event));
139*387f9dfdSAndroid Build Coastguard Worker
140*387f9dfdSAndroid Build Coastguard Worker    event.type = EVENT_MOUNT_TYPE;
141*387f9dfdSAndroid Build Coastguard Worker    __builtin_memset(event.str, 0, sizeof(event.str));
142*387f9dfdSAndroid Build Coastguard Worker    bpf_probe_read_user(event.str, sizeof(event.str), type);
143*387f9dfdSAndroid Build Coastguard Worker    events.perf_submit(ctx, &event, sizeof(event));
144*387f9dfdSAndroid Build Coastguard Worker
145*387f9dfdSAndroid Build Coastguard Worker    event.type = EVENT_MOUNT_DATA;
146*387f9dfdSAndroid Build Coastguard Worker    __builtin_memset(event.str, 0, sizeof(event.str));
147*387f9dfdSAndroid Build Coastguard Worker    bpf_probe_read_user(event.str, sizeof(event.str), data);
148*387f9dfdSAndroid Build Coastguard Worker    events.perf_submit(ctx, &event, sizeof(event));
149*387f9dfdSAndroid Build Coastguard Worker
150*387f9dfdSAndroid Build Coastguard Worker    return 0;
151*387f9dfdSAndroid Build Coastguard Worker}
152*387f9dfdSAndroid Build Coastguard Worker
153*387f9dfdSAndroid Build Coastguard Workerint do_ret_sys_mount(struct pt_regs *ctx)
154*387f9dfdSAndroid Build Coastguard Worker{
155*387f9dfdSAndroid Build Coastguard Worker    struct data_t event = {};
156*387f9dfdSAndroid Build Coastguard Worker
157*387f9dfdSAndroid Build Coastguard Worker    event.type = EVENT_MOUNT_RET;
158*387f9dfdSAndroid Build Coastguard Worker    event.pid = bpf_get_current_pid_tgid() & 0xffffffff;
159*387f9dfdSAndroid Build Coastguard Worker    event.tgid = bpf_get_current_pid_tgid() >> 32;
160*387f9dfdSAndroid Build Coastguard Worker    event.retval = PT_REGS_RC(ctx);
161*387f9dfdSAndroid Build Coastguard Worker    events.perf_submit(ctx, &event, sizeof(event));
162*387f9dfdSAndroid Build Coastguard Worker
163*387f9dfdSAndroid Build Coastguard Worker    return 0;
164*387f9dfdSAndroid Build Coastguard Worker}
165*387f9dfdSAndroid Build Coastguard Worker
166*387f9dfdSAndroid Build Coastguard Workerint syscall__umount(struct pt_regs *ctx, char __user *target, int flags)
167*387f9dfdSAndroid Build Coastguard Worker{
168*387f9dfdSAndroid Build Coastguard Worker    struct data_t event = {};
169*387f9dfdSAndroid Build Coastguard Worker    struct task_struct *task;
170*387f9dfdSAndroid Build Coastguard Worker    struct nsproxy *nsproxy;
171*387f9dfdSAndroid Build Coastguard Worker    struct mnt_namespace *mnt_ns;
172*387f9dfdSAndroid Build Coastguard Worker
173*387f9dfdSAndroid Build Coastguard Worker    if (container_should_be_filtered()) {
174*387f9dfdSAndroid Build Coastguard Worker        return 0;
175*387f9dfdSAndroid Build Coastguard Worker    }
176*387f9dfdSAndroid Build Coastguard Worker
177*387f9dfdSAndroid Build Coastguard Worker    event.pid = bpf_get_current_pid_tgid() & 0xffffffff;
178*387f9dfdSAndroid Build Coastguard Worker    event.tgid = bpf_get_current_pid_tgid() >> 32;
179*387f9dfdSAndroid Build Coastguard Worker
180*387f9dfdSAndroid Build Coastguard Worker    event.type = EVENT_UMOUNT;
181*387f9dfdSAndroid Build Coastguard Worker    bpf_get_current_comm(event.enter.comm, sizeof(event.enter.comm));
182*387f9dfdSAndroid Build Coastguard Worker    event.enter.flags = flags;
183*387f9dfdSAndroid Build Coastguard Worker    task = (struct task_struct *)bpf_get_current_task();
184*387f9dfdSAndroid Build Coastguard Worker    event.enter.ppid = task->real_parent->tgid;
185*387f9dfdSAndroid Build Coastguard Worker    bpf_probe_read_kernel_str(&event.enter.pcomm, TASK_COMM_LEN, task->real_parent->comm);
186*387f9dfdSAndroid Build Coastguard Worker    nsproxy = task->nsproxy;
187*387f9dfdSAndroid Build Coastguard Worker    mnt_ns = nsproxy->mnt_ns;
188*387f9dfdSAndroid Build Coastguard Worker    event.enter.mnt_ns = mnt_ns->ns.inum;
189*387f9dfdSAndroid Build Coastguard Worker    events.perf_submit(ctx, &event, sizeof(event));
190*387f9dfdSAndroid Build Coastguard Worker
191*387f9dfdSAndroid Build Coastguard Worker    event.type = EVENT_UMOUNT_TARGET;
192*387f9dfdSAndroid Build Coastguard Worker    __builtin_memset(event.str, 0, sizeof(event.str));
193*387f9dfdSAndroid Build Coastguard Worker    bpf_probe_read_user(event.str, sizeof(event.str), target);
194*387f9dfdSAndroid Build Coastguard Worker    events.perf_submit(ctx, &event, sizeof(event));
195*387f9dfdSAndroid Build Coastguard Worker
196*387f9dfdSAndroid Build Coastguard Worker    return 0;
197*387f9dfdSAndroid Build Coastguard Worker}
198*387f9dfdSAndroid Build Coastguard Worker
199*387f9dfdSAndroid Build Coastguard Workerint do_ret_sys_umount(struct pt_regs *ctx)
200*387f9dfdSAndroid Build Coastguard Worker{
201*387f9dfdSAndroid Build Coastguard Worker    struct data_t event = {};
202*387f9dfdSAndroid Build Coastguard Worker
203*387f9dfdSAndroid Build Coastguard Worker    event.type = EVENT_UMOUNT_RET;
204*387f9dfdSAndroid Build Coastguard Worker    event.pid = bpf_get_current_pid_tgid() & 0xffffffff;
205*387f9dfdSAndroid Build Coastguard Worker    event.tgid = bpf_get_current_pid_tgid() >> 32;
206*387f9dfdSAndroid Build Coastguard Worker    event.retval = PT_REGS_RC(ctx);
207*387f9dfdSAndroid Build Coastguard Worker    events.perf_submit(ctx, &event, sizeof(event));
208*387f9dfdSAndroid Build Coastguard Worker
209*387f9dfdSAndroid Build Coastguard Worker    return 0;
210*387f9dfdSAndroid Build Coastguard Worker}
211*387f9dfdSAndroid Build Coastguard Worker"""
212*387f9dfdSAndroid Build Coastguard Worker
213*387f9dfdSAndroid Build Coastguard Worker# sys/mount.h
214*387f9dfdSAndroid Build Coastguard WorkerMS_MGC_VAL = 0xc0ed0000
215*387f9dfdSAndroid Build Coastguard WorkerMS_MGC_MSK = 0xffff0000
216*387f9dfdSAndroid Build Coastguard WorkerMOUNT_FLAGS = [
217*387f9dfdSAndroid Build Coastguard Worker    ('MS_RDONLY', 1),
218*387f9dfdSAndroid Build Coastguard Worker    ('MS_NOSUID', 2),
219*387f9dfdSAndroid Build Coastguard Worker    ('MS_NODEV', 4),
220*387f9dfdSAndroid Build Coastguard Worker    ('MS_NOEXEC', 8),
221*387f9dfdSAndroid Build Coastguard Worker    ('MS_SYNCHRONOUS', 16),
222*387f9dfdSAndroid Build Coastguard Worker    ('MS_REMOUNT', 32),
223*387f9dfdSAndroid Build Coastguard Worker    ('MS_MANDLOCK', 64),
224*387f9dfdSAndroid Build Coastguard Worker    ('MS_DIRSYNC', 128),
225*387f9dfdSAndroid Build Coastguard Worker    ('MS_NOATIME', 1024),
226*387f9dfdSAndroid Build Coastguard Worker    ('MS_NODIRATIME', 2048),
227*387f9dfdSAndroid Build Coastguard Worker    ('MS_BIND', 4096),
228*387f9dfdSAndroid Build Coastguard Worker    ('MS_MOVE', 8192),
229*387f9dfdSAndroid Build Coastguard Worker    ('MS_REC', 16384),
230*387f9dfdSAndroid Build Coastguard Worker    ('MS_SILENT', 32768),
231*387f9dfdSAndroid Build Coastguard Worker    ('MS_POSIXACL', 1 << 16),
232*387f9dfdSAndroid Build Coastguard Worker    ('MS_UNBINDABLE', 1 << 17),
233*387f9dfdSAndroid Build Coastguard Worker    ('MS_PRIVATE', 1 << 18),
234*387f9dfdSAndroid Build Coastguard Worker    ('MS_SLAVE', 1 << 19),
235*387f9dfdSAndroid Build Coastguard Worker    ('MS_SHARED', 1 << 20),
236*387f9dfdSAndroid Build Coastguard Worker    ('MS_RELATIME', 1 << 21),
237*387f9dfdSAndroid Build Coastguard Worker    ('MS_KERNMOUNT', 1 << 22),
238*387f9dfdSAndroid Build Coastguard Worker    ('MS_I_VERSION', 1 << 23),
239*387f9dfdSAndroid Build Coastguard Worker    ('MS_STRICTATIME', 1 << 24),
240*387f9dfdSAndroid Build Coastguard Worker    ('MS_LAZYTIME', 1 << 25),
241*387f9dfdSAndroid Build Coastguard Worker    ('MS_ACTIVE', 1 << 30),
242*387f9dfdSAndroid Build Coastguard Worker    ('MS_NOUSER', 1 << 31),
243*387f9dfdSAndroid Build Coastguard Worker]
244*387f9dfdSAndroid Build Coastguard WorkerUMOUNT_FLAGS = [
245*387f9dfdSAndroid Build Coastguard Worker    ('MNT_FORCE', 1),
246*387f9dfdSAndroid Build Coastguard Worker    ('MNT_DETACH', 2),
247*387f9dfdSAndroid Build Coastguard Worker    ('MNT_EXPIRE', 4),
248*387f9dfdSAndroid Build Coastguard Worker    ('UMOUNT_NOFOLLOW', 8),
249*387f9dfdSAndroid Build Coastguard Worker]
250*387f9dfdSAndroid Build Coastguard Worker
251*387f9dfdSAndroid Build Coastguard Worker
252*387f9dfdSAndroid Build Coastguard WorkerTASK_COMM_LEN = 16  # linux/sched.h
253*387f9dfdSAndroid Build Coastguard WorkerMAX_STR_LEN = 412
254*387f9dfdSAndroid Build Coastguard Worker
255*387f9dfdSAndroid Build Coastguard Worker
256*387f9dfdSAndroid Build Coastguard Workerclass EventType(object):
257*387f9dfdSAndroid Build Coastguard Worker    EVENT_MOUNT = 0
258*387f9dfdSAndroid Build Coastguard Worker    EVENT_MOUNT_SOURCE = 1
259*387f9dfdSAndroid Build Coastguard Worker    EVENT_MOUNT_TARGET = 2
260*387f9dfdSAndroid Build Coastguard Worker    EVENT_MOUNT_TYPE = 3
261*387f9dfdSAndroid Build Coastguard Worker    EVENT_MOUNT_DATA = 4
262*387f9dfdSAndroid Build Coastguard Worker    EVENT_MOUNT_RET = 5
263*387f9dfdSAndroid Build Coastguard Worker    EVENT_UMOUNT = 6
264*387f9dfdSAndroid Build Coastguard Worker    EVENT_UMOUNT_TARGET = 7
265*387f9dfdSAndroid Build Coastguard Worker    EVENT_UMOUNT_RET = 8
266*387f9dfdSAndroid Build Coastguard Worker
267*387f9dfdSAndroid Build Coastguard Worker
268*387f9dfdSAndroid Build Coastguard Workerclass EnterData(ctypes.Structure):
269*387f9dfdSAndroid Build Coastguard Worker    _fields_ = [
270*387f9dfdSAndroid Build Coastguard Worker        ('mnt_ns', ctypes.c_uint),
271*387f9dfdSAndroid Build Coastguard Worker        ('comm', ctypes.c_char * TASK_COMM_LEN),
272*387f9dfdSAndroid Build Coastguard Worker        ('pcomm', ctypes.c_char * TASK_COMM_LEN),
273*387f9dfdSAndroid Build Coastguard Worker        ('ppid', ctypes.c_uint),
274*387f9dfdSAndroid Build Coastguard Worker        ('flags', ctypes.c_ulong),
275*387f9dfdSAndroid Build Coastguard Worker    ]
276*387f9dfdSAndroid Build Coastguard Worker
277*387f9dfdSAndroid Build Coastguard Worker
278*387f9dfdSAndroid Build Coastguard Workerclass DataUnion(ctypes.Union):
279*387f9dfdSAndroid Build Coastguard Worker    _fields_ = [
280*387f9dfdSAndroid Build Coastguard Worker        ('enter', EnterData),
281*387f9dfdSAndroid Build Coastguard Worker        ('str', ctypes.c_char * MAX_STR_LEN),
282*387f9dfdSAndroid Build Coastguard Worker        ('retval', ctypes.c_int),
283*387f9dfdSAndroid Build Coastguard Worker    ]
284*387f9dfdSAndroid Build Coastguard Worker
285*387f9dfdSAndroid Build Coastguard Worker
286*387f9dfdSAndroid Build Coastguard Workerclass Event(ctypes.Structure):
287*387f9dfdSAndroid Build Coastguard Worker    _fields_ = [
288*387f9dfdSAndroid Build Coastguard Worker        ('type', ctypes.c_uint),
289*387f9dfdSAndroid Build Coastguard Worker        ('pid', ctypes.c_uint),
290*387f9dfdSAndroid Build Coastguard Worker        ('tgid', ctypes.c_uint),
291*387f9dfdSAndroid Build Coastguard Worker        ('union', DataUnion),
292*387f9dfdSAndroid Build Coastguard Worker    ]
293*387f9dfdSAndroid Build Coastguard Worker
294*387f9dfdSAndroid Build Coastguard Worker
295*387f9dfdSAndroid Build Coastguard Workerdef _decode_flags(flags, flag_list):
296*387f9dfdSAndroid Build Coastguard Worker    str_flags = []
297*387f9dfdSAndroid Build Coastguard Worker    for flag, bit in flag_list:
298*387f9dfdSAndroid Build Coastguard Worker        if flags & bit:
299*387f9dfdSAndroid Build Coastguard Worker            str_flags.append(flag)
300*387f9dfdSAndroid Build Coastguard Worker        flags &= ~bit
301*387f9dfdSAndroid Build Coastguard Worker    if flags or not str_flags:
302*387f9dfdSAndroid Build Coastguard Worker        str_flags.append('0x{:x}'.format(flags))
303*387f9dfdSAndroid Build Coastguard Worker    return str_flags
304*387f9dfdSAndroid Build Coastguard Worker
305*387f9dfdSAndroid Build Coastguard Worker
306*387f9dfdSAndroid Build Coastguard Workerdef decode_flags(flags, flag_list):
307*387f9dfdSAndroid Build Coastguard Worker    return '|'.join(_decode_flags(flags, flag_list))
308*387f9dfdSAndroid Build Coastguard Worker
309*387f9dfdSAndroid Build Coastguard Worker
310*387f9dfdSAndroid Build Coastguard Workerdef decode_mount_flags(flags):
311*387f9dfdSAndroid Build Coastguard Worker    str_flags = []
312*387f9dfdSAndroid Build Coastguard Worker    if flags & MS_MGC_MSK == MS_MGC_VAL:
313*387f9dfdSAndroid Build Coastguard Worker        flags &= ~MS_MGC_MSK
314*387f9dfdSAndroid Build Coastguard Worker        str_flags.append('MS_MGC_VAL')
315*387f9dfdSAndroid Build Coastguard Worker    str_flags.extend(_decode_flags(flags, MOUNT_FLAGS))
316*387f9dfdSAndroid Build Coastguard Worker    return '|'.join(str_flags)
317*387f9dfdSAndroid Build Coastguard Worker
318*387f9dfdSAndroid Build Coastguard Worker
319*387f9dfdSAndroid Build Coastguard Workerdef decode_umount_flags(flags):
320*387f9dfdSAndroid Build Coastguard Worker    return decode_flags(flags, UMOUNT_FLAGS)
321*387f9dfdSAndroid Build Coastguard Worker
322*387f9dfdSAndroid Build Coastguard Worker
323*387f9dfdSAndroid Build Coastguard Workerdef decode_errno(retval):
324*387f9dfdSAndroid Build Coastguard Worker    try:
325*387f9dfdSAndroid Build Coastguard Worker        return '-' + errno.errorcode[-retval]
326*387f9dfdSAndroid Build Coastguard Worker    except KeyError:
327*387f9dfdSAndroid Build Coastguard Worker        return str(retval)
328*387f9dfdSAndroid Build Coastguard Worker
329*387f9dfdSAndroid Build Coastguard Worker
330*387f9dfdSAndroid Build Coastguard Worker_escape_chars = {
331*387f9dfdSAndroid Build Coastguard Worker    ord('\a'): '\\a',
332*387f9dfdSAndroid Build Coastguard Worker    ord('\b'): '\\b',
333*387f9dfdSAndroid Build Coastguard Worker    ord('\t'): '\\t',
334*387f9dfdSAndroid Build Coastguard Worker    ord('\n'): '\\n',
335*387f9dfdSAndroid Build Coastguard Worker    ord('\v'): '\\v',
336*387f9dfdSAndroid Build Coastguard Worker    ord('\f'): '\\f',
337*387f9dfdSAndroid Build Coastguard Worker    ord('\r'): '\\r',
338*387f9dfdSAndroid Build Coastguard Worker    ord('"'): '\\"',
339*387f9dfdSAndroid Build Coastguard Worker    ord('\\'): '\\\\',
340*387f9dfdSAndroid Build Coastguard Worker}
341*387f9dfdSAndroid Build Coastguard Worker
342*387f9dfdSAndroid Build Coastguard Worker
343*387f9dfdSAndroid Build Coastguard Workerdef escape_character(c):
344*387f9dfdSAndroid Build Coastguard Worker    try:
345*387f9dfdSAndroid Build Coastguard Worker        return _escape_chars[c]
346*387f9dfdSAndroid Build Coastguard Worker    except KeyError:
347*387f9dfdSAndroid Build Coastguard Worker        if 0x20 <= c <= 0x7e:
348*387f9dfdSAndroid Build Coastguard Worker            return chr(c)
349*387f9dfdSAndroid Build Coastguard Worker        else:
350*387f9dfdSAndroid Build Coastguard Worker            return '\\x{:02x}'.format(c)
351*387f9dfdSAndroid Build Coastguard Worker
352*387f9dfdSAndroid Build Coastguard Worker
353*387f9dfdSAndroid Build Coastguard Workerif sys.version_info.major < 3:
354*387f9dfdSAndroid Build Coastguard Worker    def decode_mount_string(s):
355*387f9dfdSAndroid Build Coastguard Worker        return '"{}"'.format(''.join(escape_character(ord(c)) for c in s))
356*387f9dfdSAndroid Build Coastguard Workerelse:
357*387f9dfdSAndroid Build Coastguard Worker    def decode_mount_string(s):
358*387f9dfdSAndroid Build Coastguard Worker        return '"{}"'.format(''.join(escape_character(c) for c in s))
359*387f9dfdSAndroid Build Coastguard Worker
360*387f9dfdSAndroid Build Coastguard Worker
361*387f9dfdSAndroid Build Coastguard Workerdef print_event(mounts, umounts, parent, cpu, data, size):
362*387f9dfdSAndroid Build Coastguard Worker    event = ctypes.cast(data, ctypes.POINTER(Event)).contents
363*387f9dfdSAndroid Build Coastguard Worker
364*387f9dfdSAndroid Build Coastguard Worker    try:
365*387f9dfdSAndroid Build Coastguard Worker        if event.type == EventType.EVENT_MOUNT:
366*387f9dfdSAndroid Build Coastguard Worker            mounts[event.pid] = {
367*387f9dfdSAndroid Build Coastguard Worker                'pid': event.pid,
368*387f9dfdSAndroid Build Coastguard Worker                'tgid': event.tgid,
369*387f9dfdSAndroid Build Coastguard Worker                'mnt_ns': event.union.enter.mnt_ns,
370*387f9dfdSAndroid Build Coastguard Worker                'comm': event.union.enter.comm,
371*387f9dfdSAndroid Build Coastguard Worker                'flags': event.union.enter.flags,
372*387f9dfdSAndroid Build Coastguard Worker                'ppid': event.union.enter.ppid,
373*387f9dfdSAndroid Build Coastguard Worker                'pcomm': event.union.enter.pcomm,
374*387f9dfdSAndroid Build Coastguard Worker            }
375*387f9dfdSAndroid Build Coastguard Worker        elif event.type == EventType.EVENT_MOUNT_SOURCE:
376*387f9dfdSAndroid Build Coastguard Worker            mounts[event.pid]['source'] = event.union.str
377*387f9dfdSAndroid Build Coastguard Worker        elif event.type == EventType.EVENT_MOUNT_TARGET:
378*387f9dfdSAndroid Build Coastguard Worker            mounts[event.pid]['target'] = event.union.str
379*387f9dfdSAndroid Build Coastguard Worker        elif event.type == EventType.EVENT_MOUNT_TYPE:
380*387f9dfdSAndroid Build Coastguard Worker            mounts[event.pid]['type'] = event.union.str
381*387f9dfdSAndroid Build Coastguard Worker        elif event.type == EventType.EVENT_MOUNT_DATA:
382*387f9dfdSAndroid Build Coastguard Worker            # XXX: data is not always a NUL-terminated string
383*387f9dfdSAndroid Build Coastguard Worker            mounts[event.pid]['data'] = event.union.str
384*387f9dfdSAndroid Build Coastguard Worker        elif event.type == EventType.EVENT_UMOUNT:
385*387f9dfdSAndroid Build Coastguard Worker            umounts[event.pid] = {
386*387f9dfdSAndroid Build Coastguard Worker                'pid': event.pid,
387*387f9dfdSAndroid Build Coastguard Worker                'tgid': event.tgid,
388*387f9dfdSAndroid Build Coastguard Worker                'mnt_ns': event.union.enter.mnt_ns,
389*387f9dfdSAndroid Build Coastguard Worker                'comm': event.union.enter.comm,
390*387f9dfdSAndroid Build Coastguard Worker                'flags': event.union.enter.flags,
391*387f9dfdSAndroid Build Coastguard Worker                'ppid': event.union.enter.ppid,
392*387f9dfdSAndroid Build Coastguard Worker                'pcomm': event.union.enter.pcomm,
393*387f9dfdSAndroid Build Coastguard Worker            }
394*387f9dfdSAndroid Build Coastguard Worker        elif event.type == EventType.EVENT_UMOUNT_TARGET:
395*387f9dfdSAndroid Build Coastguard Worker            umounts[event.pid]['target'] = event.union.str
396*387f9dfdSAndroid Build Coastguard Worker        elif (event.type == EventType.EVENT_MOUNT_RET or
397*387f9dfdSAndroid Build Coastguard Worker              event.type == EventType.EVENT_UMOUNT_RET):
398*387f9dfdSAndroid Build Coastguard Worker            if event.type == EventType.EVENT_MOUNT_RET:
399*387f9dfdSAndroid Build Coastguard Worker                syscall = mounts.pop(event.pid)
400*387f9dfdSAndroid Build Coastguard Worker                call = ('mount({source}, {target}, {type}, {flags}, {data}) ' +
401*387f9dfdSAndroid Build Coastguard Worker                        '= {retval}').format(
402*387f9dfdSAndroid Build Coastguard Worker                    source=decode_mount_string(syscall['source']),
403*387f9dfdSAndroid Build Coastguard Worker                    target=decode_mount_string(syscall['target']),
404*387f9dfdSAndroid Build Coastguard Worker                    type=decode_mount_string(syscall['type']),
405*387f9dfdSAndroid Build Coastguard Worker                    flags=decode_mount_flags(syscall['flags']),
406*387f9dfdSAndroid Build Coastguard Worker                    data=decode_mount_string(syscall['data']),
407*387f9dfdSAndroid Build Coastguard Worker                    retval=decode_errno(event.union.retval))
408*387f9dfdSAndroid Build Coastguard Worker            else:
409*387f9dfdSAndroid Build Coastguard Worker                syscall = umounts.pop(event.pid)
410*387f9dfdSAndroid Build Coastguard Worker                call = 'umount({target}, {flags}) = {retval}'.format(
411*387f9dfdSAndroid Build Coastguard Worker                    target=decode_mount_string(syscall['target']),
412*387f9dfdSAndroid Build Coastguard Worker                    flags=decode_umount_flags(syscall['flags']),
413*387f9dfdSAndroid Build Coastguard Worker                    retval=decode_errno(event.union.retval))
414*387f9dfdSAndroid Build Coastguard Worker            if parent:
415*387f9dfdSAndroid Build Coastguard Worker                print('{:16} {:<7} {:<7} {:16} {:<7} {:<11} {}'.format(
416*387f9dfdSAndroid Build Coastguard Worker                    syscall['comm'].decode('utf-8', 'replace'), syscall['tgid'],
417*387f9dfdSAndroid Build Coastguard Worker                    syscall['pid'], syscall['pcomm'].decode('utf-8', 'replace'),
418*387f9dfdSAndroid Build Coastguard Worker                    syscall['ppid'], syscall['mnt_ns'], call))
419*387f9dfdSAndroid Build Coastguard Worker            else:
420*387f9dfdSAndroid Build Coastguard Worker                print('{:16} {:<7} {:<7} {:<11} {}'.format(
421*387f9dfdSAndroid Build Coastguard Worker                    syscall['comm'].decode('utf-8', 'replace'), syscall['tgid'],
422*387f9dfdSAndroid Build Coastguard Worker                    syscall['pid'], syscall['mnt_ns'], call))
423*387f9dfdSAndroid Build Coastguard Worker        sys.stdout.flush()
424*387f9dfdSAndroid Build Coastguard Worker    except KeyError:
425*387f9dfdSAndroid Build Coastguard Worker        # This might happen if we lost an event.
426*387f9dfdSAndroid Build Coastguard Worker        pass
427*387f9dfdSAndroid Build Coastguard Worker
428*387f9dfdSAndroid Build Coastguard Worker
429*387f9dfdSAndroid Build Coastguard Workerdef main():
430*387f9dfdSAndroid Build Coastguard Worker    parser = argparse.ArgumentParser(
431*387f9dfdSAndroid Build Coastguard Worker        description='trace mount() and umount() syscalls'
432*387f9dfdSAndroid Build Coastguard Worker    )
433*387f9dfdSAndroid Build Coastguard Worker    parser.add_argument("--ebpf", action="store_true",
434*387f9dfdSAndroid Build Coastguard Worker        help=argparse.SUPPRESS)
435*387f9dfdSAndroid Build Coastguard Worker    parser.add_argument("-P", "--parent_process", action="store_true",
436*387f9dfdSAndroid Build Coastguard Worker        help="also snoop the parent process")
437*387f9dfdSAndroid Build Coastguard Worker    parser.add_argument("--cgroupmap",
438*387f9dfdSAndroid Build Coastguard Worker        help="trace cgroups in this BPF map only")
439*387f9dfdSAndroid Build Coastguard Worker    parser.add_argument("--mntnsmap",
440*387f9dfdSAndroid Build Coastguard Worker        help="trace mount namespaces in this BPF map only")
441*387f9dfdSAndroid Build Coastguard Worker    args = parser.parse_args()
442*387f9dfdSAndroid Build Coastguard Worker
443*387f9dfdSAndroid Build Coastguard Worker    mounts = {}
444*387f9dfdSAndroid Build Coastguard Worker    umounts = {}
445*387f9dfdSAndroid Build Coastguard Worker    global bpf_text
446*387f9dfdSAndroid Build Coastguard Worker    bpf_text = filter_by_containers(args) + bpf_text
447*387f9dfdSAndroid Build Coastguard Worker    if args.ebpf:
448*387f9dfdSAndroid Build Coastguard Worker        print(bpf_text)
449*387f9dfdSAndroid Build Coastguard Worker        exit()
450*387f9dfdSAndroid Build Coastguard Worker    b = bcc.BPF(text=bpf_text)
451*387f9dfdSAndroid Build Coastguard Worker    mount_fnname = b.get_syscall_fnname("mount")
452*387f9dfdSAndroid Build Coastguard Worker    b.attach_kprobe(event=mount_fnname, fn_name="syscall__mount")
453*387f9dfdSAndroid Build Coastguard Worker    b.attach_kretprobe(event=mount_fnname, fn_name="do_ret_sys_mount")
454*387f9dfdSAndroid Build Coastguard Worker    umount_fnname = b.get_syscall_fnname("umount")
455*387f9dfdSAndroid Build Coastguard Worker    b.attach_kprobe(event=umount_fnname, fn_name="syscall__umount")
456*387f9dfdSAndroid Build Coastguard Worker    b.attach_kretprobe(event=umount_fnname, fn_name="do_ret_sys_umount")
457*387f9dfdSAndroid Build Coastguard Worker    b['events'].open_perf_buffer(
458*387f9dfdSAndroid Build Coastguard Worker        functools.partial(print_event, mounts, umounts, args.parent_process))
459*387f9dfdSAndroid Build Coastguard Worker
460*387f9dfdSAndroid Build Coastguard Worker    if args.parent_process:
461*387f9dfdSAndroid Build Coastguard Worker        print('{:16} {:<7} {:<7} {:16} {:<7} {:<11} {}'.format(
462*387f9dfdSAndroid Build Coastguard Worker              'COMM', 'PID', 'TID', 'PCOMM', 'PPID', 'MNT_NS', 'CALL'))
463*387f9dfdSAndroid Build Coastguard Worker    else:
464*387f9dfdSAndroid Build Coastguard Worker        print('{:16} {:<7} {:<7} {:<11} {}'.format(
465*387f9dfdSAndroid Build Coastguard Worker            'COMM', 'PID', 'TID', 'MNT_NS', 'CALL'))
466*387f9dfdSAndroid Build Coastguard Worker
467*387f9dfdSAndroid Build Coastguard Worker    while True:
468*387f9dfdSAndroid Build Coastguard Worker        try:
469*387f9dfdSAndroid Build Coastguard Worker            b.perf_buffer_poll()
470*387f9dfdSAndroid Build Coastguard Worker        except KeyboardInterrupt:
471*387f9dfdSAndroid Build Coastguard Worker            exit()
472*387f9dfdSAndroid Build Coastguard Worker
473*387f9dfdSAndroid Build Coastguard Worker
474*387f9dfdSAndroid Build Coastguard Worker
475*387f9dfdSAndroid Build Coastguard Workerif __name__ == '__main__':
476*387f9dfdSAndroid Build Coastguard Worker    main()
477