Skip to content

Commit ffeedaf

Browse files
Alexei Starovoitovdavem330
Alexei Starovoitov
authored andcommitted
bpf: introduce current->pid, tgid, uid, gid, comm accessors
eBPF programs attached to kprobes need to filter based on current->pid, uid and other fields, so introduce helper functions: u64 bpf_get_current_pid_tgid(void) Return: current->tgid << 32 | current->pid u64 bpf_get_current_uid_gid(void) Return: current_gid << 32 | current_uid bpf_get_current_comm(char *buf, int size_of_buf) stores current->comm into buf They can be used from the programs attached to TC as well to classify packets based on current task fields. Update tracex2 example to print histogram of write syscalls for each process instead of aggregated for all. Signed-off-by: Alexei Starovoitov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent ada6c1d commit ffeedaf

File tree

9 files changed

+178
-14
lines changed

9 files changed

+178
-14
lines changed

Diff for: include/linux/bpf.h

+3
Original file line numberDiff line numberDiff line change
@@ -188,5 +188,8 @@ extern const struct bpf_func_proto bpf_get_prandom_u32_proto;
188188
extern const struct bpf_func_proto bpf_get_smp_processor_id_proto;
189189
extern const struct bpf_func_proto bpf_tail_call_proto;
190190
extern const struct bpf_func_proto bpf_ktime_get_ns_proto;
191+
extern const struct bpf_func_proto bpf_get_current_pid_tgid_proto;
192+
extern const struct bpf_func_proto bpf_get_current_uid_gid_proto;
193+
extern const struct bpf_func_proto bpf_get_current_comm_proto;
191194

192195
#endif /* _LINUX_BPF_H */

Diff for: include/uapi/linux/bpf.h

+19
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,25 @@ enum bpf_func_id {
230230
* Return: 0 on success
231231
*/
232232
BPF_FUNC_clone_redirect,
233+
234+
/**
235+
* u64 bpf_get_current_pid_tgid(void)
236+
* Return: current->tgid << 32 | current->pid
237+
*/
238+
BPF_FUNC_get_current_pid_tgid,
239+
240+
/**
241+
* u64 bpf_get_current_uid_gid(void)
242+
* Return: current_gid << 32 | current_uid
243+
*/
244+
BPF_FUNC_get_current_uid_gid,
245+
246+
/**
247+
* bpf_get_current_comm(char *buf, int size_of_buf)
248+
* stores current->comm into buf
249+
* Return: 0 on success
250+
*/
251+
BPF_FUNC_get_current_comm,
233252
__BPF_FUNC_MAX_ID,
234253
};
235254

Diff for: kernel/bpf/core.c

+3
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,9 @@ const struct bpf_func_proto bpf_map_delete_elem_proto __weak;
730730
const struct bpf_func_proto bpf_get_prandom_u32_proto __weak;
731731
const struct bpf_func_proto bpf_get_smp_processor_id_proto __weak;
732732
const struct bpf_func_proto bpf_ktime_get_ns_proto __weak;
733+
const struct bpf_func_proto bpf_get_current_pid_tgid_proto __weak;
734+
const struct bpf_func_proto bpf_get_current_uid_gid_proto __weak;
735+
const struct bpf_func_proto bpf_get_current_comm_proto __weak;
733736

734737
/* Always built-in helper functions. */
735738
const struct bpf_func_proto bpf_tail_call_proto = {

Diff for: kernel/bpf/helpers.c

+58
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#include <linux/random.h>
1515
#include <linux/smp.h>
1616
#include <linux/ktime.h>
17+
#include <linux/sched.h>
18+
#include <linux/uidgid.h>
1719

1820
/* If kernel subsystem is allowing eBPF programs to call this function,
1921
* inside its own verifier_ops->get_func_proto() callback it should return
@@ -124,3 +126,59 @@ const struct bpf_func_proto bpf_ktime_get_ns_proto = {
124126
.gpl_only = true,
125127
.ret_type = RET_INTEGER,
126128
};
129+
130+
static u64 bpf_get_current_pid_tgid(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
131+
{
132+
struct task_struct *task = current;
133+
134+
if (!task)
135+
return -EINVAL;
136+
137+
return (u64) task->tgid << 32 | task->pid;
138+
}
139+
140+
const struct bpf_func_proto bpf_get_current_pid_tgid_proto = {
141+
.func = bpf_get_current_pid_tgid,
142+
.gpl_only = false,
143+
.ret_type = RET_INTEGER,
144+
};
145+
146+
static u64 bpf_get_current_uid_gid(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
147+
{
148+
struct task_struct *task = current;
149+
kuid_t uid;
150+
kgid_t gid;
151+
152+
if (!task)
153+
return -EINVAL;
154+
155+
current_uid_gid(&uid, &gid);
156+
return (u64) from_kgid(&init_user_ns, gid) << 32 |
157+
from_kuid(&init_user_ns, uid);
158+
}
159+
160+
const struct bpf_func_proto bpf_get_current_uid_gid_proto = {
161+
.func = bpf_get_current_uid_gid,
162+
.gpl_only = false,
163+
.ret_type = RET_INTEGER,
164+
};
165+
166+
static u64 bpf_get_current_comm(u64 r1, u64 size, u64 r3, u64 r4, u64 r5)
167+
{
168+
struct task_struct *task = current;
169+
char *buf = (char *) (long) r1;
170+
171+
if (!task)
172+
return -EINVAL;
173+
174+
memcpy(buf, task->comm, min_t(size_t, size, sizeof(task->comm)));
175+
return 0;
176+
}
177+
178+
const struct bpf_func_proto bpf_get_current_comm_proto = {
179+
.func = bpf_get_current_comm,
180+
.gpl_only = false,
181+
.ret_type = RET_INTEGER,
182+
.arg1_type = ARG_PTR_TO_STACK,
183+
.arg2_type = ARG_CONST_STACK_SIZE,
184+
};

Diff for: kernel/trace/bpf_trace.c

+6
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,12 @@ static const struct bpf_func_proto *kprobe_prog_func_proto(enum bpf_func_id func
162162
return &bpf_ktime_get_ns_proto;
163163
case BPF_FUNC_tail_call:
164164
return &bpf_tail_call_proto;
165+
case BPF_FUNC_get_current_pid_tgid:
166+
return &bpf_get_current_pid_tgid_proto;
167+
case BPF_FUNC_get_current_uid_gid:
168+
return &bpf_get_current_uid_gid_proto;
169+
case BPF_FUNC_get_current_comm:
170+
return &bpf_get_current_comm_proto;
165171

166172
case BPF_FUNC_trace_printk:
167173
/*

Diff for: net/core/filter.c

+6
Original file line numberDiff line numberDiff line change
@@ -1459,6 +1459,12 @@ tc_cls_act_func_proto(enum bpf_func_id func_id)
14591459
return &bpf_l4_csum_replace_proto;
14601460
case BPF_FUNC_clone_redirect:
14611461
return &bpf_clone_redirect_proto;
1462+
case BPF_FUNC_get_current_pid_tgid:
1463+
return &bpf_get_current_pid_tgid_proto;
1464+
case BPF_FUNC_get_current_uid_gid:
1465+
return &bpf_get_current_uid_gid_proto;
1466+
case BPF_FUNC_get_current_comm:
1467+
return &bpf_get_current_comm_proto;
14621468
default:
14631469
return sk_filter_func_proto(func_id);
14641470
}

Diff for: samples/bpf/bpf_helpers.h

+6
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ static void (*bpf_tail_call)(void *ctx, void *map, int index) =
2525
(void *) BPF_FUNC_tail_call;
2626
static unsigned long long (*bpf_get_smp_processor_id)(void) =
2727
(void *) BPF_FUNC_get_smp_processor_id;
28+
static unsigned long long (*bpf_get_current_pid_tgid)(void) =
29+
(void *) BPF_FUNC_get_current_pid_tgid;
30+
static unsigned long long (*bpf_get_current_uid_gid)(void) =
31+
(void *) BPF_FUNC_get_current_uid_gid;
32+
static int (*bpf_get_current_comm)(void *buf, int buf_size) =
33+
(void *) BPF_FUNC_get_current_comm;
2834

2935
/* llvm builtin functions that eBPF C program may use to
3036
* emit BPF_LD_ABS and BPF_LD_IND instructions

Diff for: samples/bpf/tracex2_kern.c

+19-5
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,18 @@ static unsigned int log2l(unsigned long v)
6262
return log2(v);
6363
}
6464

65+
struct hist_key {
66+
char comm[16];
67+
u64 pid_tgid;
68+
u64 uid_gid;
69+
u32 index;
70+
};
71+
6572
struct bpf_map_def SEC("maps") my_hist_map = {
66-
.type = BPF_MAP_TYPE_ARRAY,
67-
.key_size = sizeof(u32),
73+
.type = BPF_MAP_TYPE_HASH,
74+
.key_size = sizeof(struct hist_key),
6875
.value_size = sizeof(long),
69-
.max_entries = 64,
76+
.max_entries = 1024,
7077
};
7178

7279
SEC("kprobe/sys_write")
@@ -75,11 +82,18 @@ int bpf_prog3(struct pt_regs *ctx)
7582
long write_size = ctx->dx; /* arg3 */
7683
long init_val = 1;
7784
long *value;
78-
u32 index = log2l(write_size);
85+
struct hist_key key = {};
86+
87+
key.index = log2l(write_size);
88+
key.pid_tgid = bpf_get_current_pid_tgid();
89+
key.uid_gid = bpf_get_current_uid_gid();
90+
bpf_get_current_comm(&key.comm, sizeof(key.comm));
7991

80-
value = bpf_map_lookup_elem(&my_hist_map, &index);
92+
value = bpf_map_lookup_elem(&my_hist_map, &key);
8193
if (value)
8294
__sync_fetch_and_add(value, 1);
95+
else
96+
bpf_map_update_elem(&my_hist_map, &key, &init_val, BPF_ANY);
8397
return 0;
8498
}
8599
char _license[] SEC("license") = "GPL";

Diff for: samples/bpf/tracex2_user.c

+58-9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <stdlib.h>
44
#include <signal.h>
55
#include <linux/bpf.h>
6+
#include <string.h>
67
#include "libbpf.h"
78
#include "bpf_load.h"
89

@@ -20,23 +21,42 @@ static void stars(char *str, long val, long max, int width)
2021
str[i] = '\0';
2122
}
2223

23-
static void print_hist(int fd)
24+
struct task {
25+
char comm[16];
26+
__u64 pid_tgid;
27+
__u64 uid_gid;
28+
};
29+
30+
struct hist_key {
31+
struct task t;
32+
__u32 index;
33+
};
34+
35+
#define SIZE sizeof(struct task)
36+
37+
static void print_hist_for_pid(int fd, void *task)
2438
{
25-
int key;
39+
struct hist_key key = {}, next_key;
40+
char starstr[MAX_STARS];
2641
long value;
2742
long data[MAX_INDEX] = {};
28-
char starstr[MAX_STARS];
29-
int i;
3043
int max_ind = -1;
3144
long max_value = 0;
45+
int i, ind;
3246

33-
for (key = 0; key < MAX_INDEX; key++) {
34-
bpf_lookup_elem(fd, &key, &value);
35-
data[key] = value;
36-
if (value && key > max_ind)
37-
max_ind = key;
47+
while (bpf_get_next_key(fd, &key, &next_key) == 0) {
48+
if (memcmp(&next_key, task, SIZE)) {
49+
key = next_key;
50+
continue;
51+
}
52+
bpf_lookup_elem(fd, &next_key, &value);
53+
ind = next_key.index;
54+
data[ind] = value;
55+
if (value && ind > max_ind)
56+
max_ind = ind;
3857
if (value > max_value)
3958
max_value = value;
59+
key = next_key;
4060
}
4161

4262
printf(" syscall write() stats\n");
@@ -48,6 +68,35 @@ static void print_hist(int fd)
4868
MAX_STARS, starstr);
4969
}
5070
}
71+
72+
static void print_hist(int fd)
73+
{
74+
struct hist_key key = {}, next_key;
75+
static struct task tasks[1024];
76+
int task_cnt = 0;
77+
int i;
78+
79+
while (bpf_get_next_key(fd, &key, &next_key) == 0) {
80+
int found = 0;
81+
82+
for (i = 0; i < task_cnt; i++)
83+
if (memcmp(&tasks[i], &next_key, SIZE) == 0)
84+
found = 1;
85+
if (!found)
86+
memcpy(&tasks[task_cnt++], &next_key, SIZE);
87+
key = next_key;
88+
}
89+
90+
for (i = 0; i < task_cnt; i++) {
91+
printf("\npid %d cmd %s uid %d\n",
92+
(__u32) tasks[i].pid_tgid,
93+
tasks[i].comm,
94+
(__u32) tasks[i].uid_gid);
95+
print_hist_for_pid(fd, &tasks[i]);
96+
}
97+
98+
}
99+
51100
static void int_exit(int sig)
52101
{
53102
print_hist(map_fd[1]);

0 commit comments

Comments
 (0)