github.com/ubuntu-core/snappy@v0.0.0-20210827154228-9e584df982bb/cmd/libsnap-confine-private/bpf-support.c (about)

     1  /*
     2   * Copyright (C) 2021 Canonical Ltd
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License version 3 as
     6   * published by the Free Software Foundation.
     7   *
     8   * This program is distributed in the hope that it will be useful,
     9   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11   * GNU General Public License for more details.
    12   *
    13   * You should have received a copy of the GNU General Public License
    14   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15   *
    16   */
    17  
    18  #include "bpf-support.h"
    19  
    20  #include <errno.h>
    21  #include <stddef.h>
    22  #include <stdint.h>
    23  #include <string.h>
    24  #include <sys/syscall.h>
    25  #include <unistd.h>
    26  
    27  #include "utils.h"
    28  
    29  static int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr, size_t size) {
    30  #ifdef SYS_bpf
    31      return syscall(SYS_bpf, cmd, attr, size);
    32  #else
    33      errno = ENOSYS;
    34      return -1;
    35  #endif
    36  }
    37  
    38  #define __ptr_as_u64(__x) ((uint64_t)(uintptr_t)__x)
    39  
    40  int bpf_create_map(enum bpf_map_type type, size_t key_size, size_t value_size, size_t max_entries) {
    41      debug("create bpf map of type 0x%x, key size %zu, value size %zu, entries %zu", type, key_size, value_size,
    42            max_entries);
    43      union bpf_attr attr;
    44      memset(&attr, 0, sizeof(attr));
    45      attr.map_type = type;
    46      attr.key_size = key_size;
    47      attr.value_size = value_size;
    48      attr.max_entries = max_entries;
    49      return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
    50  }
    51  
    52  int bpf_update_map(int map_fd, const void *key, const void *value) {
    53      union bpf_attr attr;
    54      memset(&attr, 0, sizeof(attr));
    55      attr.map_fd = map_fd;
    56      attr.key = __ptr_as_u64(key);
    57      attr.value = __ptr_as_u64(value);
    58      /* update or create an existing element */
    59      attr.flags = BPF_ANY;
    60      return sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
    61  }
    62  
    63  int bpf_pin_to_path(int fd, const char *path) {
    64      debug("pin bpf object %d to path %s", fd, path);
    65      union bpf_attr attr;
    66      memset(&attr, 0, sizeof(attr));
    67      attr.bpf_fd = fd;
    68      /* pointer must be converted to a u64 */
    69      attr.pathname = __ptr_as_u64(path);
    70  
    71      return sys_bpf(BPF_OBJ_PIN, &attr, sizeof(attr));
    72  }
    73  
    74  int bpf_get_by_path(const char *path) {
    75      debug("get bpf object at path %s", path);
    76      union bpf_attr attr;
    77      memset(&attr, 0, sizeof(attr));
    78      /* pointer must be converted to a u64 */
    79      attr.pathname = __ptr_as_u64(path);
    80  
    81      return sys_bpf(BPF_OBJ_GET, &attr, sizeof(attr));
    82  }
    83  
    84  int bpf_load_prog(enum bpf_prog_type type, const struct bpf_insn *insns, size_t insns_cnt, char *log_buf,
    85                    size_t log_buf_size) {
    86      if (type == BPF_PROG_TYPE_UNSPEC) {
    87          errno = EINVAL;
    88          return -1;
    89      }
    90      debug("load program of type 0x%x, %zu instructions", type, insns_cnt);
    91      union bpf_attr attr;
    92      memset(&attr, 0, sizeof(attr));
    93      attr.prog_type = type;
    94      attr.insns = __ptr_as_u64(insns);
    95      attr.insn_cnt = (uint64_t)insns_cnt;
    96      attr.license = __ptr_as_u64("GPL");
    97      if (log_buf != NULL) {
    98          attr.log_buf = __ptr_as_u64(log_buf);
    99          attr.log_size = log_buf_size;
   100          attr.log_level = 1;
   101      }
   102  
   103      /* XXX: libbpf does a while loop checking for EAGAIN */
   104      /* XXX: do we need to handle E2BIG? */
   105      return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
   106  }
   107  
   108  int bpf_prog_attach(enum bpf_attach_type type, int cgroup_fd, int prog_fd) {
   109      debug("attach type 0x%x program %d to cgroup %d", type, prog_fd, cgroup_fd);
   110      union bpf_attr attr;
   111      memset(&attr, 0, sizeof(attr));
   112  
   113      attr.attach_type = type;
   114      attr.target_fd = cgroup_fd;
   115      attr.attach_bpf_fd = prog_fd;
   116  
   117      return sys_bpf(BPF_PROG_ATTACH, &attr, sizeof(attr));
   118  }
   119  
   120  int bpf_map_get_next_key(int map_fd, const void *key, void *next_key) {
   121      debug("get next key for map %d", map_fd);
   122      union bpf_attr attr;
   123      memset(&attr, 0, sizeof(attr));
   124  
   125      attr.map_fd = map_fd;
   126      attr.key = __ptr_as_u64(key);
   127      attr.next_key = __ptr_as_u64(next_key);
   128  
   129      return sys_bpf(BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr));
   130  }
   131  
   132  int bpf_map_delete_batch(int map_fd, const void *keys, size_t cnt) {
   133  #if 0
   134  /*
   135   * XXX: batch operations don't seem to work with 5.13.10, getting -EINVAL
   136   * XXX: also batch operations are supported by recent kernels only
   137   */
   138      debug("batch delete in map %d keys cnt %zu", map_fd, cnt);
   139      union bpf_attr attr;
   140      memset(&attr, 0, sizeof(attr));
   141  
   142      attr.map_fd = map_fd;
   143      attr.batch.keys = __ptr_as_u64(keys);
   144      attr.batch.count = cnt;
   145      /* TODO: getting EINVAL? */
   146      int ret = sys_bpf(BPF_MAP_DELETE_BATCH, &attr, sizeof(attr));
   147      debug("returned count %d", attr.batch.count);
   148      return ret;
   149  #endif
   150      errno = ENOSYS;
   151      return -1;
   152  }
   153  
   154  int bpf_map_delete_elem(int map_fd, const void *key) {
   155      debug("delete elem in map %d", map_fd);
   156      union bpf_attr attr;
   157      memset(&attr, 0, sizeof(attr));
   158  
   159      attr.map_fd = map_fd;
   160      attr.key = __ptr_as_u64(key);
   161  
   162      return sys_bpf(BPF_MAP_DELETE_ELEM, &attr, sizeof(attr));
   163  }