task_iter.c 8.0 KB

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