1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2020 Facebook */
3 #include <vmlinux.h>
4 #include <bpf/bpf_helpers.h>
5 #include <bpf/bpf_tracing.h>
6
7 char _license[] SEC("license") = "GPL";
8
9 uint32_t tid = 0;
10 int num_unknown_tid = 0;
11 int num_known_tid = 0;
12 void *user_ptr = 0;
13 void *user_ptr_long = 0;
14 uint32_t pid = 0;
15
16 static char big_str1[5000];
17 static char big_str2[5005];
18 static char big_str3[4996];
19
20 SEC("iter/task")
dump_task(struct bpf_iter__task * ctx)21 int dump_task(struct bpf_iter__task *ctx)
22 {
23 struct seq_file *seq = ctx->meta->seq;
24 struct task_struct *task = ctx->task;
25 static char info[] = " === END ===";
26
27 if (task == (void *)0) {
28 BPF_SEQ_PRINTF(seq, "%s\n", info);
29 return 0;
30 }
31
32 if (task->pid != (pid_t)tid)
33 num_unknown_tid++;
34 else
35 num_known_tid++;
36
37 if (ctx->meta->seq_num == 0)
38 BPF_SEQ_PRINTF(seq, " tgid gid\n");
39
40 BPF_SEQ_PRINTF(seq, "%8d %8d\n", task->tgid, task->pid);
41 return 0;
42 }
43
44 int num_expected_failure_copy_from_user_task = 0;
45 int num_expected_failure_copy_from_user_task_str = 0;
46 int num_success_copy_from_user_task = 0;
47 int num_success_copy_from_user_task_str = 0;
48
49 SEC("iter.s/task")
dump_task_sleepable(struct bpf_iter__task * ctx)50 int dump_task_sleepable(struct bpf_iter__task *ctx)
51 {
52 struct seq_file *seq = ctx->meta->seq;
53 struct task_struct *task = ctx->task;
54 static const char info[] = " === END ===";
55 struct pt_regs *regs;
56 char task_str1[10] = "aaaaaaaaaa";
57 char task_str2[10], task_str3[10];
58 char task_str4[20] = "aaaaaaaaaaaaaaaaaaaa";
59 void *ptr;
60 uint32_t user_data = 0;
61 int ret;
62
63 if (task == (void *)0) {
64 BPF_SEQ_PRINTF(seq, "%s\n", info);
65 return 0;
66 }
67
68 /* Read an invalid pointer and ensure we get an error */
69 ptr = NULL;
70 ret = bpf_copy_from_user_task(&user_data, sizeof(uint32_t), ptr, task, 0);
71 if (ret) {
72 ++num_expected_failure_copy_from_user_task;
73 } else {
74 BPF_SEQ_PRINTF(seq, "%s\n", info);
75 return 0;
76 }
77
78 /* Try to read the contents of the task's instruction pointer from the
79 * remote task's address space.
80 */
81 regs = (struct pt_regs *)bpf_task_pt_regs(task);
82 if (regs == (void *)0) {
83 BPF_SEQ_PRINTF(seq, "%s\n", info);
84 return 0;
85 }
86 ptr = (void *)PT_REGS_IP(regs);
87
88 ret = bpf_copy_from_user_task(&user_data, sizeof(uint32_t), ptr, task, 0);
89 if (ret) {
90 BPF_SEQ_PRINTF(seq, "%s\n", info);
91 return 0;
92 }
93
94 ++num_success_copy_from_user_task;
95
96 /* Read an invalid pointer and ensure we get an error */
97 ptr = NULL;
98 ret = bpf_copy_from_user_task_str((char *)task_str1, sizeof(task_str1), ptr, task, 0);
99 if (ret >= 0 || task_str1[9] != 'a' || task_str1[0] != '\0') {
100 BPF_SEQ_PRINTF(seq, "%s\n", info);
101 return 0;
102 }
103
104 /* Read an invalid pointer and ensure we get error with pad zeros flag */
105 ptr = NULL;
106 ret = bpf_copy_from_user_task_str((char *)task_str1, sizeof(task_str1),
107 ptr, task, BPF_F_PAD_ZEROS);
108 if (ret >= 0 || task_str1[9] != '\0' || task_str1[0] != '\0') {
109 BPF_SEQ_PRINTF(seq, "%s\n", info);
110 return 0;
111 }
112
113 ++num_expected_failure_copy_from_user_task_str;
114
115 /* Same length as the string */
116 ret = bpf_copy_from_user_task_str((char *)task_str2, 10, user_ptr, task, 0);
117 /* only need to do the task pid check once */
118 if (bpf_strncmp(task_str2, 10, "test_data\0") != 0 || ret != 10 || task->tgid != pid) {
119 BPF_SEQ_PRINTF(seq, "%s\n", info);
120 return 0;
121 }
122
123 /* Shorter length than the string */
124 ret = bpf_copy_from_user_task_str((char *)task_str3, 2, user_ptr, task, 0);
125 if (bpf_strncmp(task_str3, 2, "t\0") != 0 || ret != 2) {
126 BPF_SEQ_PRINTF(seq, "%s\n", info);
127 return 0;
128 }
129
130 /* Longer length than the string */
131 ret = bpf_copy_from_user_task_str((char *)task_str4, 20, user_ptr, task, 0);
132 if (bpf_strncmp(task_str4, 10, "test_data\0") != 0 || ret != 10
133 || task_str4[sizeof(task_str4) - 1] != 'a') {
134 BPF_SEQ_PRINTF(seq, "%s\n", info);
135 return 0;
136 }
137
138 /* Longer length than the string with pad zeros flag */
139 ret = bpf_copy_from_user_task_str((char *)task_str4, 20, user_ptr, task, BPF_F_PAD_ZEROS);
140 if (bpf_strncmp(task_str4, 10, "test_data\0") != 0 || ret != 10
141 || task_str4[sizeof(task_str4) - 1] != '\0') {
142 BPF_SEQ_PRINTF(seq, "%s\n", info);
143 return 0;
144 }
145
146 /* Longer length than the string past a page boundary */
147 ret = bpf_copy_from_user_task_str(big_str1, 5000, user_ptr, task, 0);
148 if (bpf_strncmp(big_str1, 10, "test_data\0") != 0 || ret != 10) {
149 BPF_SEQ_PRINTF(seq, "%s\n", info);
150 return 0;
151 }
152
153 /* String that crosses a page boundary */
154 ret = bpf_copy_from_user_task_str(big_str1, 5000, user_ptr_long, task, BPF_F_PAD_ZEROS);
155 if (bpf_strncmp(big_str1, 4, "baba") != 0 || ret != 5000
156 || bpf_strncmp(big_str1 + 4996, 4, "bab\0") != 0) {
157 BPF_SEQ_PRINTF(seq, "%s\n", info);
158 return 0;
159 }
160
161 for (int i = 0; i < 4999; ++i) {
162 if (i % 2 == 0) {
163 if (big_str1[i] != 'b') {
164 BPF_SEQ_PRINTF(seq, "%s\n", info);
165 return 0;
166 }
167 } else {
168 if (big_str1[i] != 'a') {
169 BPF_SEQ_PRINTF(seq, "%s\n", info);
170 return 0;
171 }
172 }
173 }
174
175 /* Longer length than the string that crosses a page boundary */
176 ret = bpf_copy_from_user_task_str(big_str2, 5005, user_ptr_long, task, BPF_F_PAD_ZEROS);
177 if (bpf_strncmp(big_str2, 4, "baba") != 0 || ret != 5000
178 || bpf_strncmp(big_str2 + 4996, 5, "bab\0\0") != 0) {
179 BPF_SEQ_PRINTF(seq, "%s\n", info);
180 return 0;
181 }
182
183 /* Shorter length than the string that crosses a page boundary */
184 ret = bpf_copy_from_user_task_str(big_str3, 4996, user_ptr_long, task, 0);
185 if (bpf_strncmp(big_str3, 4, "baba") != 0 || ret != 4996
186 || bpf_strncmp(big_str3 + 4992, 4, "bab\0") != 0) {
187 BPF_SEQ_PRINTF(seq, "%s\n", info);
188 return 0;
189 }
190
191 ++num_success_copy_from_user_task_str;
192
193 if (ctx->meta->seq_num == 0)
194 BPF_SEQ_PRINTF(seq, " tgid gid data\n");
195
196 BPF_SEQ_PRINTF(seq, "%8d %8d %8d\n", task->tgid, task->pid, user_data);
197 return 0;
198 }
199