mprog.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Copyright (c) 2023 Isovalent */
  3. #include <linux/bpf.h>
  4. #include <linux/bpf_mprog.h>
  5. static int bpf_mprog_link(struct bpf_tuple *tuple,
  6. u32 id_or_fd, u32 flags,
  7. enum bpf_prog_type type)
  8. {
  9. struct bpf_link *link = ERR_PTR(-EINVAL);
  10. bool id = flags & BPF_F_ID;
  11. if (id)
  12. link = bpf_link_by_id(id_or_fd);
  13. else if (id_or_fd)
  14. link = bpf_link_get_from_fd(id_or_fd);
  15. if (IS_ERR(link))
  16. return PTR_ERR(link);
  17. if (type && link->prog->type != type) {
  18. bpf_link_put(link);
  19. return -EINVAL;
  20. }
  21. tuple->link = link;
  22. tuple->prog = link->prog;
  23. return 0;
  24. }
  25. static int bpf_mprog_prog(struct bpf_tuple *tuple,
  26. u32 id_or_fd, u32 flags,
  27. enum bpf_prog_type type)
  28. {
  29. struct bpf_prog *prog = ERR_PTR(-EINVAL);
  30. bool id = flags & BPF_F_ID;
  31. if (id)
  32. prog = bpf_prog_by_id(id_or_fd);
  33. else if (id_or_fd)
  34. prog = bpf_prog_get(id_or_fd);
  35. if (IS_ERR(prog))
  36. return PTR_ERR(prog);
  37. if (type && prog->type != type) {
  38. bpf_prog_put(prog);
  39. return -EINVAL;
  40. }
  41. tuple->link = NULL;
  42. tuple->prog = prog;
  43. return 0;
  44. }
  45. static int bpf_mprog_tuple_relative(struct bpf_tuple *tuple,
  46. u32 id_or_fd, u32 flags,
  47. enum bpf_prog_type type)
  48. {
  49. bool link = flags & BPF_F_LINK;
  50. bool id = flags & BPF_F_ID;
  51. memset(tuple, 0, sizeof(*tuple));
  52. if (link)
  53. return bpf_mprog_link(tuple, id_or_fd, flags, type);
  54. /* If no relevant flag is set and no id_or_fd was passed, then
  55. * tuple link/prog is just NULLed. This is the case when before/
  56. * after selects first/last position without passing fd.
  57. */
  58. if (!id && !id_or_fd)
  59. return 0;
  60. return bpf_mprog_prog(tuple, id_or_fd, flags, type);
  61. }
  62. static void bpf_mprog_tuple_put(struct bpf_tuple *tuple)
  63. {
  64. if (tuple->link)
  65. bpf_link_put(tuple->link);
  66. else if (tuple->prog)
  67. bpf_prog_put(tuple->prog);
  68. }
  69. /* The bpf_mprog_{replace,delete}() operate on exact idx position with the
  70. * one exception that for deletion we support delete from front/back. In
  71. * case of front idx is -1, in case of back idx is bpf_mprog_total(entry).
  72. * Adjustment to first and last entry is trivial. The bpf_mprog_insert()
  73. * we have to deal with the following cases:
  74. *
  75. * idx + before:
  76. *
  77. * Insert P4 before P3: idx for old array is 1, idx for new array is 2,
  78. * hence we adjust target idx for the new array, so that memmove copies
  79. * P1 and P2 to the new entry, and we insert P4 into idx 2. Inserting
  80. * before P1 would have old idx -1 and new idx 0.
  81. *
  82. * +--+--+--+ +--+--+--+--+ +--+--+--+--+
  83. * |P1|P2|P3| ==> |P1|P2| |P3| ==> |P1|P2|P4|P3|
  84. * +--+--+--+ +--+--+--+--+ +--+--+--+--+
  85. *
  86. * idx + after:
  87. *
  88. * Insert P4 after P2: idx for old array is 2, idx for new array is 2.
  89. * Again, memmove copies P1 and P2 to the new entry, and we insert P4
  90. * into idx 2. Inserting after P3 would have both old/new idx at 4 aka
  91. * bpf_mprog_total(entry).
  92. *
  93. * +--+--+--+ +--+--+--+--+ +--+--+--+--+
  94. * |P1|P2|P3| ==> |P1|P2| |P3| ==> |P1|P2|P4|P3|
  95. * +--+--+--+ +--+--+--+--+ +--+--+--+--+
  96. */
  97. static int bpf_mprog_replace(struct bpf_mprog_entry *entry,
  98. struct bpf_mprog_entry **entry_new,
  99. struct bpf_tuple *ntuple, int idx)
  100. {
  101. struct bpf_mprog_fp *fp;
  102. struct bpf_mprog_cp *cp;
  103. struct bpf_prog *oprog;
  104. bpf_mprog_read(entry, idx, &fp, &cp);
  105. oprog = READ_ONCE(fp->prog);
  106. bpf_mprog_write(fp, cp, ntuple);
  107. if (!ntuple->link) {
  108. WARN_ON_ONCE(cp->link);
  109. bpf_prog_put(oprog);
  110. }
  111. *entry_new = entry;
  112. return 0;
  113. }
  114. static int bpf_mprog_insert(struct bpf_mprog_entry *entry,
  115. struct bpf_mprog_entry **entry_new,
  116. struct bpf_tuple *ntuple, int idx, u32 flags)
  117. {
  118. int total = bpf_mprog_total(entry);
  119. struct bpf_mprog_entry *peer;
  120. struct bpf_mprog_fp *fp;
  121. struct bpf_mprog_cp *cp;
  122. peer = bpf_mprog_peer(entry);
  123. bpf_mprog_entry_copy(peer, entry);
  124. if (idx == total)
  125. goto insert;
  126. else if (flags & BPF_F_BEFORE)
  127. idx += 1;
  128. bpf_mprog_entry_grow(peer, idx);
  129. insert:
  130. bpf_mprog_read(peer, idx, &fp, &cp);
  131. bpf_mprog_write(fp, cp, ntuple);
  132. bpf_mprog_inc(peer);
  133. *entry_new = peer;
  134. return 0;
  135. }
  136. static int bpf_mprog_delete(struct bpf_mprog_entry *entry,
  137. struct bpf_mprog_entry **entry_new,
  138. struct bpf_tuple *dtuple, int idx)
  139. {
  140. int total = bpf_mprog_total(entry);
  141. struct bpf_mprog_entry *peer;
  142. peer = bpf_mprog_peer(entry);
  143. bpf_mprog_entry_copy(peer, entry);
  144. if (idx == -1)
  145. idx = 0;
  146. else if (idx == total)
  147. idx = total - 1;
  148. bpf_mprog_entry_shrink(peer, idx);
  149. bpf_mprog_dec(peer);
  150. bpf_mprog_mark_for_release(peer, dtuple);
  151. *entry_new = peer;
  152. return 0;
  153. }
  154. /* In bpf_mprog_pos_*() we evaluate the target position for the BPF
  155. * program/link that needs to be replaced, inserted or deleted for
  156. * each "rule" independently. If all rules agree on that position
  157. * or existing element, then enact replacement, addition or deletion.
  158. * If this is not the case, then the request cannot be satisfied and
  159. * we bail out with an error.
  160. */
  161. static int bpf_mprog_pos_exact(struct bpf_mprog_entry *entry,
  162. struct bpf_tuple *tuple)
  163. {
  164. struct bpf_mprog_fp *fp;
  165. struct bpf_mprog_cp *cp;
  166. int i;
  167. for (i = 0; i < bpf_mprog_total(entry); i++) {
  168. bpf_mprog_read(entry, i, &fp, &cp);
  169. if (tuple->prog == READ_ONCE(fp->prog))
  170. return tuple->link == cp->link ? i : -EBUSY;
  171. }
  172. return -ENOENT;
  173. }
  174. static int bpf_mprog_pos_before(struct bpf_mprog_entry *entry,
  175. struct bpf_tuple *tuple)
  176. {
  177. struct bpf_mprog_fp *fp;
  178. struct bpf_mprog_cp *cp;
  179. int i;
  180. for (i = 0; i < bpf_mprog_total(entry); i++) {
  181. bpf_mprog_read(entry, i, &fp, &cp);
  182. if (tuple->prog == READ_ONCE(fp->prog) &&
  183. (!tuple->link || tuple->link == cp->link))
  184. return i - 1;
  185. }
  186. return tuple->prog ? -ENOENT : -1;
  187. }
  188. static int bpf_mprog_pos_after(struct bpf_mprog_entry *entry,
  189. struct bpf_tuple *tuple)
  190. {
  191. struct bpf_mprog_fp *fp;
  192. struct bpf_mprog_cp *cp;
  193. int i;
  194. for (i = 0; i < bpf_mprog_total(entry); i++) {
  195. bpf_mprog_read(entry, i, &fp, &cp);
  196. if (tuple->prog == READ_ONCE(fp->prog) &&
  197. (!tuple->link || tuple->link == cp->link))
  198. return i + 1;
  199. }
  200. return tuple->prog ? -ENOENT : bpf_mprog_total(entry);
  201. }
  202. int bpf_mprog_attach(struct bpf_mprog_entry *entry,
  203. struct bpf_mprog_entry **entry_new,
  204. struct bpf_prog *prog_new, struct bpf_link *link,
  205. struct bpf_prog *prog_old,
  206. u32 flags, u32 id_or_fd, u64 revision)
  207. {
  208. struct bpf_tuple rtuple, ntuple = {
  209. .prog = prog_new,
  210. .link = link,
  211. }, otuple = {
  212. .prog = prog_old,
  213. .link = link,
  214. };
  215. int ret, idx = -ERANGE, tidx;
  216. if (revision && revision != bpf_mprog_revision(entry))
  217. return -ESTALE;
  218. if (bpf_mprog_exists(entry, prog_new))
  219. return -EEXIST;
  220. ret = bpf_mprog_tuple_relative(&rtuple, id_or_fd,
  221. flags & ~BPF_F_REPLACE,
  222. prog_new->type);
  223. if (ret)
  224. return ret;
  225. if (flags & BPF_F_REPLACE) {
  226. tidx = bpf_mprog_pos_exact(entry, &otuple);
  227. if (tidx < 0) {
  228. ret = tidx;
  229. goto out;
  230. }
  231. idx = tidx;
  232. } else if (bpf_mprog_total(entry) == bpf_mprog_max()) {
  233. ret = -ERANGE;
  234. goto out;
  235. }
  236. if (flags & BPF_F_BEFORE) {
  237. tidx = bpf_mprog_pos_before(entry, &rtuple);
  238. if (tidx < -1 || (idx >= -1 && tidx != idx)) {
  239. ret = tidx < -1 ? tidx : -ERANGE;
  240. goto out;
  241. }
  242. idx = tidx;
  243. }
  244. if (flags & BPF_F_AFTER) {
  245. tidx = bpf_mprog_pos_after(entry, &rtuple);
  246. if (tidx < -1 || (idx >= -1 && tidx != idx)) {
  247. ret = tidx < 0 ? tidx : -ERANGE;
  248. goto out;
  249. }
  250. idx = tidx;
  251. }
  252. if (idx < -1) {
  253. if (rtuple.prog || flags) {
  254. ret = -EINVAL;
  255. goto out;
  256. }
  257. idx = bpf_mprog_total(entry);
  258. flags = BPF_F_AFTER;
  259. }
  260. if (idx >= bpf_mprog_max()) {
  261. ret = -ERANGE;
  262. goto out;
  263. }
  264. if (flags & BPF_F_REPLACE)
  265. ret = bpf_mprog_replace(entry, entry_new, &ntuple, idx);
  266. else
  267. ret = bpf_mprog_insert(entry, entry_new, &ntuple, idx, flags);
  268. out:
  269. bpf_mprog_tuple_put(&rtuple);
  270. return ret;
  271. }
  272. static int bpf_mprog_fetch(struct bpf_mprog_entry *entry,
  273. struct bpf_tuple *tuple, int idx)
  274. {
  275. int total = bpf_mprog_total(entry);
  276. struct bpf_mprog_cp *cp;
  277. struct bpf_mprog_fp *fp;
  278. struct bpf_prog *prog;
  279. struct bpf_link *link;
  280. if (idx == -1)
  281. idx = 0;
  282. else if (idx == total)
  283. idx = total - 1;
  284. bpf_mprog_read(entry, idx, &fp, &cp);
  285. prog = READ_ONCE(fp->prog);
  286. link = cp->link;
  287. /* The deletion request can either be without filled tuple in which
  288. * case it gets populated here based on idx, or with filled tuple
  289. * where the only thing we end up doing is the WARN_ON_ONCE() assert.
  290. * If we hit a BPF link at the given index, it must not be removed
  291. * from opts path.
  292. */
  293. if (link && !tuple->link)
  294. return -EBUSY;
  295. WARN_ON_ONCE(tuple->prog && tuple->prog != prog);
  296. WARN_ON_ONCE(tuple->link && tuple->link != link);
  297. tuple->prog = prog;
  298. tuple->link = link;
  299. return 0;
  300. }
  301. int bpf_mprog_detach(struct bpf_mprog_entry *entry,
  302. struct bpf_mprog_entry **entry_new,
  303. struct bpf_prog *prog, struct bpf_link *link,
  304. u32 flags, u32 id_or_fd, u64 revision)
  305. {
  306. struct bpf_tuple rtuple, dtuple = {
  307. .prog = prog,
  308. .link = link,
  309. };
  310. int ret, idx = -ERANGE, tidx;
  311. if (flags & BPF_F_REPLACE)
  312. return -EINVAL;
  313. if (revision && revision != bpf_mprog_revision(entry))
  314. return -ESTALE;
  315. if (!bpf_mprog_total(entry))
  316. return -ENOENT;
  317. ret = bpf_mprog_tuple_relative(&rtuple, id_or_fd, flags,
  318. prog ? prog->type :
  319. BPF_PROG_TYPE_UNSPEC);
  320. if (ret)
  321. return ret;
  322. if (dtuple.prog) {
  323. tidx = bpf_mprog_pos_exact(entry, &dtuple);
  324. if (tidx < 0) {
  325. ret = tidx;
  326. goto out;
  327. }
  328. idx = tidx;
  329. }
  330. if (flags & BPF_F_BEFORE) {
  331. tidx = bpf_mprog_pos_before(entry, &rtuple);
  332. if (tidx < -1 || (idx >= -1 && tidx != idx)) {
  333. ret = tidx < -1 ? tidx : -ERANGE;
  334. goto out;
  335. }
  336. idx = tidx;
  337. }
  338. if (flags & BPF_F_AFTER) {
  339. tidx = bpf_mprog_pos_after(entry, &rtuple);
  340. if (tidx < -1 || (idx >= -1 && tidx != idx)) {
  341. ret = tidx < 0 ? tidx : -ERANGE;
  342. goto out;
  343. }
  344. idx = tidx;
  345. }
  346. if (idx < -1) {
  347. if (rtuple.prog || flags) {
  348. ret = -EINVAL;
  349. goto out;
  350. }
  351. idx = bpf_mprog_total(entry);
  352. flags = BPF_F_AFTER;
  353. }
  354. if (idx >= bpf_mprog_max()) {
  355. ret = -ERANGE;
  356. goto out;
  357. }
  358. ret = bpf_mprog_fetch(entry, &dtuple, idx);
  359. if (ret)
  360. goto out;
  361. ret = bpf_mprog_delete(entry, entry_new, &dtuple, idx);
  362. out:
  363. bpf_mprog_tuple_put(&rtuple);
  364. return ret;
  365. }
  366. int bpf_mprog_query(const union bpf_attr *attr, union bpf_attr __user *uattr,
  367. struct bpf_mprog_entry *entry)
  368. {
  369. u32 __user *uprog_flags, *ulink_flags;
  370. u32 __user *uprog_id, *ulink_id;
  371. struct bpf_mprog_fp *fp;
  372. struct bpf_mprog_cp *cp;
  373. struct bpf_prog *prog;
  374. const u32 flags = 0;
  375. u32 id, count = 0;
  376. u64 revision = 1;
  377. int i, ret = 0;
  378. if (attr->query.query_flags || attr->query.attach_flags)
  379. return -EINVAL;
  380. if (entry) {
  381. revision = bpf_mprog_revision(entry);
  382. count = bpf_mprog_total(entry);
  383. }
  384. if (copy_to_user(&uattr->query.attach_flags, &flags, sizeof(flags)))
  385. return -EFAULT;
  386. if (copy_to_user(&uattr->query.revision, &revision, sizeof(revision)))
  387. return -EFAULT;
  388. if (copy_to_user(&uattr->query.count, &count, sizeof(count)))
  389. return -EFAULT;
  390. uprog_id = u64_to_user_ptr(attr->query.prog_ids);
  391. uprog_flags = u64_to_user_ptr(attr->query.prog_attach_flags);
  392. ulink_id = u64_to_user_ptr(attr->query.link_ids);
  393. ulink_flags = u64_to_user_ptr(attr->query.link_attach_flags);
  394. if (attr->query.count == 0 || !uprog_id || !count)
  395. return 0;
  396. if (attr->query.count < count) {
  397. count = attr->query.count;
  398. ret = -ENOSPC;
  399. }
  400. for (i = 0; i < bpf_mprog_max(); i++) {
  401. bpf_mprog_read(entry, i, &fp, &cp);
  402. prog = READ_ONCE(fp->prog);
  403. if (!prog)
  404. break;
  405. id = prog->aux->id;
  406. if (copy_to_user(uprog_id + i, &id, sizeof(id)))
  407. return -EFAULT;
  408. if (uprog_flags &&
  409. copy_to_user(uprog_flags + i, &flags, sizeof(flags)))
  410. return -EFAULT;
  411. id = cp->link ? cp->link->id : 0;
  412. if (ulink_id &&
  413. copy_to_user(ulink_id + i, &id, sizeof(id)))
  414. return -EFAULT;
  415. if (ulink_flags &&
  416. copy_to_user(ulink_flags + i, &flags, sizeof(flags)))
  417. return -EFAULT;
  418. if (i + 1 == count)
  419. break;
  420. }
  421. return ret;
  422. }