Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

libbpf: Support expected_attach_type at prog load

Support setting `expected_attach_type` at prog load time in both
`bpf/bpf.h` and `bpf/libbpf.h`.

Since both headers already have API to load programs, new functions are
added not to break backward compatibility for existing ones:
* `bpf_load_program_xattr()` is added to `bpf/bpf.h`;
* `bpf_prog_load_xattr()` is added to `bpf/libbpf.h`.

Both new functions accept structures, `struct bpf_load_program_attr` and
`struct bpf_prog_load_attr` correspondingly, where new fields can be
added in the future w/o changing the API.

Standard `_xattr` suffix is used to name the new API functions.

Since `bpf_load_program_name()` is not used as heavily as
`bpf_load_program()`, it was removed in favor of more generic
`bpf_load_program_xattr()`.

Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>

authored by

Andrey Ignatov and committed by
Daniel Borkmann
d7be143b 5e43f899

+134 -47
+5
tools/include/uapi/linux/bpf.h
··· 296 296 __u32 prog_flags; 297 297 char prog_name[BPF_OBJ_NAME_LEN]; 298 298 __u32 prog_ifindex; /* ifindex of netdev to prep for */ 299 + /* For some prog types expected attach type must be known at 300 + * load time to verify attach type specific parts of prog 301 + * (context accesses, allowed helpers, etc). 302 + */ 303 + __u32 expected_attach_type; 299 304 }; 300 305 301 306 struct { /* anonymous struct used by BPF_OBJ_* commands */
+29 -15
tools/lib/bpf/bpf.c
··· 146 146 -1); 147 147 } 148 148 149 - int bpf_load_program_name(enum bpf_prog_type type, const char *name, 150 - const struct bpf_insn *insns, 151 - size_t insns_cnt, const char *license, 152 - __u32 kern_version, char *log_buf, 153 - size_t log_buf_sz) 149 + int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, 150 + char *log_buf, size_t log_buf_sz) 154 151 { 155 - int fd; 156 152 union bpf_attr attr; 157 - __u32 name_len = name ? strlen(name) : 0; 153 + __u32 name_len; 154 + int fd; 155 + 156 + if (!load_attr) 157 + return -EINVAL; 158 + 159 + name_len = load_attr->name ? strlen(load_attr->name) : 0; 158 160 159 161 bzero(&attr, sizeof(attr)); 160 - attr.prog_type = type; 161 - attr.insn_cnt = (__u32)insns_cnt; 162 - attr.insns = ptr_to_u64(insns); 163 - attr.license = ptr_to_u64(license); 162 + attr.prog_type = load_attr->prog_type; 163 + attr.expected_attach_type = load_attr->expected_attach_type; 164 + attr.insn_cnt = (__u32)load_attr->insns_cnt; 165 + attr.insns = ptr_to_u64(load_attr->insns); 166 + attr.license = ptr_to_u64(load_attr->license); 164 167 attr.log_buf = ptr_to_u64(NULL); 165 168 attr.log_size = 0; 166 169 attr.log_level = 0; 167 - attr.kern_version = kern_version; 168 - memcpy(attr.prog_name, name, min(name_len, BPF_OBJ_NAME_LEN - 1)); 170 + attr.kern_version = load_attr->kern_version; 171 + memcpy(attr.prog_name, load_attr->name, 172 + min(name_len, BPF_OBJ_NAME_LEN - 1)); 169 173 170 174 fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); 171 175 if (fd >= 0 || !log_buf || !log_buf_sz) ··· 188 184 __u32 kern_version, char *log_buf, 189 185 size_t log_buf_sz) 190 186 { 191 - return bpf_load_program_name(type, NULL, insns, insns_cnt, license, 192 - kern_version, log_buf, log_buf_sz); 187 + struct bpf_load_program_attr load_attr; 188 + 189 + memset(&load_attr, 0, sizeof(struct bpf_load_program_attr)); 190 + load_attr.prog_type = type; 191 + load_attr.expected_attach_type = 0; 192 + load_attr.name = NULL; 193 + load_attr.insns = insns; 194 + load_attr.insns_cnt = insns_cnt; 195 + load_attr.license = license; 196 + load_attr.kern_version = kern_version; 197 + 198 + return bpf_load_program_xattr(&load_attr, log_buf, log_buf_sz); 193 199 } 194 200 195 201 int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns,
+12 -5
tools/lib/bpf/bpf.h
··· 41 41 int key_size, int inner_map_fd, int max_entries, 42 42 __u32 map_flags); 43 43 44 + struct bpf_load_program_attr { 45 + enum bpf_prog_type prog_type; 46 + enum bpf_attach_type expected_attach_type; 47 + const char *name; 48 + const struct bpf_insn *insns; 49 + size_t insns_cnt; 50 + const char *license; 51 + __u32 kern_version; 52 + }; 53 + 44 54 /* Recommend log buffer size */ 45 55 #define BPF_LOG_BUF_SIZE (256 * 1024) 46 - int bpf_load_program_name(enum bpf_prog_type type, const char *name, 47 - const struct bpf_insn *insns, 48 - size_t insns_cnt, const char *license, 49 - __u32 kern_version, char *log_buf, 50 - size_t log_buf_sz); 56 + int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, 57 + char *log_buf, size_t log_buf_sz); 51 58 int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, 52 59 size_t insns_cnt, const char *license, 53 60 __u32 kern_version, char *log_buf,
+80 -27
tools/lib/bpf/libbpf.c
··· 203 203 struct bpf_object *obj; 204 204 void *priv; 205 205 bpf_program_clear_priv_t clear_priv; 206 + 207 + enum bpf_attach_type expected_attach_type; 206 208 }; 207 209 208 210 struct bpf_map { ··· 1164 1162 } 1165 1163 1166 1164 static int 1167 - load_program(enum bpf_prog_type type, const char *name, struct bpf_insn *insns, 1168 - int insns_cnt, char *license, u32 kern_version, int *pfd) 1165 + load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type, 1166 + const char *name, struct bpf_insn *insns, int insns_cnt, 1167 + char *license, u32 kern_version, int *pfd) 1169 1168 { 1170 - int ret; 1169 + struct bpf_load_program_attr load_attr; 1171 1170 char *log_buf; 1171 + int ret; 1172 1172 1173 - if (!insns || !insns_cnt) 1173 + memset(&load_attr, 0, sizeof(struct bpf_load_program_attr)); 1174 + load_attr.prog_type = type; 1175 + load_attr.expected_attach_type = expected_attach_type; 1176 + load_attr.name = name; 1177 + load_attr.insns = insns; 1178 + load_attr.insns_cnt = insns_cnt; 1179 + load_attr.license = license; 1180 + load_attr.kern_version = kern_version; 1181 + 1182 + if (!load_attr.insns || !load_attr.insns_cnt) 1174 1183 return -EINVAL; 1175 1184 1176 1185 log_buf = malloc(BPF_LOG_BUF_SIZE); 1177 1186 if (!log_buf) 1178 1187 pr_warning("Alloc log buffer for bpf loader error, continue without log\n"); 1179 1188 1180 - ret = bpf_load_program_name(type, name, insns, insns_cnt, license, 1181 - kern_version, log_buf, BPF_LOG_BUF_SIZE); 1189 + ret = bpf_load_program_xattr(&load_attr, log_buf, BPF_LOG_BUF_SIZE); 1182 1190 1183 1191 if (ret >= 0) { 1184 1192 *pfd = ret; ··· 1204 1192 pr_warning("-- BEGIN DUMP LOG ---\n"); 1205 1193 pr_warning("\n%s\n", log_buf); 1206 1194 pr_warning("-- END LOG --\n"); 1207 - } else if (insns_cnt >= BPF_MAXINSNS) { 1208 - pr_warning("Program too large (%d insns), at most %d insns\n", 1209 - insns_cnt, BPF_MAXINSNS); 1195 + } else if (load_attr.insns_cnt >= BPF_MAXINSNS) { 1196 + pr_warning("Program too large (%zu insns), at most %d insns\n", 1197 + load_attr.insns_cnt, BPF_MAXINSNS); 1210 1198 ret = -LIBBPF_ERRNO__PROG2BIG; 1211 1199 } else { 1212 1200 /* Wrong program type? */ 1213 - if (type != BPF_PROG_TYPE_KPROBE) { 1201 + if (load_attr.prog_type != BPF_PROG_TYPE_KPROBE) { 1214 1202 int fd; 1215 1203 1216 - fd = bpf_load_program_name(BPF_PROG_TYPE_KPROBE, name, 1217 - insns, insns_cnt, license, 1218 - kern_version, NULL, 0); 1204 + load_attr.prog_type = BPF_PROG_TYPE_KPROBE; 1205 + load_attr.expected_attach_type = 0; 1206 + fd = bpf_load_program_xattr(&load_attr, NULL, 0); 1219 1207 if (fd >= 0) { 1220 1208 close(fd); 1221 1209 ret = -LIBBPF_ERRNO__PROGTYPE; ··· 1259 1247 pr_warning("Program '%s' is inconsistent: nr(%d) != 1\n", 1260 1248 prog->section_name, prog->instances.nr); 1261 1249 } 1262 - err = load_program(prog->type, prog->name, prog->insns, 1263 - prog->insns_cnt, license, kern_version, &fd); 1250 + err = load_program(prog->type, prog->expected_attach_type, 1251 + prog->name, prog->insns, prog->insns_cnt, 1252 + license, kern_version, &fd); 1264 1253 if (!err) 1265 1254 prog->instances.fds[0] = fd; 1266 1255 goto out; ··· 1289 1276 continue; 1290 1277 } 1291 1278 1292 - err = load_program(prog->type, prog->name, 1293 - result.new_insn_ptr, 1279 + err = load_program(prog->type, prog->expected_attach_type, 1280 + prog->name, result.new_insn_ptr, 1294 1281 result.new_insn_cnt, 1295 1282 license, kern_version, &fd); 1296 1283 ··· 1848 1835 BPF_PROG_TYPE_FNS(xdp, BPF_PROG_TYPE_XDP); 1849 1836 BPF_PROG_TYPE_FNS(perf_event, BPF_PROG_TYPE_PERF_EVENT); 1850 1837 1851 - #define BPF_PROG_SEC(string, type) { string, sizeof(string) - 1, type } 1838 + static void bpf_program__set_expected_attach_type(struct bpf_program *prog, 1839 + enum bpf_attach_type type) 1840 + { 1841 + prog->expected_attach_type = type; 1842 + } 1843 + 1844 + #define BPF_PROG_SEC_FULL(string, ptype, atype) \ 1845 + { string, sizeof(string) - 1, ptype, atype } 1846 + 1847 + #define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_FULL(string, ptype, 0) 1848 + 1852 1849 static const struct { 1853 1850 const char *sec; 1854 1851 size_t len; 1855 1852 enum bpf_prog_type prog_type; 1853 + enum bpf_attach_type expected_attach_type; 1856 1854 } section_names[] = { 1857 1855 BPF_PROG_SEC("socket", BPF_PROG_TYPE_SOCKET_FILTER), 1858 1856 BPF_PROG_SEC("kprobe/", BPF_PROG_TYPE_KPROBE), ··· 1883 1859 BPF_PROG_SEC("sk_skb", BPF_PROG_TYPE_SK_SKB), 1884 1860 BPF_PROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG), 1885 1861 }; 1886 - #undef BPF_PROG_SEC 1887 1862 1888 - static enum bpf_prog_type bpf_program__guess_type(struct bpf_program *prog) 1863 + #undef BPF_PROG_SEC 1864 + #undef BPF_PROG_SEC_FULL 1865 + 1866 + static int bpf_program__identify_section(struct bpf_program *prog) 1889 1867 { 1890 1868 int i; 1891 1869 ··· 1897 1871 for (i = 0; i < ARRAY_SIZE(section_names); i++) 1898 1872 if (strncmp(prog->section_name, section_names[i].sec, 1899 1873 section_names[i].len) == 0) 1900 - return section_names[i].prog_type; 1874 + return i; 1901 1875 1902 1876 err: 1903 1877 pr_warning("failed to guess program type based on section name %s\n", 1904 1878 prog->section_name); 1905 1879 1906 - return BPF_PROG_TYPE_UNSPEC; 1880 + return -1; 1907 1881 } 1908 1882 1909 1883 int bpf_map__fd(struct bpf_map *map) ··· 2003 1977 int bpf_prog_load(const char *file, enum bpf_prog_type type, 2004 1978 struct bpf_object **pobj, int *prog_fd) 2005 1979 { 1980 + struct bpf_prog_load_attr attr; 1981 + 1982 + memset(&attr, 0, sizeof(struct bpf_prog_load_attr)); 1983 + attr.file = file; 1984 + attr.prog_type = type; 1985 + attr.expected_attach_type = 0; 1986 + 1987 + return bpf_prog_load_xattr(&attr, pobj, prog_fd); 1988 + } 1989 + 1990 + int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, 1991 + struct bpf_object **pobj, int *prog_fd) 1992 + { 2006 1993 struct bpf_program *prog, *first_prog = NULL; 1994 + enum bpf_attach_type expected_attach_type; 1995 + enum bpf_prog_type prog_type; 2007 1996 struct bpf_object *obj; 1997 + int section_idx; 2008 1998 int err; 2009 1999 2010 - obj = bpf_object__open(file); 2000 + if (!attr) 2001 + return -EINVAL; 2002 + 2003 + obj = bpf_object__open(attr->file); 2011 2004 if (IS_ERR(obj)) 2012 2005 return -ENOENT; 2013 2006 ··· 2035 1990 * If type is not specified, try to guess it based on 2036 1991 * section name. 2037 1992 */ 2038 - if (type == BPF_PROG_TYPE_UNSPEC) { 2039 - type = bpf_program__guess_type(prog); 2040 - if (type == BPF_PROG_TYPE_UNSPEC) { 1993 + prog_type = attr->prog_type; 1994 + expected_attach_type = attr->expected_attach_type; 1995 + if (prog_type == BPF_PROG_TYPE_UNSPEC) { 1996 + section_idx = bpf_program__identify_section(prog); 1997 + if (section_idx < 0) { 2041 1998 bpf_object__close(obj); 2042 1999 return -EINVAL; 2043 2000 } 2001 + prog_type = section_names[section_idx].prog_type; 2002 + expected_attach_type = 2003 + section_names[section_idx].expected_attach_type; 2044 2004 } 2045 2005 2046 - bpf_program__set_type(prog, type); 2006 + bpf_program__set_type(prog, prog_type); 2007 + bpf_program__set_expected_attach_type(prog, 2008 + expected_attach_type); 2009 + 2047 2010 if (prog->idx != obj->efile.text_shndx && !first_prog) 2048 2011 first_prog = prog; 2049 2012 }
+8
tools/lib/bpf/libbpf.h
··· 248 248 249 249 long libbpf_get_error(const void *ptr); 250 250 251 + struct bpf_prog_load_attr { 252 + const char *file; 253 + enum bpf_prog_type prog_type; 254 + enum bpf_attach_type expected_attach_type; 255 + }; 256 + 257 + int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, 258 + struct bpf_object **pobj, int *prog_fd); 251 259 int bpf_prog_load(const char *file, enum bpf_prog_type type, 252 260 struct bpf_object **pobj, int *prog_fd); 253 261