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