aboutsummaryrefslogtreecommitdiffstats
path: root/security/smack/smack_lsm.c
diff options
context:
space:
mode:
authorCasey Schaufler <casey@schaufler-ca.com>2008-12-31 12:54:12 -0500
committerPaul Moore <paul.moore@hp.com>2008-12-31 12:54:12 -0500
commit6d3dc07cbb1e88deed2e8710e215f232a56b1dce (patch)
tree4c294d1ddac8c9f417bcd406771993aa58106f6d /security/smack/smack_lsm.c
parent277d342fc423fca5e66e677fe629d1b2f8f1b9e2 (diff)
smack: Add support for unlabeled network hosts and networks
Add support for unlabeled network hosts and networks. Relies heavily on Paul Moore's netlabel support. Creates a new entry in /smack called netlabel. Writes to /smack/netlabel take the form: A.B.C.D LABEL or A.B.C.D/N LABEL where A.B.C.D is a network address, N is an integer between 0-32, and LABEL is the Smack label to be used. If /N is omitted /32 is assumed. N designates the netmask for the address. Entries are matched by the most specific address/mask pair. 0.0.0.0/0 will match everything, while 192.168.1.117/32 will match exactly one host. A new system label "@", pronounced "web", is defined. Processes can not be assigned the web label. An address assigned the web label can be written to by any process, and packets coming from a web address can be written to any socket. Use of the web label is a violation of any strict MAC policy, but the web label has been requested many times. The nltype entry has been removed from /smack. It did not work right and the netlabel interface can be used to specify that all hosts be treated as unlabeled. CIPSO labels on incoming packets will be honored, even from designated single label hosts. Single label hosts can only be written to by processes with labels that can write to the label of the host. Packets sent to single label hosts will always be unlabeled. Once added a single label designation cannot be removed, however the label may be changed. The behavior of the ambient label remains unchanged. Signed-off-by: Casey Schaufler <casey@schaufler-ca.com> Signed-off-by: Paul Moore <paul.moore@hp.com>
Diffstat (limited to 'security/smack/smack_lsm.c')
-rw-r--r--security/smack/smack_lsm.c310
1 files changed, 255 insertions, 55 deletions
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 1b5551dfc1f7..6bfaba6177c2 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1277,6 +1277,7 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
1277 1277
1278 ssp->smk_in = csp; 1278 ssp->smk_in = csp;
1279 ssp->smk_out = csp; 1279 ssp->smk_out = csp;
1280 ssp->smk_labeled = SMACK_CIPSO_SOCKET;
1280 ssp->smk_packet[0] = '\0'; 1281 ssp->smk_packet[0] = '\0';
1281 1282
1282 sk->sk_security = ssp; 1283 sk->sk_security = ssp;
@@ -1341,45 +1342,69 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp)
1341 struct smack_cipso cipso; 1342 struct smack_cipso cipso;
1342 int rc; 1343 int rc;
1343 1344
1344 switch (smack_net_nltype) { 1345 nlsp->domain = smack;
1345 case NETLBL_NLTYPE_CIPSOV4: 1346 nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
1346 nlsp->domain = smack;
1347 nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
1348 1347
1349 rc = smack_to_cipso(smack, &cipso); 1348 rc = smack_to_cipso(smack, &cipso);
1350 if (rc == 0) { 1349 if (rc == 0) {
1351 nlsp->attr.mls.lvl = cipso.smk_level; 1350 nlsp->attr.mls.lvl = cipso.smk_level;
1352 smack_set_catset(cipso.smk_catset, nlsp); 1351 smack_set_catset(cipso.smk_catset, nlsp);
1353 } else { 1352 } else {
1354 nlsp->attr.mls.lvl = smack_cipso_direct; 1353 nlsp->attr.mls.lvl = smack_cipso_direct;
1355 smack_set_catset(smack, nlsp); 1354 smack_set_catset(smack, nlsp);
1356 }
1357 break;
1358 default:
1359 break;
1360 } 1355 }
1361} 1356}
1362 1357
1363/** 1358/**
1364 * smack_netlabel - Set the secattr on a socket 1359 * smack_netlabel - Set the secattr on a socket
1365 * @sk: the socket 1360 * @sk: the socket
1361 * @labeled: socket label scheme
1366 * 1362 *
1367 * Convert the outbound smack value (smk_out) to a 1363 * Convert the outbound smack value (smk_out) to a
1368 * secattr and attach it to the socket. 1364 * secattr and attach it to the socket.
1369 * 1365 *
1370 * Returns 0 on success or an error code 1366 * Returns 0 on success or an error code
1371 */ 1367 */
1372static int smack_netlabel(struct sock *sk) 1368static int smack_netlabel(struct sock *sk, int labeled)
1373{ 1369{
1374 struct socket_smack *ssp; 1370 struct socket_smack *ssp;
1375 struct netlbl_lsm_secattr secattr; 1371 struct netlbl_lsm_secattr secattr;
1376 int rc; 1372 int rc = 0;
1377 1373
1378 ssp = sk->sk_security; 1374 ssp = sk->sk_security;
1379 netlbl_secattr_init(&secattr); 1375 /*
1380 smack_to_secattr(ssp->smk_out, &secattr); 1376 * Usually the netlabel code will handle changing the
1381 rc = netlbl_sock_setattr(sk, &secattr); 1377 * packet labeling based on the label.
1382 netlbl_secattr_destroy(&secattr); 1378 * The case of a single label host is different, because
1379 * a single label host should never get a labeled packet
1380 * even though the label is usually associated with a packet
1381 * label.
1382 */
1383 local_bh_disable();
1384 bh_lock_sock_nested(sk);
1385
1386 if (ssp->smk_out == smack_net_ambient ||
1387 labeled == SMACK_UNLABELED_SOCKET)
1388 netlbl_sock_delattr(sk);
1389 else {
1390 netlbl_secattr_init(&secattr);
1391 smack_to_secattr(ssp->smk_out, &secattr);
1392 rc = netlbl_sock_setattr(sk, &secattr);
1393 netlbl_secattr_destroy(&secattr);
1394 }
1395
1396 bh_unlock_sock(sk);
1397 local_bh_enable();
1398 /*
1399 * Remember the label scheme used so that it is not
1400 * necessary to do the netlabel setting if it has not
1401 * changed the next time through.
1402 *
1403 * The -EDESTADDRREQ case is an indication that there's
1404 * a single level host involved.
1405 */
1406 if (rc == 0)
1407 ssp->smk_labeled = labeled;
1383 1408
1384 return rc; 1409 return rc;
1385} 1410}
@@ -1432,7 +1457,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
1432 ssp->smk_in = sp; 1457 ssp->smk_in = sp;
1433 else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) { 1458 else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) {
1434 ssp->smk_out = sp; 1459 ssp->smk_out = sp;
1435 rc = smack_netlabel(sock->sk); 1460 rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
1436 if (rc != 0) 1461 if (rc != 0)
1437 printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n", 1462 printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n",
1438 __func__, -rc); 1463 __func__, -rc);
@@ -1462,7 +1487,108 @@ static int smack_socket_post_create(struct socket *sock, int family,
1462 /* 1487 /*
1463 * Set the outbound netlbl. 1488 * Set the outbound netlbl.
1464 */ 1489 */
1465 return smack_netlabel(sock->sk); 1490 return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
1491}
1492
1493
1494/**
1495 * smack_host_label - check host based restrictions
1496 * @sip: the object end
1497 *
1498 * looks for host based access restrictions
1499 *
1500 * This version will only be appropriate for really small
1501 * sets of single label hosts. Because of the masking
1502 * it cannot shortcut out on the first match. There are
1503 * numerious ways to address the problem, but none of them
1504 * have been applied here.
1505 *
1506 * Returns the label of the far end or NULL if it's not special.
1507 */
1508static char *smack_host_label(struct sockaddr_in *sip)
1509{
1510 struct smk_netlbladdr *snp;
1511 char *bestlabel = NULL;
1512 struct in_addr *siap = &sip->sin_addr;
1513 struct in_addr *liap;
1514 struct in_addr *miap;
1515 struct in_addr bestmask;
1516
1517 if (siap->s_addr == 0)
1518 return NULL;
1519
1520 bestmask.s_addr = 0;
1521
1522 for (snp = smack_netlbladdrs; snp != NULL; snp = snp->smk_next) {
1523 liap = &snp->smk_host.sin_addr;
1524 miap = &snp->smk_mask;
1525 /*
1526 * If the addresses match after applying the list entry mask
1527 * the entry matches the address. If it doesn't move along to
1528 * the next entry.
1529 */
1530 if ((liap->s_addr & miap->s_addr) !=
1531 (siap->s_addr & miap->s_addr))
1532 continue;
1533 /*
1534 * If the list entry mask identifies a single address
1535 * it can't get any more specific.
1536 */
1537 if (miap->s_addr == 0xffffffff)
1538 return snp->smk_label;
1539 /*
1540 * If the list entry mask is less specific than the best
1541 * already found this entry is uninteresting.
1542 */
1543 if ((miap->s_addr | bestmask.s_addr) == bestmask.s_addr)
1544 continue;
1545 /*
1546 * This is better than any entry found so far.
1547 */
1548 bestmask.s_addr = miap->s_addr;
1549 bestlabel = snp->smk_label;
1550 }
1551
1552 return bestlabel;
1553}
1554
1555/**
1556 * smack_socket_connect - connect access check
1557 * @sock: the socket
1558 * @sap: the other end
1559 * @addrlen: size of sap
1560 *
1561 * Verifies that a connection may be possible
1562 *
1563 * Returns 0 on success, and error code otherwise
1564 */
1565static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
1566 int addrlen)
1567{
1568 struct socket_smack *ssp = sock->sk->sk_security;
1569 char *hostsp;
1570 int rc;
1571
1572 if (sock->sk == NULL || sock->sk->sk_family != PF_INET)
1573 return 0;
1574
1575 if (addrlen < sizeof(struct sockaddr_in))
1576 return -EINVAL;
1577
1578 hostsp = smack_host_label((struct sockaddr_in *)sap);
1579 if (hostsp == NULL) {
1580 if (ssp->smk_labeled != SMACK_CIPSO_SOCKET)
1581 return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
1582 return 0;
1583 }
1584
1585 rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
1586 if (rc != 0)
1587 return rc;
1588
1589 if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET)
1590 return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET);
1591 return 0;
1466} 1592}
1467 1593
1468/** 1594/**
@@ -2101,8 +2227,14 @@ static int smack_setprocattr(struct task_struct *p, char *name,
2101 if (newsmack == NULL) 2227 if (newsmack == NULL)
2102 return -EINVAL; 2228 return -EINVAL;
2103 2229
2230 /*
2231 * No process is ever allowed the web ("@") label.
2232 */
2233 if (newsmack == smack_known_web.smk_known)
2234 return -EPERM;
2235
2104 new = prepare_creds(); 2236 new = prepare_creds();
2105 if (!new) 2237 if (new == NULL)
2106 return -ENOMEM; 2238 return -ENOMEM;
2107 new->security = newsmack; 2239 new->security = newsmack;
2108 commit_creds(new); 2240 commit_creds(new);
@@ -2144,6 +2276,49 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
2144} 2276}
2145 2277
2146/** 2278/**
2279 * smack_socket_sendmsg - Smack check based on destination host
2280 * @sock: the socket
2281 * @msghdr: the message
2282 * @size: the size of the message
2283 *
2284 * Return 0 if the current subject can write to the destination
2285 * host. This is only a question if the destination is a single
2286 * label host.
2287 */
2288static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
2289 int size)
2290{
2291 struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name;
2292 struct socket_smack *ssp = sock->sk->sk_security;
2293 char *hostsp;
2294 int rc;
2295
2296 /*
2297 * Perfectly reasonable for this to be NULL
2298 */
2299 if (sip == NULL || sip->sin_family != PF_INET)
2300 return 0;
2301
2302 hostsp = smack_host_label(sip);
2303 if (hostsp == NULL) {
2304 if (ssp->smk_labeled != SMACK_CIPSO_SOCKET)
2305 return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
2306 return 0;
2307 }
2308
2309 rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
2310 if (rc != 0)
2311 return rc;
2312
2313 if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET)
2314 return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET);
2315
2316 return 0;
2317
2318}
2319
2320
2321/**
2147 * smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat 2322 * smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat
2148 * pair to smack 2323 * pair to smack
2149 * @sap: netlabel secattr 2324 * @sap: netlabel secattr
@@ -2154,44 +2329,66 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
2154static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip) 2329static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip)
2155{ 2330{
2156 char smack[SMK_LABELLEN]; 2331 char smack[SMK_LABELLEN];
2332 char *sp;
2157 int pcat; 2333 int pcat;
2158 2334
2159 if ((sap->flags & NETLBL_SECATTR_MLS_LVL) == 0) { 2335 if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) {
2160 /* 2336 /*
2337 * Looks like a CIPSO packet.
2161 * If there are flags but no level netlabel isn't 2338 * If there are flags but no level netlabel isn't
2162 * behaving the way we expect it to. 2339 * behaving the way we expect it to.
2163 * 2340 *
2341 * Get the categories, if any
2164 * Without guidance regarding the smack value 2342 * Without guidance regarding the smack value
2165 * for the packet fall back on the network 2343 * for the packet fall back on the network
2166 * ambient value. 2344 * ambient value.
2167 */ 2345 */
2168 strncpy(sip, smack_net_ambient, SMK_MAXLEN); 2346 memset(smack, '\0', SMK_LABELLEN);
2347 if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0)
2348 for (pcat = -1;;) {
2349 pcat = netlbl_secattr_catmap_walk(
2350 sap->attr.mls.cat, pcat + 1);
2351 if (pcat < 0)
2352 break;
2353 smack_catset_bit(pcat, smack);
2354 }
2355 /*
2356 * If it is CIPSO using smack direct mapping
2357 * we are already done. WeeHee.
2358 */
2359 if (sap->attr.mls.lvl == smack_cipso_direct) {
2360 memcpy(sip, smack, SMK_MAXLEN);
2361 return;
2362 }
2363 /*
2364 * Look it up in the supplied table if it is not
2365 * a direct mapping.
2366 */
2367 smack_from_cipso(sap->attr.mls.lvl, smack, sip);
2169 return; 2368 return;
2170 } 2369 }
2171 /* 2370 if ((sap->flags & NETLBL_SECATTR_SECID) != 0) {
2172 * Get the categories, if any 2371 /*
2173 */ 2372 * Looks like a fallback, which gives us a secid.
2174 memset(smack, '\0', SMK_LABELLEN); 2373 */
2175 if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0) 2374 sp = smack_from_secid(sap->attr.secid);
2176 for (pcat = -1;;) { 2375 /*
2177 pcat = netlbl_secattr_catmap_walk(sap->attr.mls.cat, 2376 * This has got to be a bug because it is
2178 pcat + 1); 2377 * impossible to specify a fallback without
2179 if (pcat < 0) 2378 * specifying the label, which will ensure
2180 break; 2379 * it has a secid, and the only way to get a
2181 smack_catset_bit(pcat, smack); 2380 * secid is from a fallback.
2182 } 2381 */
2183 /* 2382 BUG_ON(sp == NULL);
2184 * If it is CIPSO using smack direct mapping 2383 strncpy(sip, sp, SMK_MAXLEN);
2185 * we are already done. WeeHee.
2186 */
2187 if (sap->attr.mls.lvl == smack_cipso_direct) {
2188 memcpy(sip, smack, SMK_MAXLEN);
2189 return; 2384 return;
2190 } 2385 }
2191 /* 2386 /*
2192 * Look it up in the supplied table if it is not a direct mapping. 2387 * Without guidance regarding the smack value
2388 * for the packet fall back on the network
2389 * ambient value.
2193 */ 2390 */
2194 smack_from_cipso(sap->attr.mls.lvl, smack, sip); 2391 strncpy(sip, smack_net_ambient, SMK_MAXLEN);
2195 return; 2392 return;
2196} 2393}
2197 2394
@@ -2207,6 +2404,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
2207 struct netlbl_lsm_secattr secattr; 2404 struct netlbl_lsm_secattr secattr;
2208 struct socket_smack *ssp = sk->sk_security; 2405 struct socket_smack *ssp = sk->sk_security;
2209 char smack[SMK_LABELLEN]; 2406 char smack[SMK_LABELLEN];
2407 char *csp;
2210 int rc; 2408 int rc;
2211 2409
2212 if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6) 2410 if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
@@ -2215,21 +2413,24 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
2215 /* 2413 /*
2216 * Translate what netlabel gave us. 2414 * Translate what netlabel gave us.
2217 */ 2415 */
2218 memset(smack, '\0', SMK_LABELLEN);
2219 netlbl_secattr_init(&secattr); 2416 netlbl_secattr_init(&secattr);
2417
2220 rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr); 2418 rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr);
2221 if (rc == 0) 2419 if (rc == 0) {
2222 smack_from_secattr(&secattr, smack); 2420 smack_from_secattr(&secattr, smack);
2223 else 2421 csp = smack;
2224 strncpy(smack, smack_net_ambient, SMK_MAXLEN); 2422 } else
2423 csp = smack_net_ambient;
2424
2225 netlbl_secattr_destroy(&secattr); 2425 netlbl_secattr_destroy(&secattr);
2426
2226 /* 2427 /*
2227 * Receiving a packet requires that the other end 2428 * Receiving a packet requires that the other end
2228 * be able to write here. Read access is not required. 2429 * be able to write here. Read access is not required.
2229 * This is the simplist possible security model 2430 * This is the simplist possible security model
2230 * for networking. 2431 * for networking.
2231 */ 2432 */
2232 rc = smk_access(smack, ssp->smk_in, MAY_WRITE); 2433 rc = smk_access(csp, ssp->smk_in, MAY_WRITE);
2233 if (rc != 0) 2434 if (rc != 0)
2234 netlbl_skbuff_err(skb, rc, 0); 2435 netlbl_skbuff_err(skb, rc, 0);
2235 return rc; 2436 return rc;
@@ -2298,7 +2499,6 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
2298 /* 2499 /*
2299 * Translate what netlabel gave us. 2500 * Translate what netlabel gave us.
2300 */ 2501 */
2301 memset(smack, '\0', SMK_LABELLEN);
2302 netlbl_secattr_init(&secattr); 2502 netlbl_secattr_init(&secattr);
2303 rc = netlbl_skbuff_getattr(skb, family, &secattr); 2503 rc = netlbl_skbuff_getattr(skb, family, &secattr);
2304 if (rc == 0) 2504 if (rc == 0)
@@ -2341,7 +2541,7 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent)
2341 ssp->smk_in = ssp->smk_out = current_security(); 2541 ssp->smk_in = ssp->smk_out = current_security();
2342 ssp->smk_packet[0] = '\0'; 2542 ssp->smk_packet[0] = '\0';
2343 2543
2344 rc = smack_netlabel(sk); 2544 rc = smack_netlabel(sk, SMACK_CIPSO_SOCKET);
2345 if (rc != 0) 2545 if (rc != 0)
2346 printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n", 2546 printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n",
2347 __func__, -rc); 2547 __func__, -rc);
@@ -2367,7 +2567,6 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
2367 if (skb == NULL) 2567 if (skb == NULL)
2368 return -EACCES; 2568 return -EACCES;
2369 2569
2370 memset(smack, '\0', SMK_LABELLEN);
2371 netlbl_secattr_init(&skb_secattr); 2570 netlbl_secattr_init(&skb_secattr);
2372 rc = netlbl_skbuff_getattr(skb, sk->sk_family, &skb_secattr); 2571 rc = netlbl_skbuff_getattr(skb, sk->sk_family, &skb_secattr);
2373 if (rc == 0) 2572 if (rc == 0)
@@ -2732,6 +2931,8 @@ struct security_operations smack_ops = {
2732 .unix_may_send = smack_unix_may_send, 2931 .unix_may_send = smack_unix_may_send,
2733 2932
2734 .socket_post_create = smack_socket_post_create, 2933 .socket_post_create = smack_socket_post_create,
2934 .socket_connect = smack_socket_connect,
2935 .socket_sendmsg = smack_socket_sendmsg,
2735 .socket_sock_rcv_skb = smack_socket_sock_rcv_skb, 2936 .socket_sock_rcv_skb = smack_socket_sock_rcv_skb,
2736 .socket_getpeersec_stream = smack_socket_getpeersec_stream, 2937 .socket_getpeersec_stream = smack_socket_getpeersec_stream,
2737 .socket_getpeersec_dgram = smack_socket_getpeersec_dgram, 2938 .socket_getpeersec_dgram = smack_socket_getpeersec_dgram,
@@ -2783,7 +2984,6 @@ static __init int smack_init(void)
2783 /* 2984 /*
2784 * Initialize locks 2985 * Initialize locks
2785 */ 2986 */
2786 spin_lock_init(&smack_known_unset.smk_cipsolock);
2787 spin_lock_init(&smack_known_huh.smk_cipsolock); 2987 spin_lock_init(&smack_known_huh.smk_cipsolock);
2788 spin_lock_init(&smack_known_hat.smk_cipsolock); 2988 spin_lock_init(&smack_known_hat.smk_cipsolock);
2789 spin_lock_init(&smack_known_star.smk_cipsolock); 2989 spin_lock_init(&smack_known_star.smk_cipsolock);