aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/bpf/helpers.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/bpf/helpers.c')
-rw-r--r--kernel/bpf/helpers.c131
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
372static 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
423static 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
445BPF_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
460const 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
470BPF_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
488const 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