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

bpf: add support for sockmap detach programs

The bpf map sockmap supports adding programs via attach commands. This
patch adds the detach command to keep the API symmetric and allow
users to remove previously added programs. Otherwise the user would
have to delete the map and re-add it to get in this state.

This also adds a series of additional tests to capture detach operation
and also attaching/detaching invalid prog types.

API note: socks will run (or not run) programs depending on the state
of the map at the time the sock is added. We do not for example walk
the map and remove programs from previously attached socks.

Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

John Fastabend and committed by
David S. Miller
5a67da2a bbbe211c

+72 -16
+4 -4
include/linux/bpf.h
··· 385 385 386 386 #if defined(CONFIG_STREAM_PARSER) && defined(CONFIG_BPF_SYSCALL) 387 387 struct sock *__sock_map_lookup_elem(struct bpf_map *map, u32 key); 388 - int sock_map_attach_prog(struct bpf_map *map, struct bpf_prog *prog, u32 type); 388 + int sock_map_prog(struct bpf_map *map, struct bpf_prog *prog, u32 type); 389 389 #else 390 390 static inline struct sock *__sock_map_lookup_elem(struct bpf_map *map, u32 key) 391 391 { 392 392 return NULL; 393 393 } 394 394 395 - static inline int sock_map_attach_prog(struct bpf_map *map, 396 - struct bpf_prog *prog, 397 - u32 type) 395 + static inline int sock_map_prog(struct bpf_map *map, 396 + struct bpf_prog *prog, 397 + u32 type) 398 398 { 399 399 return -EOPNOTSUPP; 400 400 }
+1 -1
kernel/bpf/sockmap.c
··· 792 792 return err; 793 793 } 794 794 795 - int sock_map_attach_prog(struct bpf_map *map, struct bpf_prog *prog, u32 type) 795 + int sock_map_prog(struct bpf_map *map, struct bpf_prog *prog, u32 type) 796 796 { 797 797 struct bpf_stab *stab = container_of(map, struct bpf_stab, map); 798 798 struct bpf_prog *orig;
+17 -10
kernel/bpf/syscall.c
··· 1096 1096 1097 1097 #define BPF_PROG_ATTACH_LAST_FIELD attach_flags 1098 1098 1099 - static int sockmap_get_from_fd(const union bpf_attr *attr) 1099 + static int sockmap_get_from_fd(const union bpf_attr *attr, bool attach) 1100 1100 { 1101 + struct bpf_prog *prog = NULL; 1101 1102 int ufd = attr->target_fd; 1102 - struct bpf_prog *prog; 1103 1103 struct bpf_map *map; 1104 1104 struct fd f; 1105 1105 int err; ··· 1109 1109 if (IS_ERR(map)) 1110 1110 return PTR_ERR(map); 1111 1111 1112 - prog = bpf_prog_get_type(attr->attach_bpf_fd, BPF_PROG_TYPE_SK_SKB); 1113 - if (IS_ERR(prog)) { 1114 - fdput(f); 1115 - return PTR_ERR(prog); 1112 + if (attach) { 1113 + prog = bpf_prog_get_type(attr->attach_bpf_fd, 1114 + BPF_PROG_TYPE_SK_SKB); 1115 + if (IS_ERR(prog)) { 1116 + fdput(f); 1117 + return PTR_ERR(prog); 1118 + } 1116 1119 } 1117 1120 1118 - err = sock_map_attach_prog(map, prog, attr->attach_type); 1121 + err = sock_map_prog(map, prog, attr->attach_type); 1119 1122 if (err) { 1120 1123 fdput(f); 1121 - bpf_prog_put(prog); 1124 + if (prog) 1125 + bpf_prog_put(prog); 1122 1126 return err; 1123 1127 } 1124 1128 ··· 1159 1155 break; 1160 1156 case BPF_SK_SKB_STREAM_PARSER: 1161 1157 case BPF_SK_SKB_STREAM_VERDICT: 1162 - return sockmap_get_from_fd(attr); 1158 + return sockmap_get_from_fd(attr, true); 1163 1159 default: 1164 1160 return -EINVAL; 1165 1161 } ··· 1208 1204 ret = cgroup_bpf_update(cgrp, NULL, attr->attach_type, false); 1209 1205 cgroup_put(cgrp); 1210 1206 break; 1211 - 1207 + case BPF_SK_SKB_STREAM_PARSER: 1208 + case BPF_SK_SKB_STREAM_VERDICT: 1209 + ret = sockmap_get_from_fd(attr, false); 1210 + break; 1212 1211 default: 1213 1212 return -EINVAL; 1214 1213 }
+50 -1
tools/testing/selftests/bpf/test_maps.c
··· 558 558 } 559 559 } 560 560 561 - /* Test attaching bad fds */ 561 + /* Test attaching/detaching bad fds */ 562 562 err = bpf_prog_attach(-1, fd, BPF_SK_SKB_STREAM_PARSER, 0); 563 563 if (!err) { 564 564 printf("Failed invalid parser prog attach\n"); ··· 568 568 err = bpf_prog_attach(-1, fd, BPF_SK_SKB_STREAM_VERDICT, 0); 569 569 if (!err) { 570 570 printf("Failed invalid verdict prog attach\n"); 571 + goto out_sockmap; 572 + } 573 + 574 + err = bpf_prog_attach(-1, fd, __MAX_BPF_ATTACH_TYPE, 0); 575 + if (!err) { 576 + printf("Failed unknown prog attach\n"); 577 + goto out_sockmap; 578 + } 579 + 580 + err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_PARSER); 581 + if (err) { 582 + printf("Failed empty parser prog detach\n"); 583 + goto out_sockmap; 584 + } 585 + 586 + err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_VERDICT); 587 + if (err) { 588 + printf("Failed empty verdict prog detach\n"); 589 + goto out_sockmap; 590 + } 591 + 592 + err = bpf_prog_detach(fd, __MAX_BPF_ATTACH_TYPE); 593 + if (!err) { 594 + printf("Detach invalid prog successful\n"); 571 595 goto out_sockmap; 572 596 } 573 597 ··· 664 640 BPF_SK_SKB_STREAM_VERDICT, 0); 665 641 if (err) { 666 642 printf("Failed stream verdict bpf prog attach\n"); 643 + goto out_sockmap; 644 + } 645 + 646 + err = bpf_prog_attach(verdict_prog, map_fd_rx, 647 + __MAX_BPF_ATTACH_TYPE, 0); 648 + if (!err) { 649 + printf("Attached unknown bpf prog\n"); 667 650 goto out_sockmap; 668 651 } 669 652 ··· 838 807 839 808 assert(waitpid(pid[i], &status, 0) == pid[i]); 840 809 assert(status == 0); 810 + } 811 + 812 + err = bpf_prog_detach(map_fd_rx, __MAX_BPF_ATTACH_TYPE); 813 + if (!err) { 814 + printf("Detached an invalid prog type.\n"); 815 + goto out_sockmap; 816 + } 817 + 818 + err = bpf_prog_detach(map_fd_rx, BPF_SK_SKB_STREAM_PARSER); 819 + if (err) { 820 + printf("Failed parser prog detach\n"); 821 + goto out_sockmap; 822 + } 823 + 824 + err = bpf_prog_detach(map_fd_rx, BPF_SK_SKB_STREAM_VERDICT); 825 + if (err) { 826 + printf("Failed parser prog detach\n"); 827 + goto out_sockmap; 841 828 } 842 829 843 830 /* Test map close sockets */