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") 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") 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