diff options
Diffstat (limited to 'kernel/bpf/helpers.c')
-rw-r--r-- | kernel/bpf/helpers.c | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index a411fc17d265..4266ffde07ca 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c | |||
@@ -18,6 +18,9 @@ | |||
18 | #include <linux/sched.h> | 18 | #include <linux/sched.h> |
19 | #include <linux/uidgid.h> | 19 | #include <linux/uidgid.h> |
20 | #include <linux/filter.h> | 20 | #include <linux/filter.h> |
21 | #include <linux/ctype.h> | ||
22 | |||
23 | #include "../../lib/kstrtox.h" | ||
21 | 24 | ||
22 | /* If kernel subsystem is allowing eBPF programs to call this function, | 25 | /* If kernel subsystem is allowing eBPF programs to call this function, |
23 | * inside its own verifier_ops->get_func_proto() callback it should return | 26 | * inside its own verifier_ops->get_func_proto() callback it should return |
@@ -363,4 +366,132 @@ const struct bpf_func_proto bpf_get_local_storage_proto = { | |||
363 | .arg2_type = ARG_ANYTHING, | 366 | .arg2_type = ARG_ANYTHING, |
364 | }; | 367 | }; |
365 | #endif | 368 | #endif |
369 | |||
370 | #define BPF_STRTOX_BASE_MASK 0x1F | ||
371 | |||
372 | static int __bpf_strtoull(const char *buf, size_t buf_len, u64 flags, | ||
373 | unsigned long long *res, bool *is_negative) | ||
374 | { | ||
375 | unsigned int base = flags & BPF_STRTOX_BASE_MASK; | ||
376 | const char *cur_buf = buf; | ||
377 | size_t cur_len = buf_len; | ||
378 | unsigned int consumed; | ||
379 | size_t val_len; | ||
380 | char str[64]; | ||
381 | |||
382 | if (!buf || !buf_len || !res || !is_negative) | ||
383 | return -EINVAL; | ||
384 | |||
385 | if (base != 0 && base != 8 && base != 10 && base != 16) | ||
386 | return -EINVAL; | ||
387 | |||
388 | if (flags & ~BPF_STRTOX_BASE_MASK) | ||
389 | return -EINVAL; | ||
390 | |||
391 | while (cur_buf < buf + buf_len && isspace(*cur_buf)) | ||
392 | ++cur_buf; | ||
393 | |||
394 | *is_negative = (cur_buf < buf + buf_len && *cur_buf == '-'); | ||
395 | if (*is_negative) | ||
396 | ++cur_buf; | ||
397 | |||
398 | consumed = cur_buf - buf; | ||
399 | cur_len -= consumed; | ||
400 | if (!cur_len) | ||
401 | return -EINVAL; | ||
402 | |||
403 | cur_len = min(cur_len, sizeof(str) - 1); | ||
404 | memcpy(str, cur_buf, cur_len); | ||
405 | str[cur_len] = '\0'; | ||
406 | cur_buf = str; | ||
407 | |||
408 | cur_buf = _parse_integer_fixup_radix(cur_buf, &base); | ||
409 | val_len = _parse_integer(cur_buf, base, res); | ||
410 | |||
411 | if (val_len & KSTRTOX_OVERFLOW) | ||
412 | return -ERANGE; | ||
413 | |||
414 | if (val_len == 0) | ||
415 | return -EINVAL; | ||
416 | |||
417 | cur_buf += val_len; | ||
418 | consumed += cur_buf - str; | ||
419 | |||
420 | return consumed; | ||
421 | } | ||
422 | |||
423 | static int __bpf_strtoll(const char *buf, size_t buf_len, u64 flags, | ||
424 | long long *res) | ||
425 | { | ||
426 | unsigned long long _res; | ||
427 | bool is_negative; | ||
428 | int err; | ||
429 | |||
430 | err = __bpf_strtoull(buf, buf_len, flags, &_res, &is_negative); | ||
431 | if (err < 0) | ||
432 | return err; | ||
433 | if (is_negative) { | ||
434 | if ((long long)-_res > 0) | ||
435 | return -ERANGE; | ||
436 | *res = -_res; | ||
437 | } else { | ||
438 | if ((long long)_res < 0) | ||
439 | return -ERANGE; | ||
440 | *res = _res; | ||
441 | } | ||
442 | return err; | ||
443 | } | ||
444 | |||
445 | BPF_CALL_4(bpf_strtol, const char *, buf, size_t, buf_len, u64, flags, | ||
446 | long *, res) | ||
447 | { | ||
448 | long long _res; | ||
449 | int err; | ||
450 | |||
451 | err = __bpf_strtoll(buf, buf_len, flags, &_res); | ||
452 | if (err < 0) | ||
453 | return err; | ||
454 | if (_res != (long)_res) | ||
455 | return -ERANGE; | ||
456 | *res = _res; | ||
457 | return err; | ||
458 | } | ||
459 | |||
460 | const struct bpf_func_proto bpf_strtol_proto = { | ||
461 | .func = bpf_strtol, | ||
462 | .gpl_only = false, | ||
463 | .ret_type = RET_INTEGER, | ||
464 | .arg1_type = ARG_PTR_TO_MEM, | ||
465 | .arg2_type = ARG_CONST_SIZE, | ||
466 | .arg3_type = ARG_ANYTHING, | ||
467 | .arg4_type = ARG_PTR_TO_LONG, | ||
468 | }; | ||
469 | |||
470 | BPF_CALL_4(bpf_strtoul, const char *, buf, size_t, buf_len, u64, flags, | ||
471 | unsigned long *, res) | ||
472 | { | ||
473 | unsigned long long _res; | ||
474 | bool is_negative; | ||
475 | int err; | ||
476 | |||
477 | err = __bpf_strtoull(buf, buf_len, flags, &_res, &is_negative); | ||
478 | if (err < 0) | ||
479 | return err; | ||
480 | if (is_negative) | ||
481 | return -EINVAL; | ||
482 | if (_res != (unsigned long)_res) | ||
483 | return -ERANGE; | ||
484 | *res = _res; | ||
485 | return err; | ||
486 | } | ||
487 | |||
488 | const struct bpf_func_proto bpf_strtoul_proto = { | ||
489 | .func = bpf_strtoul, | ||
490 | .gpl_only = false, | ||
491 | .ret_type = RET_INTEGER, | ||
492 | .arg1_type = ARG_PTR_TO_MEM, | ||
493 | .arg2_type = ARG_CONST_SIZE, | ||
494 | .arg3_type = ARG_ANYTHING, | ||
495 | .arg4_type = ARG_PTR_TO_LONG, | ||
496 | }; | ||
366 | #endif | 497 | #endif |