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 }