diff options
Diffstat (limited to 'kernel/bpf/syscall.c')
-rw-r--r-- | kernel/bpf/syscall.c | 204 |
1 files changed, 195 insertions, 9 deletions
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index e24aa3241387..ebfe9f29dae8 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c | |||
@@ -203,11 +203,13 @@ static int bpf_map_alloc_id(struct bpf_map *map) | |||
203 | { | 203 | { |
204 | int id; | 204 | int id; |
205 | 205 | ||
206 | idr_preload(GFP_KERNEL); | ||
206 | spin_lock_bh(&map_idr_lock); | 207 | spin_lock_bh(&map_idr_lock); |
207 | id = idr_alloc_cyclic(&map_idr, map, 1, INT_MAX, GFP_ATOMIC); | 208 | id = idr_alloc_cyclic(&map_idr, map, 1, INT_MAX, GFP_ATOMIC); |
208 | if (id > 0) | 209 | if (id > 0) |
209 | map->id = id; | 210 | map->id = id; |
210 | spin_unlock_bh(&map_idr_lock); | 211 | spin_unlock_bh(&map_idr_lock); |
212 | idr_preload_end(); | ||
211 | 213 | ||
212 | if (WARN_ON_ONCE(!id)) | 214 | if (WARN_ON_ONCE(!id)) |
213 | return -ENOSPC; | 215 | return -ENOSPC; |
@@ -255,8 +257,8 @@ static void bpf_map_free_deferred(struct work_struct *work) | |||
255 | static void bpf_map_put_uref(struct bpf_map *map) | 257 | static void bpf_map_put_uref(struct bpf_map *map) |
256 | { | 258 | { |
257 | if (atomic_dec_and_test(&map->usercnt)) { | 259 | if (atomic_dec_and_test(&map->usercnt)) { |
258 | if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) | 260 | if (map->ops->map_release_uref) |
259 | bpf_fd_array_map_clear(map); | 261 | map->ops->map_release_uref(map); |
260 | } | 262 | } |
261 | } | 263 | } |
262 | 264 | ||
@@ -940,11 +942,13 @@ static int bpf_prog_alloc_id(struct bpf_prog *prog) | |||
940 | { | 942 | { |
941 | int id; | 943 | int id; |
942 | 944 | ||
945 | idr_preload(GFP_KERNEL); | ||
943 | spin_lock_bh(&prog_idr_lock); | 946 | spin_lock_bh(&prog_idr_lock); |
944 | id = idr_alloc_cyclic(&prog_idr, prog, 1, INT_MAX, GFP_ATOMIC); | 947 | id = idr_alloc_cyclic(&prog_idr, prog, 1, INT_MAX, GFP_ATOMIC); |
945 | if (id > 0) | 948 | if (id > 0) |
946 | prog->aux->id = id; | 949 | prog->aux->id = id; |
947 | spin_unlock_bh(&prog_idr_lock); | 950 | spin_unlock_bh(&prog_idr_lock); |
951 | idr_preload_end(); | ||
948 | 952 | ||
949 | /* id is in [1, INT_MAX) */ | 953 | /* id is in [1, INT_MAX) */ |
950 | if (WARN_ON_ONCE(!id)) | 954 | if (WARN_ON_ONCE(!id)) |
@@ -1167,8 +1171,63 @@ struct bpf_prog *bpf_prog_get_type_dev(u32 ufd, enum bpf_prog_type type, | |||
1167 | } | 1171 | } |
1168 | EXPORT_SYMBOL_GPL(bpf_prog_get_type_dev); | 1172 | EXPORT_SYMBOL_GPL(bpf_prog_get_type_dev); |
1169 | 1173 | ||
1174 | /* Initially all BPF programs could be loaded w/o specifying | ||
1175 | * expected_attach_type. Later for some of them specifying expected_attach_type | ||
1176 | * at load time became required so that program could be validated properly. | ||
1177 | * Programs of types that are allowed to be loaded both w/ and w/o (for | ||
1178 | * backward compatibility) expected_attach_type, should have the default attach | ||
1179 | * type assigned to expected_attach_type for the latter case, so that it can be | ||
1180 | * validated later at attach time. | ||
1181 | * | ||
1182 | * bpf_prog_load_fixup_attach_type() sets expected_attach_type in @attr if | ||
1183 | * prog type requires it but has some attach types that have to be backward | ||
1184 | * compatible. | ||
1185 | */ | ||
1186 | static void bpf_prog_load_fixup_attach_type(union bpf_attr *attr) | ||
1187 | { | ||
1188 | switch (attr->prog_type) { | ||
1189 | case BPF_PROG_TYPE_CGROUP_SOCK: | ||
1190 | /* Unfortunately BPF_ATTACH_TYPE_UNSPEC enumeration doesn't | ||
1191 | * exist so checking for non-zero is the way to go here. | ||
1192 | */ | ||
1193 | if (!attr->expected_attach_type) | ||
1194 | attr->expected_attach_type = | ||
1195 | BPF_CGROUP_INET_SOCK_CREATE; | ||
1196 | break; | ||
1197 | } | ||
1198 | } | ||
1199 | |||
1200 | static int | ||
1201 | bpf_prog_load_check_attach_type(enum bpf_prog_type prog_type, | ||
1202 | enum bpf_attach_type expected_attach_type) | ||
1203 | { | ||
1204 | switch (prog_type) { | ||
1205 | case BPF_PROG_TYPE_CGROUP_SOCK: | ||
1206 | switch (expected_attach_type) { | ||
1207 | case BPF_CGROUP_INET_SOCK_CREATE: | ||
1208 | case BPF_CGROUP_INET4_POST_BIND: | ||
1209 | case BPF_CGROUP_INET6_POST_BIND: | ||
1210 | return 0; | ||
1211 | default: | ||
1212 | return -EINVAL; | ||
1213 | } | ||
1214 | case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: | ||
1215 | switch (expected_attach_type) { | ||
1216 | case BPF_CGROUP_INET4_BIND: | ||
1217 | case BPF_CGROUP_INET6_BIND: | ||
1218 | case BPF_CGROUP_INET4_CONNECT: | ||
1219 | case BPF_CGROUP_INET6_CONNECT: | ||
1220 | return 0; | ||
1221 | default: | ||
1222 | return -EINVAL; | ||
1223 | } | ||
1224 | default: | ||
1225 | return 0; | ||
1226 | } | ||
1227 | } | ||
1228 | |||
1170 | /* last field in 'union bpf_attr' used by this command */ | 1229 | /* last field in 'union bpf_attr' used by this command */ |
1171 | #define BPF_PROG_LOAD_LAST_FIELD prog_ifindex | 1230 | #define BPF_PROG_LOAD_LAST_FIELD expected_attach_type |
1172 | 1231 | ||
1173 | static int bpf_prog_load(union bpf_attr *attr) | 1232 | static int bpf_prog_load(union bpf_attr *attr) |
1174 | { | 1233 | { |
@@ -1205,11 +1264,17 @@ static int bpf_prog_load(union bpf_attr *attr) | |||
1205 | !capable(CAP_SYS_ADMIN)) | 1264 | !capable(CAP_SYS_ADMIN)) |
1206 | return -EPERM; | 1265 | return -EPERM; |
1207 | 1266 | ||
1267 | bpf_prog_load_fixup_attach_type(attr); | ||
1268 | if (bpf_prog_load_check_attach_type(type, attr->expected_attach_type)) | ||
1269 | return -EINVAL; | ||
1270 | |||
1208 | /* plain bpf_prog allocation */ | 1271 | /* plain bpf_prog allocation */ |
1209 | prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER); | 1272 | prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER); |
1210 | if (!prog) | 1273 | if (!prog) |
1211 | return -ENOMEM; | 1274 | return -ENOMEM; |
1212 | 1275 | ||
1276 | prog->expected_attach_type = attr->expected_attach_type; | ||
1277 | |||
1213 | prog->aux->offload_requested = !!attr->prog_ifindex; | 1278 | prog->aux->offload_requested = !!attr->prog_ifindex; |
1214 | 1279 | ||
1215 | err = security_bpf_prog_alloc(prog->aux); | 1280 | err = security_bpf_prog_alloc(prog->aux); |
@@ -1311,11 +1376,99 @@ static int bpf_obj_get(const union bpf_attr *attr) | |||
1311 | attr->file_flags); | 1376 | attr->file_flags); |
1312 | } | 1377 | } |
1313 | 1378 | ||
1379 | struct bpf_raw_tracepoint { | ||
1380 | struct bpf_raw_event_map *btp; | ||
1381 | struct bpf_prog *prog; | ||
1382 | }; | ||
1383 | |||
1384 | static int bpf_raw_tracepoint_release(struct inode *inode, struct file *filp) | ||
1385 | { | ||
1386 | struct bpf_raw_tracepoint *raw_tp = filp->private_data; | ||
1387 | |||
1388 | if (raw_tp->prog) { | ||
1389 | bpf_probe_unregister(raw_tp->btp, raw_tp->prog); | ||
1390 | bpf_prog_put(raw_tp->prog); | ||
1391 | } | ||
1392 | kfree(raw_tp); | ||
1393 | return 0; | ||
1394 | } | ||
1395 | |||
1396 | static const struct file_operations bpf_raw_tp_fops = { | ||
1397 | .release = bpf_raw_tracepoint_release, | ||
1398 | .read = bpf_dummy_read, | ||
1399 | .write = bpf_dummy_write, | ||
1400 | }; | ||
1401 | |||
1402 | #define BPF_RAW_TRACEPOINT_OPEN_LAST_FIELD raw_tracepoint.prog_fd | ||
1403 | |||
1404 | static int bpf_raw_tracepoint_open(const union bpf_attr *attr) | ||
1405 | { | ||
1406 | struct bpf_raw_tracepoint *raw_tp; | ||
1407 | struct bpf_raw_event_map *btp; | ||
1408 | struct bpf_prog *prog; | ||
1409 | char tp_name[128]; | ||
1410 | int tp_fd, err; | ||
1411 | |||
1412 | if (strncpy_from_user(tp_name, u64_to_user_ptr(attr->raw_tracepoint.name), | ||
1413 | sizeof(tp_name) - 1) < 0) | ||
1414 | return -EFAULT; | ||
1415 | tp_name[sizeof(tp_name) - 1] = 0; | ||
1416 | |||
1417 | btp = bpf_find_raw_tracepoint(tp_name); | ||
1418 | if (!btp) | ||
1419 | return -ENOENT; | ||
1420 | |||
1421 | raw_tp = kzalloc(sizeof(*raw_tp), GFP_USER); | ||
1422 | if (!raw_tp) | ||
1423 | return -ENOMEM; | ||
1424 | raw_tp->btp = btp; | ||
1425 | |||
1426 | prog = bpf_prog_get_type(attr->raw_tracepoint.prog_fd, | ||
1427 | BPF_PROG_TYPE_RAW_TRACEPOINT); | ||
1428 | if (IS_ERR(prog)) { | ||
1429 | err = PTR_ERR(prog); | ||
1430 | goto out_free_tp; | ||
1431 | } | ||
1432 | |||
1433 | err = bpf_probe_register(raw_tp->btp, prog); | ||
1434 | if (err) | ||
1435 | goto out_put_prog; | ||
1436 | |||
1437 | raw_tp->prog = prog; | ||
1438 | tp_fd = anon_inode_getfd("bpf-raw-tracepoint", &bpf_raw_tp_fops, raw_tp, | ||
1439 | O_CLOEXEC); | ||
1440 | if (tp_fd < 0) { | ||
1441 | bpf_probe_unregister(raw_tp->btp, prog); | ||
1442 | err = tp_fd; | ||
1443 | goto out_put_prog; | ||
1444 | } | ||
1445 | return tp_fd; | ||
1446 | |||
1447 | out_put_prog: | ||
1448 | bpf_prog_put(prog); | ||
1449 | out_free_tp: | ||
1450 | kfree(raw_tp); | ||
1451 | return err; | ||
1452 | } | ||
1453 | |||
1314 | #ifdef CONFIG_CGROUP_BPF | 1454 | #ifdef CONFIG_CGROUP_BPF |
1315 | 1455 | ||
1456 | static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog, | ||
1457 | enum bpf_attach_type attach_type) | ||
1458 | { | ||
1459 | switch (prog->type) { | ||
1460 | case BPF_PROG_TYPE_CGROUP_SOCK: | ||
1461 | case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: | ||
1462 | return attach_type == prog->expected_attach_type ? 0 : -EINVAL; | ||
1463 | default: | ||
1464 | return 0; | ||
1465 | } | ||
1466 | } | ||
1467 | |||
1316 | #define BPF_PROG_ATTACH_LAST_FIELD attach_flags | 1468 | #define BPF_PROG_ATTACH_LAST_FIELD attach_flags |
1317 | 1469 | ||
1318 | static int sockmap_get_from_fd(const union bpf_attr *attr, bool attach) | 1470 | static int sockmap_get_from_fd(const union bpf_attr *attr, |
1471 | int type, bool attach) | ||
1319 | { | 1472 | { |
1320 | struct bpf_prog *prog = NULL; | 1473 | struct bpf_prog *prog = NULL; |
1321 | int ufd = attr->target_fd; | 1474 | int ufd = attr->target_fd; |
@@ -1329,8 +1482,7 @@ static int sockmap_get_from_fd(const union bpf_attr *attr, bool attach) | |||
1329 | return PTR_ERR(map); | 1482 | return PTR_ERR(map); |
1330 | 1483 | ||
1331 | if (attach) { | 1484 | if (attach) { |
1332 | prog = bpf_prog_get_type(attr->attach_bpf_fd, | 1485 | prog = bpf_prog_get_type(attr->attach_bpf_fd, type); |
1333 | BPF_PROG_TYPE_SK_SKB); | ||
1334 | if (IS_ERR(prog)) { | 1486 | if (IS_ERR(prog)) { |
1335 | fdput(f); | 1487 | fdput(f); |
1336 | return PTR_ERR(prog); | 1488 | return PTR_ERR(prog); |
@@ -1374,17 +1526,27 @@ static int bpf_prog_attach(const union bpf_attr *attr) | |||
1374 | ptype = BPF_PROG_TYPE_CGROUP_SKB; | 1526 | ptype = BPF_PROG_TYPE_CGROUP_SKB; |
1375 | break; | 1527 | break; |
1376 | case BPF_CGROUP_INET_SOCK_CREATE: | 1528 | case BPF_CGROUP_INET_SOCK_CREATE: |
1529 | case BPF_CGROUP_INET4_POST_BIND: | ||
1530 | case BPF_CGROUP_INET6_POST_BIND: | ||
1377 | ptype = BPF_PROG_TYPE_CGROUP_SOCK; | 1531 | ptype = BPF_PROG_TYPE_CGROUP_SOCK; |
1378 | break; | 1532 | break; |
1533 | case BPF_CGROUP_INET4_BIND: | ||
1534 | case BPF_CGROUP_INET6_BIND: | ||
1535 | case BPF_CGROUP_INET4_CONNECT: | ||
1536 | case BPF_CGROUP_INET6_CONNECT: | ||
1537 | ptype = BPF_PROG_TYPE_CGROUP_SOCK_ADDR; | ||
1538 | break; | ||
1379 | case BPF_CGROUP_SOCK_OPS: | 1539 | case BPF_CGROUP_SOCK_OPS: |
1380 | ptype = BPF_PROG_TYPE_SOCK_OPS; | 1540 | ptype = BPF_PROG_TYPE_SOCK_OPS; |
1381 | break; | 1541 | break; |
1382 | case BPF_CGROUP_DEVICE: | 1542 | case BPF_CGROUP_DEVICE: |
1383 | ptype = BPF_PROG_TYPE_CGROUP_DEVICE; | 1543 | ptype = BPF_PROG_TYPE_CGROUP_DEVICE; |
1384 | break; | 1544 | break; |
1545 | case BPF_SK_MSG_VERDICT: | ||
1546 | return sockmap_get_from_fd(attr, BPF_PROG_TYPE_SK_MSG, true); | ||
1385 | case BPF_SK_SKB_STREAM_PARSER: | 1547 | case BPF_SK_SKB_STREAM_PARSER: |
1386 | case BPF_SK_SKB_STREAM_VERDICT: | 1548 | case BPF_SK_SKB_STREAM_VERDICT: |
1387 | return sockmap_get_from_fd(attr, true); | 1549 | return sockmap_get_from_fd(attr, BPF_PROG_TYPE_SK_SKB, true); |
1388 | default: | 1550 | default: |
1389 | return -EINVAL; | 1551 | return -EINVAL; |
1390 | } | 1552 | } |
@@ -1393,6 +1555,11 @@ static int bpf_prog_attach(const union bpf_attr *attr) | |||
1393 | if (IS_ERR(prog)) | 1555 | if (IS_ERR(prog)) |
1394 | return PTR_ERR(prog); | 1556 | return PTR_ERR(prog); |
1395 | 1557 | ||
1558 | if (bpf_prog_attach_check_attach_type(prog, attr->attach_type)) { | ||
1559 | bpf_prog_put(prog); | ||
1560 | return -EINVAL; | ||
1561 | } | ||
1562 | |||
1396 | cgrp = cgroup_get_from_fd(attr->target_fd); | 1563 | cgrp = cgroup_get_from_fd(attr->target_fd); |
1397 | if (IS_ERR(cgrp)) { | 1564 | if (IS_ERR(cgrp)) { |
1398 | bpf_prog_put(prog); | 1565 | bpf_prog_put(prog); |
@@ -1429,17 +1596,27 @@ static int bpf_prog_detach(const union bpf_attr *attr) | |||
1429 | ptype = BPF_PROG_TYPE_CGROUP_SKB; | 1596 | ptype = BPF_PROG_TYPE_CGROUP_SKB; |
1430 | break; | 1597 | break; |
1431 | case BPF_CGROUP_INET_SOCK_CREATE: | 1598 | case BPF_CGROUP_INET_SOCK_CREATE: |
1599 | case BPF_CGROUP_INET4_POST_BIND: | ||
1600 | case BPF_CGROUP_INET6_POST_BIND: | ||
1432 | ptype = BPF_PROG_TYPE_CGROUP_SOCK; | 1601 | ptype = BPF_PROG_TYPE_CGROUP_SOCK; |
1433 | break; | 1602 | break; |
1603 | case BPF_CGROUP_INET4_BIND: | ||
1604 | case BPF_CGROUP_INET6_BIND: | ||
1605 | case BPF_CGROUP_INET4_CONNECT: | ||
1606 | case BPF_CGROUP_INET6_CONNECT: | ||
1607 | ptype = BPF_PROG_TYPE_CGROUP_SOCK_ADDR; | ||
1608 | break; | ||
1434 | case BPF_CGROUP_SOCK_OPS: | 1609 | case BPF_CGROUP_SOCK_OPS: |
1435 | ptype = BPF_PROG_TYPE_SOCK_OPS; | 1610 | ptype = BPF_PROG_TYPE_SOCK_OPS; |
1436 | break; | 1611 | break; |
1437 | case BPF_CGROUP_DEVICE: | 1612 | case BPF_CGROUP_DEVICE: |
1438 | ptype = BPF_PROG_TYPE_CGROUP_DEVICE; | 1613 | ptype = BPF_PROG_TYPE_CGROUP_DEVICE; |
1439 | break; | 1614 | break; |
1615 | case BPF_SK_MSG_VERDICT: | ||
1616 | return sockmap_get_from_fd(attr, BPF_PROG_TYPE_SK_MSG, false); | ||
1440 | case BPF_SK_SKB_STREAM_PARSER: | 1617 | case BPF_SK_SKB_STREAM_PARSER: |
1441 | case BPF_SK_SKB_STREAM_VERDICT: | 1618 | case BPF_SK_SKB_STREAM_VERDICT: |
1442 | return sockmap_get_from_fd(attr, false); | 1619 | return sockmap_get_from_fd(attr, BPF_PROG_TYPE_SK_SKB, false); |
1443 | default: | 1620 | default: |
1444 | return -EINVAL; | 1621 | return -EINVAL; |
1445 | } | 1622 | } |
@@ -1478,6 +1655,12 @@ static int bpf_prog_query(const union bpf_attr *attr, | |||
1478 | case BPF_CGROUP_INET_INGRESS: | 1655 | case BPF_CGROUP_INET_INGRESS: |
1479 | case BPF_CGROUP_INET_EGRESS: | 1656 | case BPF_CGROUP_INET_EGRESS: |
1480 | case BPF_CGROUP_INET_SOCK_CREATE: | 1657 | case BPF_CGROUP_INET_SOCK_CREATE: |
1658 | case BPF_CGROUP_INET4_BIND: | ||
1659 | case BPF_CGROUP_INET6_BIND: | ||
1660 | case BPF_CGROUP_INET4_POST_BIND: | ||
1661 | case BPF_CGROUP_INET6_POST_BIND: | ||
1662 | case BPF_CGROUP_INET4_CONNECT: | ||
1663 | case BPF_CGROUP_INET6_CONNECT: | ||
1481 | case BPF_CGROUP_SOCK_OPS: | 1664 | case BPF_CGROUP_SOCK_OPS: |
1482 | case BPF_CGROUP_DEVICE: | 1665 | case BPF_CGROUP_DEVICE: |
1483 | break; | 1666 | break; |
@@ -1845,7 +2028,7 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz | |||
1845 | union bpf_attr attr = {}; | 2028 | union bpf_attr attr = {}; |
1846 | int err; | 2029 | int err; |
1847 | 2030 | ||
1848 | if (!capable(CAP_SYS_ADMIN) && sysctl_unprivileged_bpf_disabled) | 2031 | if (sysctl_unprivileged_bpf_disabled && !capable(CAP_SYS_ADMIN)) |
1849 | return -EPERM; | 2032 | return -EPERM; |
1850 | 2033 | ||
1851 | err = check_uarg_tail_zero(uattr, sizeof(attr), size); | 2034 | err = check_uarg_tail_zero(uattr, sizeof(attr), size); |
@@ -1917,6 +2100,9 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz | |||
1917 | case BPF_OBJ_GET_INFO_BY_FD: | 2100 | case BPF_OBJ_GET_INFO_BY_FD: |
1918 | err = bpf_obj_get_info_by_fd(&attr, uattr); | 2101 | err = bpf_obj_get_info_by_fd(&attr, uattr); |
1919 | break; | 2102 | break; |
2103 | case BPF_RAW_TRACEPOINT_OPEN: | ||
2104 | err = bpf_raw_tracepoint_open(&attr); | ||
2105 | break; | ||
1920 | default: | 2106 | default: |
1921 | err = -EINVAL; | 2107 | err = -EINVAL; |
1922 | break; | 2108 | break; |