1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Test that the flow_dissector program can be updated with a single 4 * syscall by attaching a new program that replaces the existing one. 5 * 6 * Corner case - the same program cannot be attached twice. 7 */ 8 9 #define _GNU_SOURCE 10 #include <errno.h> 11 #include <fcntl.h> 12 #include <sched.h> 13 #include <stdbool.h> 14 #include <unistd.h> 15 16 #include <linux/bpf.h> 17 #include <bpf/bpf.h> 18 19 #include "test_progs.h" 20 21 static bool is_attached(int netns) 22 { 23 __u32 cnt; 24 int err; 25 26 err = bpf_prog_query(netns, BPF_FLOW_DISSECTOR, 0, NULL, NULL, &cnt); 27 if (CHECK_FAIL(err)) { 28 perror("bpf_prog_query"); 29 return true; /* fail-safe */ 30 } 31 32 return cnt > 0; 33 } 34 35 static int load_prog(void) 36 { 37 struct bpf_insn prog[] = { 38 BPF_MOV64_IMM(BPF_REG_0, BPF_OK), 39 BPF_EXIT_INSN(), 40 }; 41 int fd; 42 43 fd = bpf_load_program(BPF_PROG_TYPE_FLOW_DISSECTOR, prog, 44 ARRAY_SIZE(prog), "GPL", 0, NULL, 0); 45 if (CHECK_FAIL(fd < 0)) 46 perror("bpf_load_program"); 47 48 return fd; 49 } 50 51 static void do_flow_dissector_reattach(void) 52 { 53 int prog_fd[2] = { -1, -1 }; 54 int err; 55 56 prog_fd[0] = load_prog(); 57 if (prog_fd[0] < 0) 58 return; 59 60 prog_fd[1] = load_prog(); 61 if (prog_fd[1] < 0) 62 goto out_close; 63 64 err = bpf_prog_attach(prog_fd[0], 0, BPF_FLOW_DISSECTOR, 0); 65 if (CHECK_FAIL(err)) { 66 perror("bpf_prog_attach-0"); 67 goto out_close; 68 } 69 70 /* Expect success when attaching a different program */ 71 err = bpf_prog_attach(prog_fd[1], 0, BPF_FLOW_DISSECTOR, 0); 72 if (CHECK_FAIL(err)) { 73 perror("bpf_prog_attach-1"); 74 goto out_detach; 75 } 76 77 /* Expect failure when attaching the same program twice */ 78 err = bpf_prog_attach(prog_fd[1], 0, BPF_FLOW_DISSECTOR, 0); 79 if (CHECK_FAIL(!err || errno != EINVAL)) 80 perror("bpf_prog_attach-2"); 81 82 out_detach: 83 err = bpf_prog_detach(0, BPF_FLOW_DISSECTOR); 84 if (CHECK_FAIL(err)) 85 perror("bpf_prog_detach"); 86 87 out_close: 88 close(prog_fd[1]); 89 close(prog_fd[0]); 90 } 91 92 void test_flow_dissector_reattach(void) 93 { 94 int init_net, self_net, err; 95 96 self_net = open("/proc/self/ns/net", O_RDONLY); 97 if (CHECK_FAIL(self_net < 0)) { 98 perror("open(/proc/self/ns/net"); 99 return; 100 } 101 102 init_net = open("/proc/1/ns/net", O_RDONLY); 103 if (CHECK_FAIL(init_net < 0)) { 104 perror("open(/proc/1/ns/net)"); 105 goto out_close; 106 } 107 108 err = setns(init_net, CLONE_NEWNET); 109 if (CHECK_FAIL(err)) { 110 perror("setns(/proc/1/ns/net)"); 111 goto out_close; 112 } 113 114 if (is_attached(init_net)) { 115 test__skip(); 116 printf("Can't test with flow dissector attached to init_net\n"); 117 goto out_setns; 118 } 119 120 /* First run tests in root network namespace */ 121 do_flow_dissector_reattach(); 122 123 /* Then repeat tests in a non-root namespace */ 124 err = unshare(CLONE_NEWNET); 125 if (CHECK_FAIL(err)) { 126 perror("unshare(CLONE_NEWNET)"); 127 goto out_setns; 128 } 129 do_flow_dissector_reattach(); 130 131 out_setns: 132 /* Move back to netns we started in. */ 133 err = setns(self_net, CLONE_NEWNET); 134 if (CHECK_FAIL(err)) 135 perror("setns(/proc/self/ns/net)"); 136 137 out_close: 138 close(init_net); 139 close(self_net); 140 } 141