Skip to content

Commit

Permalink
tools/opensnoop: Display mode for -e, --extended_fields
Browse files Browse the repository at this point in the history
When a program creates a file with mode=0000, it cannot even access the file
itself. It would be helpful if we could track the mode value. so we can know
who did it.

Example:

    open("a.txt", O_WRONLY | O_EXCL | O_CREAT, 0000);

Then:

    $ ls -l a.txt
    ----------. 1 rongtao rongtao 0 Jan 24 09:07 a.txt
    $ cat a.txt
    cat: a.txt: Permission denied

    $ sudo ./opensnoop.py -e
    PID    COMM               FD ERR FLAGS    MODE PATH
    673067 open                3   0 00000301 n/a  a.txt
                                              ^^^^

If flags is an illegal value, displaying the mode value can better handle the
relationship between flags and mode. After all, mode is only effective when
flags only contains O_TMPFILE or O_CREAT.

Signed-off-by: Rong Tao <rongtao@cestc.cn>
  • Loading branch information
Rtoax committed Jan 31, 2025
1 parent 0dc4282 commit d2077fd
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 27 deletions.
55 changes: 49 additions & 6 deletions tools/opensnoop.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
bpf_text = """
#include <uapi/linux/ptrace.h>
#include <uapi/linux/limits.h>
#include <linux/fcntl.h>
#include <linux/sched.h>
#ifdef FULLPATH
#include <linux/fs_struct.h>
Expand All @@ -117,6 +118,7 @@
char comm[TASK_COMM_LEN];
const char *fname;
int flags; // EXTENDED_STRUCT_MEMBER
u32 mode; // EXTENDED_STRUCT_MEMBER
};
struct data_t {
Expand All @@ -130,6 +132,7 @@
#endif
char name[NAME_MAX];
int flags; // EXTENDED_STRUCT_MEMBER
u32 mode; // EXTENDED_STRUCT_MEMBER
};
BPF_PERF_OUTPUT(events);
Expand Down Expand Up @@ -158,6 +161,7 @@
data.ts = tsp / 1000;
data.uid = bpf_get_current_uid_gid();
data.flags = valp->flags; // EXTENDED_STRUCT_MEMBER
data.mode = valp->mode; // EXTENDED_STRUCT_MEMBER
data.ret = PT_REGS_RC(ctx);
SUBMIT_DATA
Expand All @@ -169,12 +173,15 @@
"""

bpf_text_kprobe_header_open = """
int syscall__trace_entry_open(struct pt_regs *ctx, const char __user *filename, int flags)
int syscall__trace_entry_open(struct pt_regs *ctx, const char __user *filename,
int flags, u32 mode)
{
"""

bpf_text_kprobe_header_openat = """
int syscall__trace_entry_openat(struct pt_regs *ctx, int dfd, const char __user *filename, int flags)
int syscall__trace_entry_openat(struct pt_regs *ctx, int dfd,
const char __user *filename, int flags,
u32 mode)
{
"""

Expand All @@ -183,6 +190,10 @@
int syscall__trace_entry_openat2(struct pt_regs *ctx, int dfd, const char __user *filename, struct open_how *how)
{
int flags = how->flags;
u32 mode = 0;
if (flags & (O_CREAT | O_TMPFILE))
mode = how->mode;
"""

bpf_text_kprobe_body = """
Expand All @@ -204,6 +215,7 @@
val.id = id;
val.fname = filename;
val.flags = flags; // EXTENDED_STRUCT_MEMBER
val.mode = mode; // EXTENDED_STRUCT_MEMBER
infotmp.update(&id, &val);
}
Expand All @@ -217,8 +229,20 @@
{
const char __user *filename = (char *)PT_REGS_PARM1(regs);
int flags = PT_REGS_PARM2(regs);
u32 mode = 0;
/**
* open(2): The mode argument must be supplied if O_CREAT or O_TMPFILE is
* specified in flags; if it is not supplied, some arbitrary bytes from
* the stack will be applied as the file mode.
*
* Other O_CREAT | O_TMPFILE checks about flags are also for this reason.
*/
if (flags & (O_CREAT | O_TMPFILE))
mode = PT_REGS_PARM3(regs);
#else
KRETFUNC_PROBE(FNNAME, const char __user *filename, int flags, int ret)
KRETFUNC_PROBE(FNNAME, const char __user *filename, int flags,
u32 mode, int ret)
{
#endif
"""
Expand All @@ -230,8 +254,13 @@
int dfd = PT_REGS_PARM1(regs);
const char __user *filename = (char *)PT_REGS_PARM2(regs);
int flags = PT_REGS_PARM3(regs);
u32 mode = 0;
if (flags & (O_CREAT | O_TMPFILE))
mode = PT_REGS_PARM4(regs);
#else
KRETFUNC_PROBE(FNNAME, int dfd, const char __user *filename, int flags, int ret)
KRETFUNC_PROBE(FNNAME, int dfd, const char __user *filename, int flags,
u32 mode, int ret)
{
#endif
"""
Expand All @@ -245,13 +274,21 @@
const char __user *filename = (char *)PT_REGS_PARM2(regs);
struct open_how __user how;
int flags;
u32 mode = 0;
bpf_probe_read_user(&how, sizeof(struct open_how), (struct open_how*)PT_REGS_PARM3(regs));
flags = how.flags;
if (flags & (O_CREAT | O_TMPFILE))
mode = how.mode;
#else
KRETFUNC_PROBE(FNNAME, int dfd, const char __user *filename, struct open_how __user *how, int ret)
{
int flags = how->flags;
u32 mode = 0;
if (flags & (O_CREAT | O_TMPFILE))
mode = how->mode;
#endif
"""

Expand All @@ -278,6 +315,7 @@
data.ts = tsp / 1000;
data.uid = bpf_get_current_uid_gid();
data.flags = flags; // EXTENDED_STRUCT_MEMBER
data.mode = mode; // EXTENDED_STRUCT_MEMBER
data.ret = ret;
SUBMIT_DATA
Expand Down Expand Up @@ -406,7 +444,7 @@
print("%-6s %-16s %4s %3s " %
("TID" if args.tid else "PID", "COMM", "FD", "ERR"), end="")
if args.extended_fields:
print("%-9s" % ("FLAGS"), end="")
print("%-8s %-4s " % ("FLAGS", "MODE"), end="")
print("PATH")

class EventType(object):
Expand Down Expand Up @@ -453,7 +491,12 @@ def print_event(cpu, data, size):
event.comm, fd_s, err), nl="")

if args.extended_fields:
printb(b"%08o " % event.flags, nl="")
# If neither O_CREAT nor O_TMPFILE is specified in flags, then
# mode is ignored, see open(2).
if event.mode == 0 and event.flags & (os.O_CREAT | os.O_TMPFILE) == 0:
printb(b"%08o n/a " % event.flags, nl="")
else:
printb(b"%08o %04o " % (event.flags, event.mode), nl="")

if not args.full_path:
printb(b"%s" % event.name)
Expand Down
39 changes: 18 additions & 21 deletions tools/opensnoop_example.txt
Original file line number Diff line number Diff line change
Expand Up @@ -156,30 +156,27 @@ to the '-n' option.
The -e option prints out extra columns; for example, the following output
contains the flags passed to open(2), in octal:

# ./opensnoop -e
PID COMM FD ERR FLAGS PATH
28512 sshd 10 0 00101101 /proc/self/oom_score_adj
28512 sshd 3 0 02100000 /etc/ld.so.cache
28512 sshd 3 0 02100000 /lib/x86_64-linux-gnu/libwrap.so.0
28512 sshd 3 0 02100000 /lib/x86_64-linux-gnu/libaudit.so.1
28512 sshd 3 0 02100000 /lib/x86_64-linux-gnu/libpam.so.0
28512 sshd 3 0 02100000 /lib/x86_64-linux-gnu/libselinux.so.1
28512 sshd 3 0 02100000 /lib/x86_64-linux-gnu/libsystemd.so.0
28512 sshd 3 0 02100000 /usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.2
28512 sshd 3 0 02100000 /lib/x86_64-linux-gnu/libutil.so.1

# ./opensnoop.py -e
PID COMM FD ERR FLAGS MODE PATH
12458 open 3 0 02000000 n/a /etc/ld.so.cache
12458 open 3 0 02000000 n/a /lib/x86_64-linux-gnu/libc.so.6
12458 open 3 0 00000301 0664 tmp.txt
12459 openat 3 0 02000000 n/a /etc/ld.so.cache
12459 openat 3 0 02000000 n/a /lib/x86_64-linux-gnu/libc.so.6
12459 openat 3 0 00000301 0664 tmp.txt
12460 openat2 3 0 02000000 n/a /etc/ld.so.cache
12460 openat2 3 0 02000000 n/a /lib/x86_64-linux-gnu/libc.so.6
12460 openat2 3 0 00000000 n/a .
12460 openat2 3 0 00000000 n/a .
12460 openat2 4 0 00000000 n/a ..

The -f option filters based on flags to the open(2) call, for example:

# ./opensnoop -e -f O_WRONLY -f O_RDWR
PID COMM FD ERR FLAGS PATH
28084 clear_console 3 0 00100002 /dev/tty
28084 clear_console -1 13 00100002 /dev/tty0
28084 clear_console -1 13 00100001 /dev/tty0
28084 clear_console -1 13 00100002 /dev/console
28084 clear_console -1 13 00100001 /dev/console
28051 sshd 8 0 02100002 /var/run/utmp
28051 sshd 7 0 00100001 /var/log/wtmp
# ./opensnoop.py -e -f O_WRONLY -f O_RDWR
PID COMM FD ERR FLAGS MODE PATH
12540 open 3 0 00000301 0664 tmp.txt
12541 openat 3 0 00000301 0664 tmp.txt
9039 openat 3 0 00000301 0000 tmp.txt


The --cgroupmap option filters based on a cgroup set. It is meant to be used
Expand Down

0 comments on commit d2077fd

Please sign in to comment.