~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/kernel/bpf/mprog.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php