1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright (c) 2020 Facebook */ 3 4 #include <linux/init.h> 5 #include <linux/namei.h> 6 #include <linux/pid_namespace.h> 7 #include <linux/fs.h> 8 #include <linux/fdtable.h> 9 #include <linux/filter.h> 10 11 struct bpf_iter_seq_task_common { 12 struct pid_namespace *ns; 13 }; 14 15 struct bpf_iter_seq_task_info { 16 /* The first field must be struct bpf_iter_seq_task_common. 17 * this is assumed by {init, fini}_seq_pidns() callback functions. 18 */ 19 struct bpf_iter_seq_task_common common; 20 u32 tid; 21 }; 22 23 static struct task_struct *task_seq_get_next(struct pid_namespace *ns, 24 u32 *tid) 25 { 26 struct task_struct *task = NULL; 27 struct pid *pid; 28 29 rcu_read_lock(); 30 retry: 31 pid = idr_get_next(&ns->idr, tid); 32 if (pid) { 33 task = get_pid_task(pid, PIDTYPE_PID); 34 if (!task) { 35 ++*tid; 36 goto retry; 37 } 38 } 39 rcu_read_unlock(); 40 41 return task; 42 } 43 44 static void *task_seq_start(struct seq_file *seq, loff_t *pos) 45 { 46 struct bpf_iter_seq_task_info *info = seq->private; 47 struct task_struct *task; 48 49 task = task_seq_get_next(info->common.ns, &info->tid); 50 if (!task) 51 return NULL; 52 53 ++*pos; 54 return task; 55 } 56 57 static void *task_seq_next(struct seq_file *seq, void *v, loff_t *pos) 58 { 59 struct bpf_iter_seq_task_info *info = seq->private; 60 struct task_struct *task; 61 62 ++*pos; 63 ++info->tid; 64 put_task_struct((struct task_struct *)v); 65 task = task_seq_get_next(info->common.ns, &info->tid); 66 if (!task) 67 return NULL; 68 69 return task; 70 } 71 72 struct bpf_iter__task { 73 __bpf_md_ptr(struct bpf_iter_meta *, meta); 74 __bpf_md_ptr(struct task_struct *, task); 75 }; 76 77 DEFINE_BPF_ITER_FUNC(task, struct bpf_iter_meta *meta, struct task_struct *task) 78 79 static int __task_seq_show(struct seq_file *seq, struct task_struct *task, 80 bool in_stop) 81 { 82 struct bpf_iter_meta meta; 83 struct bpf_iter__task ctx; 84 struct bpf_prog *prog; 85 86 meta.seq = seq; 87 prog = bpf_iter_get_info(&meta, in_stop); 88 if (!prog) 89 return 0; 90 91 meta.seq = seq; 92 ctx.meta = &meta; 93 ctx.task = task; 94 return bpf_iter_run_prog(prog, &ctx); 95 } 96 97 static int task_seq_show(struct seq_file *seq, void *v) 98 { 99 return __task_seq_show(seq, v, false); 100 } 101 102 static void task_seq_stop(struct seq_file *seq, void *v) 103 { 104 if (!v) 105 (void)__task_seq_show(seq, v, true); 106 else 107 put_task_struct((struct task_struct *)v); 108 } 109 110 static const struct seq_operations task_seq_ops = { 111 .start = task_seq_start, 112 .next = task_seq_next, 113 .stop = task_seq_stop, 114 .show = task_seq_show, 115 }; 116 117 struct bpf_iter_seq_task_file_info { 118 /* The first field must be struct bpf_iter_seq_task_common. 119 * this is assumed by {init, fini}_seq_pidns() callback functions. 120 */ 121 struct bpf_iter_seq_task_common common; 122 struct task_struct *task; 123 struct files_struct *files; 124 u32 tid; 125 u32 fd; 126 }; 127 128 static struct file * 129 task_file_seq_get_next(struct bpf_iter_seq_task_file_info *info, 130 struct task_struct **task, struct files_struct **fstruct) 131 { 132 struct pid_namespace *ns = info->common.ns; 133 u32 curr_tid = info->tid, max_fds; 134 struct files_struct *curr_files; 135 struct task_struct *curr_task; 136 int curr_fd = info->fd; 137 138 /* If this function returns a non-NULL file object, 139 * it held a reference to the task/files_struct/file. 140 * Otherwise, it does not hold any reference. 141 */ 142 again: 143 if (*task) { 144 curr_task = *task; 145 curr_files = *fstruct; 146 curr_fd = info->fd; 147 } else { 148 curr_task = task_seq_get_next(ns, &curr_tid); 149 if (!curr_task) 150 return NULL; 151 152 curr_files = get_files_struct(curr_task); 153 if (!curr_files) { 154 put_task_struct(curr_task); 155 curr_tid = ++(info->tid); 156 info->fd = 0; 157 goto again; 158 } 159 160 /* set *fstruct, *task and info->tid */ 161 *fstruct = curr_files; 162 *task = curr_task; 163 if (curr_tid == info->tid) { 164 curr_fd = info->fd; 165 } else { 166 info->tid = curr_tid; 167 curr_fd = 0; 168 } 169 } 170 171 rcu_read_lock(); 172 max_fds = files_fdtable(curr_files)->max_fds; 173 for (; curr_fd < max_fds; curr_fd++) { 174 struct file *f; 175 176 f = fcheck_files(curr_files, curr_fd); 177 if (!f) 178 continue; 179 180 /* set info->fd */ 181 info->fd = curr_fd; 182 get_file(f); 183 rcu_read_unlock(); 184 return f; 185 } 186 187 /* the current task is done, go to the next task */ 188 rcu_read_unlock(); 189 put_files_struct(curr_files); 190 put_task_struct(curr_task); 191 *task = NULL; 192 *fstruct = NULL; 193 info->fd = 0; 194 curr_tid = ++(info->tid); 195 goto again; 196 } 197 198 static void *task_file_seq_start(struct seq_file *seq, loff_t *pos) 199 { 200 struct bpf_iter_seq_task_file_info *info = seq->private; 201 struct files_struct *files = NULL; 202 struct task_struct *task = NULL; 203 struct file *file; 204 205 file = task_file_seq_get_next(info, &task, &files); 206 if (!file) { 207 info->files = NULL; 208 info->task = NULL; 209 return NULL; 210 } 211 212 ++*pos; 213 info->task = task; 214 info->files = files; 215 216 return file; 217 } 218 219 static void *task_file_seq_next(struct seq_file *seq, void *v, loff_t *pos) 220 { 221 struct bpf_iter_seq_task_file_info *info = seq->private; 222 struct files_struct *files = info->files; 223 struct task_struct *task = info->task; 224 struct file *file; 225 226 ++*pos; 227 ++info->fd; 228 fput((struct file *)v); 229 file = task_file_seq_get_next(info, &task, &files); 230 if (!file) { 231 info->files = NULL; 232 info->task = NULL; 233 return NULL; 234 } 235 236 info->task = task; 237 info->files = files; 238 239 return file; 240 } 241 242 struct bpf_iter__task_file { 243 __bpf_md_ptr(struct bpf_iter_meta *, meta); 244 __bpf_md_ptr(struct task_struct *, task); 245 u32 fd __aligned(8); 246 __bpf_md_ptr(struct file *, file); 247 }; 248 249 DEFINE_BPF_ITER_FUNC(task_file, struct bpf_iter_meta *meta, 250 struct task_struct *task, u32 fd, 251 struct file *file) 252 253 static int __task_file_seq_show(struct seq_file *seq, struct file *file, 254 bool in_stop) 255 { 256 struct bpf_iter_seq_task_file_info *info = seq->private; 257 struct bpf_iter__task_file ctx; 258 struct bpf_iter_meta meta; 259 struct bpf_prog *prog; 260 261 meta.seq = seq; 262 prog = bpf_iter_get_info(&meta, in_stop); 263 if (!prog) 264 return 0; 265 266 ctx.meta = &meta; 267 ctx.task = info->task; 268 ctx.fd = info->fd; 269 ctx.file = file; 270 return bpf_iter_run_prog(prog, &ctx); 271 } 272 273 static int task_file_seq_show(struct seq_file *seq, void *v) 274 { 275 return __task_file_seq_show(seq, v, false); 276 } 277 278 static void task_file_seq_stop(struct seq_file *seq, void *v) 279 { 280 struct bpf_iter_seq_task_file_info *info = seq->private; 281 282 if (!v) { 283 (void)__task_file_seq_show(seq, v, true); 284 } else { 285 fput((struct file *)v); 286 put_files_struct(info->files); 287 put_task_struct(info->task); 288 info->files = NULL; 289 info->task = NULL; 290 } 291 } 292 293 static int init_seq_pidns(void *priv_data) 294 { 295 struct bpf_iter_seq_task_common *common = priv_data; 296 297 common->ns = get_pid_ns(task_active_pid_ns(current)); 298 return 0; 299 } 300 301 static void fini_seq_pidns(void *priv_data) 302 { 303 struct bpf_iter_seq_task_common *common = priv_data; 304 305 put_pid_ns(common->ns); 306 } 307 308 static const struct seq_operations task_file_seq_ops = { 309 .start = task_file_seq_start, 310 .next = task_file_seq_next, 311 .stop = task_file_seq_stop, 312 .show = task_file_seq_show, 313 }; 314 315 static const struct bpf_iter_reg task_reg_info = { 316 .target = "task", 317 .seq_ops = &task_seq_ops, 318 .init_seq_private = init_seq_pidns, 319 .fini_seq_private = fini_seq_pidns, 320 .seq_priv_size = sizeof(struct bpf_iter_seq_task_info), 321 .ctx_arg_info_size = 1, 322 .ctx_arg_info = { 323 { offsetof(struct bpf_iter__task, task), 324 PTR_TO_BTF_ID_OR_NULL }, 325 }, 326 }; 327 328 static const struct bpf_iter_reg task_file_reg_info = { 329 .target = "task_file", 330 .seq_ops = &task_file_seq_ops, 331 .init_seq_private = init_seq_pidns, 332 .fini_seq_private = fini_seq_pidns, 333 .seq_priv_size = sizeof(struct bpf_iter_seq_task_file_info), 334 .ctx_arg_info_size = 2, 335 .ctx_arg_info = { 336 { offsetof(struct bpf_iter__task_file, task), 337 PTR_TO_BTF_ID_OR_NULL }, 338 { offsetof(struct bpf_iter__task_file, file), 339 PTR_TO_BTF_ID_OR_NULL }, 340 }, 341 }; 342 343 static int __init task_iter_init(void) 344 { 345 int ret; 346 347 ret = bpf_iter_reg_target(&task_reg_info); 348 if (ret) 349 return ret; 350 351 return bpf_iter_reg_target(&task_file_reg_info); 352 } 353 late_initcall(task_iter_init); 354