aboutsummaryrefslogtreecommitdiffstats
path: root/security/smack/smack_lsm.c
diff options
context:
space:
mode:
authorPaul Moore <paul.moore@hp.com>2009-03-27 17:10:54 -0400
committerJames Morris <jmorris@namei.org>2009-03-28 00:01:37 -0400
commit07feee8f812f7327a46186f7604df312c8c81962 (patch)
tree73eac643b60532aa82d7680a7de193ba2b62eddd /security/smack/smack_lsm.c
parent8651d5c0b1f874c5b8307ae2b858bc40f9f02482 (diff)
netlabel: Cleanup the Smack/NetLabel code to fix incoming TCP connections
This patch cleans up a lot of the Smack network access control code. The largest changes are to fix the labeling of incoming TCP connections in a manner similar to the recent SELinux changes which use the security_inet_conn_request() hook to label the request_sock and let the label move to the child socket via the normal network stack mechanisms. In addition to the incoming TCP connection fixes this patch also removes the smk_labled field from the socket_smack struct as the minor optimization advantage was outweighed by the difficulty in maintaining it's proper state. Signed-off-by: Paul Moore <paul.moore@hp.com> Acked-by: Casey Schaufler <casey@schaufler-ca.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/smack/smack_lsm.c')
-rw-r--r--security/smack/smack_lsm.c260
1 files changed, 143 insertions, 117 deletions
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 23ad420a49aa..8ed502c2ad45 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -7,6 +7,8 @@
7 * Casey Schaufler <casey@schaufler-ca.com> 7 * Casey Schaufler <casey@schaufler-ca.com>
8 * 8 *
9 * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com> 9 * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
10 * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
11 * Paul Moore <paul.moore@hp.com>
10 * 12 *
11 * This program is free software; you can redistribute it and/or modify 13 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2, 14 * it under the terms of the GNU General Public License version 2,
@@ -20,6 +22,7 @@
20#include <linux/ext2_fs.h> 22#include <linux/ext2_fs.h>
21#include <linux/kd.h> 23#include <linux/kd.h>
22#include <asm/ioctls.h> 24#include <asm/ioctls.h>
25#include <linux/ip.h>
23#include <linux/tcp.h> 26#include <linux/tcp.h>
24#include <linux/udp.h> 27#include <linux/udp.h>
25#include <linux/mutex.h> 28#include <linux/mutex.h>
@@ -1275,7 +1278,6 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
1275 1278
1276 ssp->smk_in = csp; 1279 ssp->smk_in = csp;
1277 ssp->smk_out = csp; 1280 ssp->smk_out = csp;
1278 ssp->smk_labeled = SMACK_CIPSO_SOCKET;
1279 ssp->smk_packet[0] = '\0'; 1281 ssp->smk_packet[0] = '\0';
1280 1282
1281 sk->sk_security = ssp; 1283 sk->sk_security = ssp;
@@ -1295,6 +1297,39 @@ static void smack_sk_free_security(struct sock *sk)
1295} 1297}
1296 1298
1297/** 1299/**
1300* smack_host_label - check host based restrictions
1301* @sip: the object end
1302*
1303* looks for host based access restrictions
1304*
1305* This version will only be appropriate for really small sets of single label
1306* hosts. The caller is responsible for ensuring that the RCU read lock is
1307* taken before calling this function.
1308*
1309* Returns the label of the far end or NULL if it's not special.
1310*/
1311static char *smack_host_label(struct sockaddr_in *sip)
1312{
1313 struct smk_netlbladdr *snp;
1314 struct in_addr *siap = &sip->sin_addr;
1315
1316 if (siap->s_addr == 0)
1317 return NULL;
1318
1319 list_for_each_entry_rcu(snp, &smk_netlbladdr_list, list)
1320 /*
1321 * we break after finding the first match because
1322 * the list is sorted from longest to shortest mask
1323 * so we have found the most specific match
1324 */
1325 if ((&snp->smk_host.sin_addr)->s_addr ==
1326 (siap->s_addr & (&snp->smk_mask)->s_addr))
1327 return snp->smk_label;
1328
1329 return NULL;
1330}
1331
1332/**
1298 * smack_set_catset - convert a capset to netlabel mls categories 1333 * smack_set_catset - convert a capset to netlabel mls categories
1299 * @catset: the Smack categories 1334 * @catset: the Smack categories
1300 * @sap: where to put the netlabel categories 1335 * @sap: where to put the netlabel categories
@@ -1365,11 +1400,10 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp)
1365 */ 1400 */
1366static int smack_netlabel(struct sock *sk, int labeled) 1401static int smack_netlabel(struct sock *sk, int labeled)
1367{ 1402{
1368 struct socket_smack *ssp; 1403 struct socket_smack *ssp = sk->sk_security;
1369 struct netlbl_lsm_secattr secattr; 1404 struct netlbl_lsm_secattr secattr;
1370 int rc = 0; 1405 int rc = 0;
1371 1406
1372 ssp = sk->sk_security;
1373 /* 1407 /*
1374 * Usually the netlabel code will handle changing the 1408 * Usually the netlabel code will handle changing the
1375 * packet labeling based on the label. 1409 * packet labeling based on the label.
@@ -1393,21 +1427,45 @@ static int smack_netlabel(struct sock *sk, int labeled)
1393 1427
1394 bh_unlock_sock(sk); 1428 bh_unlock_sock(sk);
1395 local_bh_enable(); 1429 local_bh_enable();
1396 /*
1397 * Remember the label scheme used so that it is not
1398 * necessary to do the netlabel setting if it has not
1399 * changed the next time through.
1400 *
1401 * The -EDESTADDRREQ case is an indication that there's
1402 * a single level host involved.
1403 */
1404 if (rc == 0)
1405 ssp->smk_labeled = labeled;
1406 1430
1407 return rc; 1431 return rc;
1408} 1432}
1409 1433
1410/** 1434/**
1435 * smack_netlbel_send - Set the secattr on a socket and perform access checks
1436 * @sk: the socket
1437 * @sap: the destination address
1438 *
1439 * Set the correct secattr for the given socket based on the destination
1440 * address and perform any outbound access checks needed.
1441 *
1442 * Returns 0 on success or an error code.
1443 *
1444 */
1445static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
1446{
1447 int rc;
1448 int sk_lbl;
1449 char *hostsp;
1450 struct socket_smack *ssp = sk->sk_security;
1451
1452 rcu_read_lock();
1453 hostsp = smack_host_label(sap);
1454 if (hostsp != NULL) {
1455 sk_lbl = SMACK_UNLABELED_SOCKET;
1456 rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
1457 } else {
1458 sk_lbl = SMACK_CIPSO_SOCKET;
1459 rc = 0;
1460 }
1461 rcu_read_unlock();
1462 if (rc != 0)
1463 return rc;
1464
1465 return smack_netlabel(sk, sk_lbl);
1466}
1467
1468/**
1411 * smack_inode_setsecurity - set smack xattrs 1469 * smack_inode_setsecurity - set smack xattrs
1412 * @inode: the object 1470 * @inode: the object
1413 * @name: attribute name 1471 * @name: attribute name
@@ -1488,43 +1546,6 @@ static int smack_socket_post_create(struct socket *sock, int family,
1488 return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); 1546 return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
1489} 1547}
1490 1548
1491
1492/**
1493 * smack_host_label - check host based restrictions
1494 * @sip: the object end
1495 *
1496 * looks for host based access restrictions
1497 *
1498 * This version will only be appropriate for really small
1499 * sets of single label hosts.
1500 *
1501 * Returns the label of the far end or NULL if it's not special.
1502 */
1503static char *smack_host_label(struct sockaddr_in *sip)
1504{
1505 struct smk_netlbladdr *snp;
1506 struct in_addr *siap = &sip->sin_addr;
1507
1508 if (siap->s_addr == 0)
1509 return NULL;
1510
1511 rcu_read_lock();
1512 list_for_each_entry_rcu(snp, &smk_netlbladdr_list, list) {
1513 /*
1514 * we break after finding the first match because
1515 * the list is sorted from longest to shortest mask
1516 * so we have found the most specific match
1517 */
1518 if ((&snp->smk_host.sin_addr)->s_addr ==
1519 (siap->s_addr & (&snp->smk_mask)->s_addr)) {
1520 rcu_read_unlock();
1521 return snp->smk_label;
1522 }
1523 }
1524 rcu_read_unlock();
1525 return NULL;
1526}
1527
1528/** 1549/**
1529 * smack_socket_connect - connect access check 1550 * smack_socket_connect - connect access check
1530 * @sock: the socket 1551 * @sock: the socket
@@ -1538,30 +1559,12 @@ static char *smack_host_label(struct sockaddr_in *sip)
1538static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, 1559static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
1539 int addrlen) 1560 int addrlen)
1540{ 1561{
1541 struct socket_smack *ssp = sock->sk->sk_security;
1542 char *hostsp;
1543 int rc;
1544
1545 if (sock->sk == NULL || sock->sk->sk_family != PF_INET) 1562 if (sock->sk == NULL || sock->sk->sk_family != PF_INET)
1546 return 0; 1563 return 0;
1547
1548 if (addrlen < sizeof(struct sockaddr_in)) 1564 if (addrlen < sizeof(struct sockaddr_in))
1549 return -EINVAL; 1565 return -EINVAL;
1550 1566
1551 hostsp = smack_host_label((struct sockaddr_in *)sap); 1567 return smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap);
1552 if (hostsp == NULL) {
1553 if (ssp->smk_labeled != SMACK_CIPSO_SOCKET)
1554 return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
1555 return 0;
1556 }
1557
1558 rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
1559 if (rc != 0)
1560 return rc;
1561
1562 if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET)
1563 return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET);
1564 return 0;
1565} 1568}
1566 1569
1567/** 1570/**
@@ -2262,9 +2265,6 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
2262 int size) 2265 int size)
2263{ 2266{
2264 struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name; 2267 struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name;
2265 struct socket_smack *ssp = sock->sk->sk_security;
2266 char *hostsp;
2267 int rc;
2268 2268
2269 /* 2269 /*
2270 * Perfectly reasonable for this to be NULL 2270 * Perfectly reasonable for this to be NULL
@@ -2272,22 +2272,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
2272 if (sip == NULL || sip->sin_family != PF_INET) 2272 if (sip == NULL || sip->sin_family != PF_INET)
2273 return 0; 2273 return 0;
2274 2274
2275 hostsp = smack_host_label(sip); 2275 return smack_netlabel_send(sock->sk, sip);
2276 if (hostsp == NULL) {
2277 if (ssp->smk_labeled != SMACK_CIPSO_SOCKET)
2278 return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
2279 return 0;
2280 }
2281
2282 rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
2283 if (rc != 0)
2284 return rc;
2285
2286 if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET)
2287 return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET);
2288
2289 return 0;
2290
2291} 2276}
2292 2277
2293 2278
@@ -2492,31 +2477,24 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
2492} 2477}
2493 2478
2494/** 2479/**
2495 * smack_sock_graft - graft access state between two sockets 2480 * smack_sock_graft - Initialize a newly created socket with an existing sock
2496 * @sk: fresh sock 2481 * @sk: child sock
2497 * @parent: donor socket 2482 * @parent: parent socket
2498 * 2483 *
2499 * Sets the netlabel socket state on sk from parent 2484 * Set the smk_{in,out} state of an existing sock based on the process that
2485 * is creating the new socket.
2500 */ 2486 */
2501static void smack_sock_graft(struct sock *sk, struct socket *parent) 2487static void smack_sock_graft(struct sock *sk, struct socket *parent)
2502{ 2488{
2503 struct socket_smack *ssp; 2489 struct socket_smack *ssp;
2504 int rc;
2505
2506 if (sk == NULL)
2507 return;
2508 2490
2509 if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6) 2491 if (sk == NULL ||
2492 (sk->sk_family != PF_INET && sk->sk_family != PF_INET6))
2510 return; 2493 return;
2511 2494
2512 ssp = sk->sk_security; 2495 ssp = sk->sk_security;
2513 ssp->smk_in = ssp->smk_out = current_security(); 2496 ssp->smk_in = ssp->smk_out = current_security();
2514 ssp->smk_packet[0] = '\0'; 2497 /* cssp->smk_packet is already set in smack_inet_csk_clone() */
2515
2516 rc = smack_netlabel(sk, SMACK_CIPSO_SOCKET);
2517 if (rc != 0)
2518 printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n",
2519 __func__, -rc);
2520} 2498}
2521 2499
2522/** 2500/**
@@ -2531,35 +2509,82 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent)
2531static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, 2509static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
2532 struct request_sock *req) 2510 struct request_sock *req)
2533{ 2511{
2534 struct netlbl_lsm_secattr skb_secattr; 2512 u16 family = sk->sk_family;
2535 struct socket_smack *ssp = sk->sk_security; 2513 struct socket_smack *ssp = sk->sk_security;
2514 struct netlbl_lsm_secattr secattr;
2515 struct sockaddr_in addr;
2516 struct iphdr *hdr;
2536 char smack[SMK_LABELLEN]; 2517 char smack[SMK_LABELLEN];
2537 int rc; 2518 int rc;
2538 2519
2539 if (skb == NULL) 2520 /* handle mapped IPv4 packets arriving via IPv6 sockets */
2540 return -EACCES; 2521 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
2522 family = PF_INET;
2541 2523
2542 netlbl_secattr_init(&skb_secattr); 2524 netlbl_secattr_init(&secattr);
2543 rc = netlbl_skbuff_getattr(skb, sk->sk_family, &skb_secattr); 2525 rc = netlbl_skbuff_getattr(skb, family, &secattr);
2544 if (rc == 0) 2526 if (rc == 0)
2545 smack_from_secattr(&skb_secattr, smack); 2527 smack_from_secattr(&secattr, smack);
2546 else 2528 else
2547 strncpy(smack, smack_known_huh.smk_known, SMK_MAXLEN); 2529 strncpy(smack, smack_known_huh.smk_known, SMK_MAXLEN);
2548 netlbl_secattr_destroy(&skb_secattr); 2530 netlbl_secattr_destroy(&secattr);
2531
2549 /* 2532 /*
2550 * Receiving a packet requires that the other end 2533 * Receiving a packet requires that the other end be able to write
2551 * be able to write here. Read access is not required. 2534 * here. Read access is not required.
2552 *
2553 * If the request is successful save the peer's label
2554 * so that SO_PEERCRED can report it.
2555 */ 2535 */
2556 rc = smk_access(smack, ssp->smk_in, MAY_WRITE); 2536 rc = smk_access(smack, ssp->smk_in, MAY_WRITE);
2557 if (rc == 0) 2537 if (rc != 0)
2558 strncpy(ssp->smk_packet, smack, SMK_MAXLEN); 2538 return rc;
2539
2540 /*
2541 * Save the peer's label in the request_sock so we can later setup
2542 * smk_packet in the child socket so that SO_PEERCRED can report it.
2543 */
2544 req->peer_secid = smack_to_secid(smack);
2545
2546 /*
2547 * We need to decide if we want to label the incoming connection here
2548 * if we do we only need to label the request_sock and the stack will
2549 * propogate the wire-label to the sock when it is created.
2550 */
2551 hdr = ip_hdr(skb);
2552 addr.sin_addr.s_addr = hdr->saddr;
2553 rcu_read_lock();
2554 if (smack_host_label(&addr) == NULL) {
2555 rcu_read_unlock();
2556 netlbl_secattr_init(&secattr);
2557 smack_to_secattr(smack, &secattr);
2558 rc = netlbl_req_setattr(req, &secattr);
2559 netlbl_secattr_destroy(&secattr);
2560 } else {
2561 rcu_read_unlock();
2562 netlbl_req_delattr(req);
2563 }
2559 2564
2560 return rc; 2565 return rc;
2561} 2566}
2562 2567
2568/**
2569 * smack_inet_csk_clone - Copy the connection information to the new socket
2570 * @sk: the new socket
2571 * @req: the connection's request_sock
2572 *
2573 * Transfer the connection's peer label to the newly created socket.
2574 */
2575static void smack_inet_csk_clone(struct sock *sk,
2576 const struct request_sock *req)
2577{
2578 struct socket_smack *ssp = sk->sk_security;
2579 char *smack;
2580
2581 if (req->peer_secid != 0) {
2582 smack = smack_from_secid(req->peer_secid);
2583 strncpy(ssp->smk_packet, smack, SMK_MAXLEN);
2584 } else
2585 ssp->smk_packet[0] = '\0';
2586}
2587
2563/* 2588/*
2564 * Key management security hooks 2589 * Key management security hooks
2565 * 2590 *
@@ -2911,6 +2936,7 @@ struct security_operations smack_ops = {
2911 .sk_free_security = smack_sk_free_security, 2936 .sk_free_security = smack_sk_free_security,
2912 .sock_graft = smack_sock_graft, 2937 .sock_graft = smack_sock_graft,
2913 .inet_conn_request = smack_inet_conn_request, 2938 .inet_conn_request = smack_inet_conn_request,
2939 .inet_csk_clone = smack_inet_csk_clone,
2914 2940
2915 /* key management security hooks */ 2941 /* key management security hooks */
2916#ifdef CONFIG_KEYS 2942#ifdef CONFIG_KEYS