LCOV - code coverage report
Current view: top level - kernel/bpf - helpers.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 0 116 0.0 %
Date: 2020-09-30 20:25:40 Functions: 0 23 0.0 %
Branches: 0 74 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
       3                 :            :  */
       4                 :            : #include <linux/bpf.h>
       5                 :            : #include <linux/rcupdate.h>
       6                 :            : #include <linux/random.h>
       7                 :            : #include <linux/smp.h>
       8                 :            : #include <linux/topology.h>
       9                 :            : #include <linux/ktime.h>
      10                 :            : #include <linux/sched.h>
      11                 :            : #include <linux/uidgid.h>
      12                 :            : #include <linux/filter.h>
      13                 :            : #include <linux/ctype.h>
      14                 :            : 
      15                 :            : #include "../../lib/kstrtox.h"
      16                 :            : 
      17                 :            : /* If kernel subsystem is allowing eBPF programs to call this function,
      18                 :            :  * inside its own verifier_ops->get_func_proto() callback it should return
      19                 :            :  * bpf_map_lookup_elem_proto, so that verifier can properly check the arguments
      20                 :            :  *
      21                 :            :  * Different map implementations will rely on rcu in map methods
      22                 :            :  * lookup/update/delete, therefore eBPF programs must run under rcu lock
      23                 :            :  * if program is allowed to access maps, so check rcu_read_lock_held in
      24                 :            :  * all three functions.
      25                 :            :  */
      26                 :          0 : BPF_CALL_2(bpf_map_lookup_elem, struct bpf_map *, map, void *, key)
      27                 :            : {
      28   [ #  #  #  # ]:          0 :         WARN_ON_ONCE(!rcu_read_lock_held());
      29                 :          0 :         return (unsigned long) map->ops->map_lookup_elem(map, key);
      30                 :            : }
      31                 :            : 
      32                 :            : const struct bpf_func_proto bpf_map_lookup_elem_proto = {
      33                 :            :         .func           = bpf_map_lookup_elem,
      34                 :            :         .gpl_only       = false,
      35                 :            :         .pkt_access     = true,
      36                 :            :         .ret_type       = RET_PTR_TO_MAP_VALUE_OR_NULL,
      37                 :            :         .arg1_type      = ARG_CONST_MAP_PTR,
      38                 :            :         .arg2_type      = ARG_PTR_TO_MAP_KEY,
      39                 :            : };
      40                 :            : 
      41                 :          0 : BPF_CALL_4(bpf_map_update_elem, struct bpf_map *, map, void *, key,
      42                 :            :            void *, value, u64, flags)
      43                 :            : {
      44   [ #  #  #  # ]:          0 :         WARN_ON_ONCE(!rcu_read_lock_held());
      45                 :          0 :         return map->ops->map_update_elem(map, key, value, flags);
      46                 :            : }
      47                 :            : 
      48                 :            : const struct bpf_func_proto bpf_map_update_elem_proto = {
      49                 :            :         .func           = bpf_map_update_elem,
      50                 :            :         .gpl_only       = false,
      51                 :            :         .pkt_access     = true,
      52                 :            :         .ret_type       = RET_INTEGER,
      53                 :            :         .arg1_type      = ARG_CONST_MAP_PTR,
      54                 :            :         .arg2_type      = ARG_PTR_TO_MAP_KEY,
      55                 :            :         .arg3_type      = ARG_PTR_TO_MAP_VALUE,
      56                 :            :         .arg4_type      = ARG_ANYTHING,
      57                 :            : };
      58                 :            : 
      59                 :          0 : BPF_CALL_2(bpf_map_delete_elem, struct bpf_map *, map, void *, key)
      60                 :            : {
      61   [ #  #  #  # ]:          0 :         WARN_ON_ONCE(!rcu_read_lock_held());
      62                 :          0 :         return map->ops->map_delete_elem(map, key);
      63                 :            : }
      64                 :            : 
      65                 :            : const struct bpf_func_proto bpf_map_delete_elem_proto = {
      66                 :            :         .func           = bpf_map_delete_elem,
      67                 :            :         .gpl_only       = false,
      68                 :            :         .pkt_access     = true,
      69                 :            :         .ret_type       = RET_INTEGER,
      70                 :            :         .arg1_type      = ARG_CONST_MAP_PTR,
      71                 :            :         .arg2_type      = ARG_PTR_TO_MAP_KEY,
      72                 :            : };
      73                 :            : 
      74                 :          0 : BPF_CALL_3(bpf_map_push_elem, struct bpf_map *, map, void *, value, u64, flags)
      75                 :            : {
      76                 :          0 :         return map->ops->map_push_elem(map, value, flags);
      77                 :            : }
      78                 :            : 
      79                 :            : const struct bpf_func_proto bpf_map_push_elem_proto = {
      80                 :            :         .func           = bpf_map_push_elem,
      81                 :            :         .gpl_only       = false,
      82                 :            :         .pkt_access     = true,
      83                 :            :         .ret_type       = RET_INTEGER,
      84                 :            :         .arg1_type      = ARG_CONST_MAP_PTR,
      85                 :            :         .arg2_type      = ARG_PTR_TO_MAP_VALUE,
      86                 :            :         .arg3_type      = ARG_ANYTHING,
      87                 :            : };
      88                 :            : 
      89                 :          0 : BPF_CALL_2(bpf_map_pop_elem, struct bpf_map *, map, void *, value)
      90                 :            : {
      91                 :          0 :         return map->ops->map_pop_elem(map, value);
      92                 :            : }
      93                 :            : 
      94                 :            : const struct bpf_func_proto bpf_map_pop_elem_proto = {
      95                 :            :         .func           = bpf_map_pop_elem,
      96                 :            :         .gpl_only       = false,
      97                 :            :         .ret_type       = RET_INTEGER,
      98                 :            :         .arg1_type      = ARG_CONST_MAP_PTR,
      99                 :            :         .arg2_type      = ARG_PTR_TO_UNINIT_MAP_VALUE,
     100                 :            : };
     101                 :            : 
     102                 :          0 : BPF_CALL_2(bpf_map_peek_elem, struct bpf_map *, map, void *, value)
     103                 :            : {
     104                 :          0 :         return map->ops->map_peek_elem(map, value);
     105                 :            : }
     106                 :            : 
     107                 :            : const struct bpf_func_proto bpf_map_peek_elem_proto = {
     108                 :            :         .func           = bpf_map_pop_elem,
     109                 :            :         .gpl_only       = false,
     110                 :            :         .ret_type       = RET_INTEGER,
     111                 :            :         .arg1_type      = ARG_CONST_MAP_PTR,
     112                 :            :         .arg2_type      = ARG_PTR_TO_UNINIT_MAP_VALUE,
     113                 :            : };
     114                 :            : 
     115                 :            : const struct bpf_func_proto bpf_get_prandom_u32_proto = {
     116                 :            :         .func           = bpf_user_rnd_u32,
     117                 :            :         .gpl_only       = false,
     118                 :            :         .ret_type       = RET_INTEGER,
     119                 :            : };
     120                 :            : 
     121                 :          0 : BPF_CALL_0(bpf_get_smp_processor_id)
     122                 :            : {
     123                 :          0 :         return smp_processor_id();
     124                 :            : }
     125                 :            : 
     126                 :            : const struct bpf_func_proto bpf_get_smp_processor_id_proto = {
     127                 :            :         .func           = bpf_get_smp_processor_id,
     128                 :            :         .gpl_only       = false,
     129                 :            :         .ret_type       = RET_INTEGER,
     130                 :            : };
     131                 :            : 
     132                 :          0 : BPF_CALL_0(bpf_get_numa_node_id)
     133                 :            : {
     134                 :          0 :         return numa_node_id();
     135                 :            : }
     136                 :            : 
     137                 :            : const struct bpf_func_proto bpf_get_numa_node_id_proto = {
     138                 :            :         .func           = bpf_get_numa_node_id,
     139                 :            :         .gpl_only       = false,
     140                 :            :         .ret_type       = RET_INTEGER,
     141                 :            : };
     142                 :            : 
     143                 :          0 : BPF_CALL_0(bpf_ktime_get_ns)
     144                 :            : {
     145                 :            :         /* NMI safe access to clock monotonic */
     146                 :          0 :         return ktime_get_mono_fast_ns();
     147                 :            : }
     148                 :            : 
     149                 :            : const struct bpf_func_proto bpf_ktime_get_ns_proto = {
     150                 :            :         .func           = bpf_ktime_get_ns,
     151                 :            :         .gpl_only       = true,
     152                 :            :         .ret_type       = RET_INTEGER,
     153                 :            : };
     154                 :            : 
     155                 :          0 : BPF_CALL_0(bpf_get_current_pid_tgid)
     156                 :            : {
     157                 :          0 :         struct task_struct *task = current;
     158                 :            : 
     159         [ #  # ]:          0 :         if (unlikely(!task))
     160                 :            :                 return -EINVAL;
     161                 :            : 
     162                 :          0 :         return (u64) task->tgid << 32 | task->pid;
     163                 :            : }
     164                 :            : 
     165                 :            : const struct bpf_func_proto bpf_get_current_pid_tgid_proto = {
     166                 :            :         .func           = bpf_get_current_pid_tgid,
     167                 :            :         .gpl_only       = false,
     168                 :            :         .ret_type       = RET_INTEGER,
     169                 :            : };
     170                 :            : 
     171                 :          0 : BPF_CALL_0(bpf_get_current_uid_gid)
     172                 :            : {
     173                 :          0 :         struct task_struct *task = current;
     174                 :            :         kuid_t uid;
     175                 :            :         kgid_t gid;
     176                 :            : 
     177         [ #  # ]:          0 :         if (unlikely(!task))
     178                 :            :                 return -EINVAL;
     179                 :            : 
     180                 :          0 :         current_uid_gid(&uid, &gid);
     181                 :          0 :         return (u64) from_kgid(&init_user_ns, gid) << 32 |
     182                 :          0 :                      from_kuid(&init_user_ns, uid);
     183                 :            : }
     184                 :            : 
     185                 :            : const struct bpf_func_proto bpf_get_current_uid_gid_proto = {
     186                 :            :         .func           = bpf_get_current_uid_gid,
     187                 :            :         .gpl_only       = false,
     188                 :            :         .ret_type       = RET_INTEGER,
     189                 :            : };
     190                 :            : 
     191                 :          0 : BPF_CALL_2(bpf_get_current_comm, char *, buf, u32, size)
     192                 :            : {
     193                 :          0 :         struct task_struct *task = current;
     194                 :            : 
     195         [ #  # ]:          0 :         if (unlikely(!task))
     196                 :            :                 goto err_clear;
     197                 :            : 
     198                 :          0 :         strncpy(buf, task->comm, size);
     199                 :            : 
     200                 :            :         /* Verifier guarantees that size > 0. For task->comm exceeding
     201                 :            :          * size, guarantee that buf is %NUL-terminated. Unconditionally
     202                 :            :          * done here to save the size test.
     203                 :            :          */
     204                 :          0 :         buf[size - 1] = 0;
     205                 :            :         return 0;
     206                 :            : err_clear:
     207                 :          0 :         memset(buf, 0, size);
     208                 :            :         return -EINVAL;
     209                 :            : }
     210                 :            : 
     211                 :            : const struct bpf_func_proto bpf_get_current_comm_proto = {
     212                 :            :         .func           = bpf_get_current_comm,
     213                 :            :         .gpl_only       = false,
     214                 :            :         .ret_type       = RET_INTEGER,
     215                 :            :         .arg1_type      = ARG_PTR_TO_UNINIT_MEM,
     216                 :            :         .arg2_type      = ARG_CONST_SIZE,
     217                 :            : };
     218                 :            : 
     219                 :            : #if defined(CONFIG_QUEUED_SPINLOCKS) || defined(CONFIG_BPF_ARCH_SPINLOCK)
     220                 :            : 
     221                 :            : static inline void __bpf_spin_lock(struct bpf_spin_lock *lock)
     222                 :            : {
     223                 :            :         arch_spinlock_t *l = (void *)lock;
     224                 :            :         union {
     225                 :            :                 __u32 val;
     226                 :            :                 arch_spinlock_t lock;
     227                 :            :         } u = { .lock = __ARCH_SPIN_LOCK_UNLOCKED };
     228                 :            : 
     229                 :            :         compiletime_assert(u.val == 0, "__ARCH_SPIN_LOCK_UNLOCKED not 0");
     230                 :            :         BUILD_BUG_ON(sizeof(*l) != sizeof(__u32));
     231                 :            :         BUILD_BUG_ON(sizeof(*lock) != sizeof(__u32));
     232                 :            :         arch_spin_lock(l);
     233                 :            : }
     234                 :            : 
     235                 :            : static inline void __bpf_spin_unlock(struct bpf_spin_lock *lock)
     236                 :            : {
     237                 :            :         arch_spinlock_t *l = (void *)lock;
     238                 :            : 
     239                 :            :         arch_spin_unlock(l);
     240                 :            : }
     241                 :            : 
     242                 :            : #else
     243                 :            : 
     244                 :          0 : static inline void __bpf_spin_lock(struct bpf_spin_lock *lock)
     245                 :            : {
     246                 :            :         atomic_t *l = (void *)lock;
     247                 :            : 
     248                 :            :         BUILD_BUG_ON(sizeof(*l) != sizeof(*lock));
     249                 :            :         do {
     250         [ #  # ]:          0 :                 atomic_cond_read_relaxed(l, !VAL);
     251         [ #  # ]:          0 :         } while (atomic_xchg(l, 1));
     252                 :          0 : }
     253                 :            : 
     254                 :          0 : static inline void __bpf_spin_unlock(struct bpf_spin_lock *lock)
     255                 :            : {
     256                 :            :         atomic_t *l = (void *)lock;
     257                 :            : 
     258                 :            :         atomic_set_release(l, 0);
     259                 :          0 : }
     260                 :            : 
     261                 :            : #endif
     262                 :            : 
     263                 :            : static DEFINE_PER_CPU(unsigned long, irqsave_flags);
     264                 :            : 
     265                 :          0 : notrace BPF_CALL_1(bpf_spin_lock, struct bpf_spin_lock *, lock)
     266                 :            : {
     267                 :            :         unsigned long flags;
     268                 :            : 
     269                 :          0 :         local_irq_save(flags);
     270                 :          0 :         __bpf_spin_lock(lock);
     271                 :          0 :         __this_cpu_write(irqsave_flags, flags);
     272                 :            :         return 0;
     273                 :            : }
     274                 :            : 
     275                 :            : const struct bpf_func_proto bpf_spin_lock_proto = {
     276                 :            :         .func           = bpf_spin_lock,
     277                 :            :         .gpl_only       = false,
     278                 :            :         .ret_type       = RET_VOID,
     279                 :            :         .arg1_type      = ARG_PTR_TO_SPIN_LOCK,
     280                 :            : };
     281                 :            : 
     282                 :          0 : notrace BPF_CALL_1(bpf_spin_unlock, struct bpf_spin_lock *, lock)
     283                 :            : {
     284                 :            :         unsigned long flags;
     285                 :            : 
     286                 :          0 :         flags = __this_cpu_read(irqsave_flags);
     287                 :          0 :         __bpf_spin_unlock(lock);
     288   [ #  #  #  # ]:          0 :         local_irq_restore(flags);
     289                 :            :         return 0;
     290                 :            : }
     291                 :            : 
     292                 :            : const struct bpf_func_proto bpf_spin_unlock_proto = {
     293                 :            :         .func           = bpf_spin_unlock,
     294                 :            :         .gpl_only       = false,
     295                 :            :         .ret_type       = RET_VOID,
     296                 :            :         .arg1_type      = ARG_PTR_TO_SPIN_LOCK,
     297                 :            : };
     298                 :            : 
     299                 :          0 : void copy_map_value_locked(struct bpf_map *map, void *dst, void *src,
     300                 :            :                            bool lock_src)
     301                 :            : {
     302                 :            :         struct bpf_spin_lock *lock;
     303                 :            : 
     304         [ #  # ]:          0 :         if (lock_src)
     305                 :          0 :                 lock = src + map->spin_lock_off;
     306                 :            :         else
     307                 :          0 :                 lock = dst + map->spin_lock_off;
     308                 :          0 :         preempt_disable();
     309                 :            :         ____bpf_spin_lock(lock);
     310                 :          0 :         copy_map_value(map, dst, src);
     311                 :            :         ____bpf_spin_unlock(lock);
     312                 :          0 :         preempt_enable();
     313                 :          0 : }
     314                 :            : 
     315                 :            : #ifdef CONFIG_CGROUPS
     316                 :          0 : BPF_CALL_0(bpf_get_current_cgroup_id)
     317                 :            : {
     318                 :          0 :         struct cgroup *cgrp = task_dfl_cgroup(current);
     319                 :            : 
     320                 :          0 :         return cgrp->kn->id.id;
     321                 :            : }
     322                 :            : 
     323                 :            : const struct bpf_func_proto bpf_get_current_cgroup_id_proto = {
     324                 :            :         .func           = bpf_get_current_cgroup_id,
     325                 :            :         .gpl_only       = false,
     326                 :            :         .ret_type       = RET_INTEGER,
     327                 :            : };
     328                 :            : 
     329                 :            : #ifdef CONFIG_CGROUP_BPF
     330                 :            : DECLARE_PER_CPU(struct bpf_cgroup_storage*,
     331                 :            :                 bpf_cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE]);
     332                 :            : 
     333                 :          0 : BPF_CALL_2(bpf_get_local_storage, struct bpf_map *, map, u64, flags)
     334                 :            : {
     335                 :            :         /* flags argument is not used now,
     336                 :            :          * but provides an ability to extend the API.
     337                 :            :          * verifier checks that its value is correct.
     338                 :            :          */
     339                 :          0 :         enum bpf_cgroup_storage_type stype = cgroup_storage_type(map);
     340                 :            :         struct bpf_cgroup_storage *storage;
     341                 :            :         void *ptr;
     342                 :            : 
     343                 :          0 :         storage = this_cpu_read(bpf_cgroup_storage[stype]);
     344                 :            : 
     345         [ #  # ]:          0 :         if (stype == BPF_CGROUP_STORAGE_SHARED)
     346                 :          0 :                 ptr = &READ_ONCE(storage->buf)->data[0];
     347                 :            :         else
     348                 :          0 :                 ptr = this_cpu_ptr(storage->percpu_buf);
     349                 :            : 
     350                 :          0 :         return (unsigned long)ptr;
     351                 :            : }
     352                 :            : 
     353                 :            : const struct bpf_func_proto bpf_get_local_storage_proto = {
     354                 :            :         .func           = bpf_get_local_storage,
     355                 :            :         .gpl_only       = false,
     356                 :            :         .ret_type       = RET_PTR_TO_MAP_VALUE,
     357                 :            :         .arg1_type      = ARG_CONST_MAP_PTR,
     358                 :            :         .arg2_type      = ARG_ANYTHING,
     359                 :            : };
     360                 :            : #endif
     361                 :            : 
     362                 :            : #define BPF_STRTOX_BASE_MASK 0x1F
     363                 :            : 
     364                 :          0 : static int __bpf_strtoull(const char *buf, size_t buf_len, u64 flags,
     365                 :            :                           unsigned long long *res, bool *is_negative)
     366                 :            : {
     367                 :          0 :         unsigned int base = flags & BPF_STRTOX_BASE_MASK;
     368                 :            :         const char *cur_buf = buf;
     369                 :            :         size_t cur_len = buf_len;
     370                 :            :         unsigned int consumed;
     371                 :            :         size_t val_len;
     372                 :            :         char str[64];
     373                 :            : 
     374   [ #  #  #  # ]:          0 :         if (!buf || !buf_len || !res || !is_negative)
     375                 :            :                 return -EINVAL;
     376                 :            : 
     377   [ #  #  #  # ]:          0 :         if (base != 0 && base != 8 && base != 10 && base != 16)
     378                 :            :                 return -EINVAL;
     379                 :            : 
     380         [ #  # ]:          0 :         if (flags & ~BPF_STRTOX_BASE_MASK)
     381                 :            :                 return -EINVAL;
     382                 :            : 
     383   [ #  #  #  # ]:          0 :         while (cur_buf < buf + buf_len && isspace(*cur_buf))
     384                 :          0 :                 ++cur_buf;
     385                 :            : 
     386   [ #  #  #  # ]:          0 :         *is_negative = (cur_buf < buf + buf_len && *cur_buf == '-');
     387         [ #  # ]:          0 :         if (*is_negative)
     388                 :          0 :                 ++cur_buf;
     389                 :            : 
     390                 :          0 :         consumed = cur_buf - buf;
     391                 :          0 :         cur_len -= consumed;
     392         [ #  # ]:          0 :         if (!cur_len)
     393                 :            :                 return -EINVAL;
     394                 :            : 
     395                 :          0 :         cur_len = min(cur_len, sizeof(str) - 1);
     396                 :          0 :         memcpy(str, cur_buf, cur_len);
     397                 :          0 :         str[cur_len] = '\0';
     398                 :            :         cur_buf = str;
     399                 :            : 
     400                 :          0 :         cur_buf = _parse_integer_fixup_radix(cur_buf, &base);
     401                 :          0 :         val_len = _parse_integer(cur_buf, base, res);
     402                 :            : 
     403         [ #  # ]:          0 :         if (val_len & KSTRTOX_OVERFLOW)
     404                 :            :                 return -ERANGE;
     405                 :            : 
     406         [ #  # ]:          0 :         if (val_len == 0)
     407                 :            :                 return -EINVAL;
     408                 :            : 
     409                 :          0 :         cur_buf += val_len;
     410                 :          0 :         consumed += cur_buf - str;
     411                 :            : 
     412                 :          0 :         return consumed;
     413                 :            : }
     414                 :            : 
     415                 :          0 : static int __bpf_strtoll(const char *buf, size_t buf_len, u64 flags,
     416                 :            :                          long long *res)
     417                 :            : {
     418                 :            :         unsigned long long _res;
     419                 :            :         bool is_negative;
     420                 :            :         int err;
     421                 :            : 
     422                 :          0 :         err = __bpf_strtoull(buf, buf_len, flags, &_res, &is_negative);
     423         [ #  # ]:          0 :         if (err < 0)
     424                 :            :                 return err;
     425         [ #  # ]:          0 :         if (is_negative) {
     426         [ #  # ]:          0 :                 if ((long long)-_res > 0)
     427                 :            :                         return -ERANGE;
     428                 :          0 :                 *res = -_res;
     429                 :            :         } else {
     430         [ #  # ]:          0 :                 if ((long long)_res < 0)
     431                 :            :                         return -ERANGE;
     432                 :          0 :                 *res = _res;
     433                 :            :         }
     434                 :          0 :         return err;
     435                 :            : }
     436                 :            : 
     437                 :          0 : BPF_CALL_4(bpf_strtol, const char *, buf, size_t, buf_len, u64, flags,
     438                 :            :            long *, res)
     439                 :            : {
     440                 :            :         long long _res;
     441                 :            :         int err;
     442                 :            : 
     443                 :          0 :         err = __bpf_strtoll(buf, buf_len, flags, &_res);
     444         [ #  # ]:          0 :         if (err < 0)
     445                 :          0 :                 return err;
     446         [ #  # ]:          0 :         if (_res != (long)_res)
     447                 :            :                 return -ERANGE;
     448                 :          0 :         *res = _res;
     449                 :          0 :         return err;
     450                 :            : }
     451                 :            : 
     452                 :            : const struct bpf_func_proto bpf_strtol_proto = {
     453                 :            :         .func           = bpf_strtol,
     454                 :            :         .gpl_only       = false,
     455                 :            :         .ret_type       = RET_INTEGER,
     456                 :            :         .arg1_type      = ARG_PTR_TO_MEM,
     457                 :            :         .arg2_type      = ARG_CONST_SIZE,
     458                 :            :         .arg3_type      = ARG_ANYTHING,
     459                 :            :         .arg4_type      = ARG_PTR_TO_LONG,
     460                 :            : };
     461                 :            : 
     462                 :          0 : BPF_CALL_4(bpf_strtoul, const char *, buf, size_t, buf_len, u64, flags,
     463                 :            :            unsigned long *, res)
     464                 :            : {
     465                 :            :         unsigned long long _res;
     466                 :            :         bool is_negative;
     467                 :            :         int err;
     468                 :            : 
     469                 :          0 :         err = __bpf_strtoull(buf, buf_len, flags, &_res, &is_negative);
     470         [ #  # ]:          0 :         if (err < 0)
     471                 :          0 :                 return err;
     472         [ #  # ]:          0 :         if (is_negative)
     473                 :            :                 return -EINVAL;
     474         [ #  # ]:          0 :         if (_res != (unsigned long)_res)
     475                 :            :                 return -ERANGE;
     476                 :          0 :         *res = _res;
     477                 :          0 :         return err;
     478                 :            : }
     479                 :            : 
     480                 :            : const struct bpf_func_proto bpf_strtoul_proto = {
     481                 :            :         .func           = bpf_strtoul,
     482                 :            :         .gpl_only       = false,
     483                 :            :         .ret_type       = RET_INTEGER,
     484                 :            :         .arg1_type      = ARG_PTR_TO_MEM,
     485                 :            :         .arg2_type      = ARG_CONST_SIZE,
     486                 :            :         .arg3_type      = ARG_ANYTHING,
     487                 :            :         .arg4_type      = ARG_PTR_TO_LONG,
     488                 :            : };
     489                 :            : #endif

Generated by: LCOV version 1.14