如何从内核 space 中确定 PID 属于哪个名称space?
How can I determine which namespaces a PID is in from kernel space?
我正在尝试编写一个 eBPF 程序来记录来自系统上容器 运行 的特定系统调用的每次调用。我正在使用 bcc 并且可以使用 bpf_get_current_pid_tgid()
检索 PID。
来自用户space 我可以检查 proc 文件系统以确定进程的名称spaces 是否与根名称spaces 不同来猜测它是否是容器进程, 但我不知道你如何从内核 space?
您可以使用(Linux 4.8+ only)bpf_get_current_task
助手来检索当前进程的 struct task_struct
。然后容器内进程看到的 PID 在 t->nsproxy->pid_ns_for_children->last_pid
.
中
以下显示了跟踪 execve
系统调用时的实际操作(您可以在容器内使用 top
来检查 upid 是否正确):
from bcc import BPF
BPF(text="""
#include <linux/pid_namespace.h>
int kprobe__sys_execve(void *ctx) {
u32 pid = bpf_get_current_pid_tgid();
struct task_struct *t = (struct task_struct *)bpf_get_current_task();
u32 upid = t->nsproxy->pid_ns_for_children->last_pid;
bpf_trace_printk("pid=%d; upid=%d!\n", pid, upid);
return 0;
}
""").trace_print()
以下差异(基于 a44d26ed3)扩展 bcc 的 execsnoop.py
以检索 upid:
diff --git a/tools/execsnoop.py b/tools/execsnoop.py
index 5711fd1..2134f69 100755
--- a/tools/execsnoop.py
+++ b/tools/execsnoop.py
@@ -53,6 +53,7 @@ bpf_text = """
#include <uapi/linux/ptrace.h>
#include <linux/sched.h>
#include <linux/fs.h>
+#include <linux/pid_namespace.h>
#define ARGSIZE 128
@@ -63,6 +64,7 @@ enum event_type {
struct data_t {
u32 pid; // PID as in the userspace term (i.e. task->tgid in kernel)
+ u32 upid;
char comm[TASK_COMM_LEN];
enum event_type type;
char argv[ARGSIZE];
@@ -119,6 +121,8 @@ int kretprobe__sys_execve(struct pt_regs *ctx)
{
struct data_t data = {};
data.pid = bpf_get_current_pid_tgid() >> 32;
+ struct task_struct *t = (struct task_struct *)bpf_get_current_task();
+ data.upid = t->nsproxy->pid_ns_for_children->last_pid;
bpf_get_current_comm(&data.comm, sizeof(data.comm));
data.type = EVENT_RET;
data.retval = PT_REGS_RC(ctx);
@@ -134,7 +138,7 @@ b = BPF(text=bpf_text.replace("MAXARG", args.max_args))
# header
if args.timestamp:
print("%-8s" % ("TIME(s)"), end="")
-print("%-16s %-6s %-6s %3s %s" % ("PCOMM", "PID", "PPID", "RET", "ARGS"))
+print("%-16s %-6s %-6s %-6s %3s %s" % ("PCOMM", "PID", "UPID", "PPID", "RET", "ARGS"))
TASK_COMM_LEN = 16 # linux/sched.h
ARGSIZE = 128 # should match #define in C above
@@ -142,6 +146,7 @@ ARGSIZE = 128 # should match #define in C above
class Data(ct.Structure):
_fields_ = [
("pid", ct.c_uint),
+ ("upid", ct.c_uint),
("comm", ct.c_char * TASK_COMM_LEN),
("type", ct.c_int),
("argv", ct.c_char * ARGSIZE),
@@ -189,8 +194,8 @@ def print_event(cpu, data, size):
if args.timestamp:
print("%-8.3f" % (time.time() - start_ts), end="")
ppid = get_ppid(event.pid)
- print("%-16s %-6s %-6s %3s %s" % (event.comm.decode(), event.pid,
- ppid if ppid > 0 else "?", event.retval,
+ print("%-16s %-6s %-6s %-6s %3s %s" % (event.comm.decode(), event.pid,
+ event.upid, ppid if ppid > 0 else "?", event.retval,
b' '.join(argv[event.pid]).decode()))
try:
del(argv[event.pid])
我正在尝试编写一个 eBPF 程序来记录来自系统上容器 运行 的特定系统调用的每次调用。我正在使用 bcc 并且可以使用 bpf_get_current_pid_tgid()
检索 PID。
来自用户space 我可以检查 proc 文件系统以确定进程的名称spaces 是否与根名称spaces 不同来猜测它是否是容器进程, 但我不知道你如何从内核 space?
您可以使用(Linux 4.8+ only)bpf_get_current_task
助手来检索当前进程的 struct task_struct
。然后容器内进程看到的 PID 在 t->nsproxy->pid_ns_for_children->last_pid
.
以下显示了跟踪 execve
系统调用时的实际操作(您可以在容器内使用 top
来检查 upid 是否正确):
from bcc import BPF
BPF(text="""
#include <linux/pid_namespace.h>
int kprobe__sys_execve(void *ctx) {
u32 pid = bpf_get_current_pid_tgid();
struct task_struct *t = (struct task_struct *)bpf_get_current_task();
u32 upid = t->nsproxy->pid_ns_for_children->last_pid;
bpf_trace_printk("pid=%d; upid=%d!\n", pid, upid);
return 0;
}
""").trace_print()
以下差异(基于 a44d26ed3)扩展 bcc 的 execsnoop.py
以检索 upid:
diff --git a/tools/execsnoop.py b/tools/execsnoop.py
index 5711fd1..2134f69 100755
--- a/tools/execsnoop.py
+++ b/tools/execsnoop.py
@@ -53,6 +53,7 @@ bpf_text = """
#include <uapi/linux/ptrace.h>
#include <linux/sched.h>
#include <linux/fs.h>
+#include <linux/pid_namespace.h>
#define ARGSIZE 128
@@ -63,6 +64,7 @@ enum event_type {
struct data_t {
u32 pid; // PID as in the userspace term (i.e. task->tgid in kernel)
+ u32 upid;
char comm[TASK_COMM_LEN];
enum event_type type;
char argv[ARGSIZE];
@@ -119,6 +121,8 @@ int kretprobe__sys_execve(struct pt_regs *ctx)
{
struct data_t data = {};
data.pid = bpf_get_current_pid_tgid() >> 32;
+ struct task_struct *t = (struct task_struct *)bpf_get_current_task();
+ data.upid = t->nsproxy->pid_ns_for_children->last_pid;
bpf_get_current_comm(&data.comm, sizeof(data.comm));
data.type = EVENT_RET;
data.retval = PT_REGS_RC(ctx);
@@ -134,7 +138,7 @@ b = BPF(text=bpf_text.replace("MAXARG", args.max_args))
# header
if args.timestamp:
print("%-8s" % ("TIME(s)"), end="")
-print("%-16s %-6s %-6s %3s %s" % ("PCOMM", "PID", "PPID", "RET", "ARGS"))
+print("%-16s %-6s %-6s %-6s %3s %s" % ("PCOMM", "PID", "UPID", "PPID", "RET", "ARGS"))
TASK_COMM_LEN = 16 # linux/sched.h
ARGSIZE = 128 # should match #define in C above
@@ -142,6 +146,7 @@ ARGSIZE = 128 # should match #define in C above
class Data(ct.Structure):
_fields_ = [
("pid", ct.c_uint),
+ ("upid", ct.c_uint),
("comm", ct.c_char * TASK_COMM_LEN),
("type", ct.c_int),
("argv", ct.c_char * ARGSIZE),
@@ -189,8 +194,8 @@ def print_event(cpu, data, size):
if args.timestamp:
print("%-8.3f" % (time.time() - start_ts), end="")
ppid = get_ppid(event.pid)
- print("%-16s %-6s %-6s %3s %s" % (event.comm.decode(), event.pid,
- ppid if ppid > 0 else "?", event.retval,
+ print("%-16s %-6s %-6s %-6s %3s %s" % (event.comm.decode(), event.pid,
+ event.upid, ppid if ppid > 0 else "?", event.retval,
b' '.join(argv[event.pid]).decode()))
try:
del(argv[event.pid])