1 /* 2 * Copyright (c) 2017 Jan Kokemüller 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include <sys/cdefs.h> 27 #include <sys/param.h> 28 #include <sys/capsicum.h> 29 #include <sys/socket.h> 30 #include <sys/sysctl.h> 31 #include <sys/stat.h> 32 33 #include <netinet/in.h> 34 #include <arpa/inet.h> 35 36 #include <atf-c.h> 37 #include <dlfcn.h> 38 #include <errno.h> 39 #include <stdarg.h> 40 #include <stdlib.h> 41 #include <string.h> 42 43 #include "freebsd_test_suite/macros.h" 44 45 static int rootfd = -1; 46 47 /* circumvent bug 215690 */ 48 int 49 open(const char *path, int flags, ...) 50 { 51 mode_t mode = 0; 52 53 if (flags & O_CREAT) { 54 va_list ap; 55 va_start(ap, flags); 56 mode = (mode_t) va_arg(ap, int); 57 va_end(ap); 58 } 59 60 if (path && path[0] == '/' && rootfd >= 0) { 61 return (openat(rootfd, path + 1, flags, mode)); 62 } else { 63 return (openat(AT_FDCWD, path, flags, mode)); 64 } 65 } 66 67 static void 68 check_capsicum(void) 69 { 70 ATF_REQUIRE_FEATURE("security_capabilities"); 71 ATF_REQUIRE_FEATURE("security_capability_mode"); 72 73 ATF_REQUIRE((rootfd = open("/", O_EXEC | O_CLOEXEC)) >= 0); 74 } 75 76 typedef int (*socket_fun)(int, const struct sockaddr *, socklen_t); 77 78 static int 79 connectat_fdcwd(int s, const struct sockaddr *name, socklen_t namelen) 80 { 81 82 return (connectat(AT_FDCWD, s, name, namelen)); 83 } 84 85 static int 86 bindat_fdcwd(int s, const struct sockaddr *name, socklen_t namelen) 87 { 88 89 return (bindat(AT_FDCWD, s, name, namelen)); 90 } 91 92 93 ATF_TC(bindat_connectat_1); 94 ATF_TC_HEAD(bindat_connectat_1, tc) 95 { 96 atf_tc_set_md_var(tc, "descr", 97 "Verify that connect/bind work in normal case"); 98 } 99 100 static void 101 check_1(socket_fun f, int s, const struct sockaddr_in *name) 102 { 103 104 ATF_REQUIRE((s = socket(AF_INET, SOCK_STREAM, 0)) >= 0); 105 ATF_REQUIRE_ERRNO(EAFNOSUPPORT, 106 f(s, (const struct sockaddr *)(name), 107 sizeof(struct sockaddr_in)) < 0); 108 } 109 110 ATF_TC_BODY(bindat_connectat_1, tc) 111 { 112 struct sockaddr_in sin; 113 114 memset(&sin, 0, sizeof(sin)); 115 sin.sin_family = AF_INET; 116 sin.sin_port = htons(0); 117 sin.sin_addr.s_addr = htonl(0xE0000000); 118 119 check_1(bindat_fdcwd, 0, &sin); 120 check_1(bind, 0, &sin); 121 check_1(connectat_fdcwd, 0, &sin); 122 check_1(connect, 0, &sin); 123 } 124 125 126 ATF_TC(bindat_connectat_2); 127 ATF_TC_HEAD(bindat_connectat_2, tc) 128 { 129 atf_tc_set_md_var(tc, "descr", 130 "Verify that connect/bind are disabled in cap-mode"); 131 } 132 133 static void 134 check_2(socket_fun f, int s, const struct sockaddr_in *name) 135 { 136 137 ATF_REQUIRE_ERRNO(ECAPMODE, 138 f(s, (const struct sockaddr *)name, 139 sizeof(struct sockaddr_in)) < 0); 140 } 141 142 ATF_TC_BODY(bindat_connectat_2, tc) 143 { 144 int sock; 145 struct sockaddr_in sin; 146 147 check_capsicum(); 148 149 ATF_REQUIRE(cap_enter() >= 0); 150 151 /* note: sock is created _after_ cap_enter() and contains all rights */ 152 ATF_REQUIRE((sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0); 153 154 memset(&sin, 0, sizeof(sin)); 155 sin.sin_family = AF_INET; 156 /* dummy port and multicast address (224.0.0.0) to distinguish two 157 * cases: 158 * - ECAPMODE/ENOTCAPABLE --> call blocked by capsicum 159 * - EAFNOSUPPORT --> call went through to protocol layer 160 */ 161 sin.sin_port = htons(0); 162 sin.sin_addr.s_addr = htonl(0xE0000000); 163 164 check_2(bindat_fdcwd, sock, &sin); 165 check_2(bind, sock, &sin); 166 check_2(connectat_fdcwd, sock, &sin); 167 check_2(connect, sock, &sin); 168 } 169 170 171 ATF_TC(bindat_connectat_3); 172 ATF_TC_HEAD(bindat_connectat_3, tc) 173 { 174 atf_tc_set_md_var(tc, "descr", 175 "Check that taking away CAP_BIND/CAP_CONNECT " 176 "sabotages bind/connect"); 177 } 178 179 static void 180 check_3(socket_fun f, int s, const struct sockaddr_in *name, 181 cap_rights_t *rights, cap_rights_t *sub_rights) 182 { 183 184 ATF_REQUIRE((s = socket(AF_INET, SOCK_STREAM, 0)) >= 0); 185 ATF_REQUIRE(cap_rights_limit(s, rights) >= 0); 186 ATF_REQUIRE_ERRNO(EAFNOSUPPORT, 187 f(s, (const struct sockaddr *)name, 188 sizeof(struct sockaddr_in)) < 0); 189 ATF_REQUIRE(cap_rights_limit(s, 190 cap_rights_remove(rights, sub_rights)) >= 0); 191 ATF_REQUIRE_ERRNO(ENOTCAPABLE, 192 f(s, (const struct sockaddr *)name, 193 sizeof(struct sockaddr_in)) < 0); 194 } 195 196 ATF_TC_BODY(bindat_connectat_3, tc) 197 { 198 struct sockaddr_in sin; 199 cap_rights_t rights, sub_rights; 200 201 check_capsicum(); 202 203 memset(&sin, 0, sizeof(sin)); 204 sin.sin_family = AF_INET; 205 sin.sin_port = htons(0); 206 sin.sin_addr.s_addr = htonl(0xE0000000); 207 208 check_3(bindat_fdcwd, 0, &sin, 209 cap_rights_init(&rights, CAP_SOCK_SERVER), 210 cap_rights_init(&sub_rights, CAP_BIND)); 211 check_3(bind, 0, &sin, 212 cap_rights_init(&rights, CAP_SOCK_SERVER), 213 cap_rights_init(&sub_rights, CAP_BIND)); 214 check_3(connectat_fdcwd, 0, &sin, 215 cap_rights_init(&rights, CAP_SOCK_CLIENT), 216 cap_rights_init(&sub_rights, CAP_CONNECT)); 217 check_3(connect, 0, &sin, 218 cap_rights_init(&rights, CAP_SOCK_CLIENT), 219 cap_rights_init(&sub_rights, CAP_CONNECT)); 220 } 221 222 223 ATF_TP_ADD_TCS(tp) 224 { 225 226 ATF_TP_ADD_TC(tp, bindat_connectat_1); 227 ATF_TP_ADD_TC(tp, bindat_connectat_2); 228 ATF_TP_ADD_TC(tp, bindat_connectat_3); 229 230 return (atf_no_error()); 231 } 232