aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Moore <paul.moore@hp.com>2008-10-10 10:16:32 -0400
committerPaul Moore <paul.moore@hp.com>2008-10-10 10:16:32 -0400
commit948bf85c1bc9a84754786a9d5dd99b7ecc46451e (patch)
treea4706be1f4a5a37408774ef3c4cab8cf2e7775b5
parent63c41688743760631188cf0f4ae986a6793ccb0a (diff)
netlabel: Add functionality to set the security attributes of a packet
This patch builds upon the new NetLabel address selector functionality by providing the NetLabel KAPI and CIPSO engine support needed to enable the new packet-based labeling. The only new addition to the NetLabel KAPI at this point is shown below: * int netlbl_skbuff_setattr(skb, family, secattr) ... and is designed to be called from a Netfilter hook after the packet's IP header has been populated such as in the FORWARD or LOCAL_OUT hooks. This patch also provides the necessary SELinux hooks to support this new functionality. Smack support is not currently included due to uncertainty regarding the permissions needed to expand the Smack network access controls. Signed-off-by: Paul Moore <paul.moore@hp.com> Reviewed-by: James Morris <jmorris@namei.org>
-rw-r--r--include/net/cipso_ipv4.h16
-rw-r--r--include/net/netlabel.h9
-rw-r--r--net/ipv4/cipso_ipv4.c222
-rw-r--r--net/netlabel/netlabel_kapi.c60
-rw-r--r--security/selinux/hooks.c50
-rw-r--r--security/selinux/include/netlabel.h9
-rw-r--r--security/selinux/include/objsec.h1
-rw-r--r--security/selinux/netlabel.c68
8 files changed, 393 insertions, 42 deletions
diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h
index 5fe6556fb3c5..2ce093ba553d 100644
--- a/include/net/cipso_ipv4.h
+++ b/include/net/cipso_ipv4.h
@@ -208,6 +208,10 @@ int cipso_v4_sock_setattr(struct sock *sk,
208 const struct cipso_v4_doi *doi_def, 208 const struct cipso_v4_doi *doi_def,
209 const struct netlbl_lsm_secattr *secattr); 209 const struct netlbl_lsm_secattr *secattr);
210int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr); 210int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr);
211int cipso_v4_skbuff_setattr(struct sk_buff *skb,
212 const struct cipso_v4_doi *doi_def,
213 const struct netlbl_lsm_secattr *secattr);
214int cipso_v4_skbuff_delattr(struct sk_buff *skb);
211int cipso_v4_skbuff_getattr(const struct sk_buff *skb, 215int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
212 struct netlbl_lsm_secattr *secattr); 216 struct netlbl_lsm_secattr *secattr);
213int cipso_v4_validate(unsigned char **option); 217int cipso_v4_validate(unsigned char **option);
@@ -232,6 +236,18 @@ static inline int cipso_v4_sock_getattr(struct sock *sk,
232 return -ENOSYS; 236 return -ENOSYS;
233} 237}
234 238
239static inline int cipso_v4_skbuff_setattr(struct sk_buff *skb,
240 const struct cipso_v4_doi *doi_def,
241 const struct netlbl_lsm_secattr *secattr)
242{
243 return -ENOSYS;
244}
245
246static inline int cipso_v4_skbuff_delattr(struct sk_buff *skb)
247{
248 return -ENOSYS;
249}
250
235static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb, 251static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
236 struct netlbl_lsm_secattr *secattr) 252 struct netlbl_lsm_secattr *secattr)
237{ 253{
diff --git a/include/net/netlabel.h b/include/net/netlabel.h
index 0729f8ce5042..3f67e6d49e40 100644
--- a/include/net/netlabel.h
+++ b/include/net/netlabel.h
@@ -382,6 +382,9 @@ int netlbl_sock_setattr(struct sock *sk,
382 const struct netlbl_lsm_secattr *secattr); 382 const struct netlbl_lsm_secattr *secattr);
383int netlbl_sock_getattr(struct sock *sk, 383int netlbl_sock_getattr(struct sock *sk,
384 struct netlbl_lsm_secattr *secattr); 384 struct netlbl_lsm_secattr *secattr);
385int netlbl_skbuff_setattr(struct sk_buff *skb,
386 u16 family,
387 const struct netlbl_lsm_secattr *secattr);
385int netlbl_skbuff_getattr(const struct sk_buff *skb, 388int netlbl_skbuff_getattr(const struct sk_buff *skb,
386 u16 family, 389 u16 family,
387 struct netlbl_lsm_secattr *secattr); 390 struct netlbl_lsm_secattr *secattr);
@@ -451,6 +454,12 @@ static inline int netlbl_sock_getattr(struct sock *sk,
451{ 454{
452 return -ENOSYS; 455 return -ENOSYS;
453} 456}
457static inline int netlbl_skbuff_setattr(struct sk_buff *skb,
458 u16 family,
459 const struct netlbl_lsm_secattr *secattr)
460{
461 return -ENOSYS;
462}
454static inline int netlbl_skbuff_getattr(const struct sk_buff *skb, 463static inline int netlbl_skbuff_getattr(const struct sk_buff *skb,
455 u16 family, 464 u16 family,
456 struct netlbl_lsm_secattr *secattr) 465 struct netlbl_lsm_secattr *secattr)
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index bf87eddfec30..e13d6dbb66ab 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -13,7 +13,7 @@
13 */ 13 */
14 14
15/* 15/*
16 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 16 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
17 * 17 *
18 * This program is free software; you can redistribute it and/or modify 18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by 19 * it under the terms of the GNU General Public License as published by
@@ -1665,48 +1665,27 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
1665} 1665}
1666 1666
1667/** 1667/**
1668 * cipso_v4_sock_setattr - Add a CIPSO option to a socket 1668 * cipso_v4_genopt - Generate a CIPSO option
1669 * @sk: the socket 1669 * @buf: the option buffer
1670 * @buf_len: the size of opt_buf
1670 * @doi_def: the CIPSO DOI to use 1671 * @doi_def: the CIPSO DOI to use
1671 * @secattr: the specific security attributes of the socket 1672 * @secattr: the security attributes
1672 * 1673 *
1673 * Description: 1674 * Description:
1674 * Set the CIPSO option on the given socket using the DOI definition and 1675 * Generate a CIPSO option using the DOI definition and security attributes
1675 * security attributes passed to the function. This function requires 1676 * passed to the function. Returns the length of the option on success and
1676 * exclusive access to @sk, which means it either needs to be in the 1677 * negative values on failure.
1677 * process of being created or locked. Returns zero on success and negative
1678 * values on failure.
1679 * 1678 *
1680 */ 1679 */
1681int cipso_v4_sock_setattr(struct sock *sk, 1680static int cipso_v4_genopt(unsigned char *buf, u32 buf_len,
1682 const struct cipso_v4_doi *doi_def, 1681 const struct cipso_v4_doi *doi_def,
1683 const struct netlbl_lsm_secattr *secattr) 1682 const struct netlbl_lsm_secattr *secattr)
1684{ 1683{
1685 int ret_val = -EPERM; 1684 int ret_val;
1686 u32 iter; 1685 u32 iter;
1687 unsigned char *buf;
1688 u32 buf_len = 0;
1689 u32 opt_len;
1690 struct ip_options *opt = NULL;
1691 struct inet_sock *sk_inet;
1692 struct inet_connection_sock *sk_conn;
1693
1694 /* In the case of sock_create_lite(), the sock->sk field is not
1695 * defined yet but it is not a problem as the only users of these
1696 * "lite" PF_INET sockets are functions which do an accept() call
1697 * afterwards so we will label the socket as part of the accept(). */
1698 if (sk == NULL)
1699 return 0;
1700 1686
1701 /* We allocate the maximum CIPSO option size here so we are probably 1687 if (buf_len <= CIPSO_V4_HDR_LEN)
1702 * being a little wasteful, but it makes our life _much_ easier later 1688 return -ENOSPC;
1703 * on and after all we are only talking about 40 bytes. */
1704 buf_len = CIPSO_V4_OPT_LEN_MAX;
1705 buf = kmalloc(buf_len, GFP_ATOMIC);
1706 if (buf == NULL) {
1707 ret_val = -ENOMEM;
1708 goto socket_setattr_failure;
1709 }
1710 1689
1711 /* XXX - This code assumes only one tag per CIPSO option which isn't 1690 /* XXX - This code assumes only one tag per CIPSO option which isn't
1712 * really a good assumption to make but since we only support the MAC 1691 * really a good assumption to make but since we only support the MAC
@@ -1734,8 +1713,7 @@ int cipso_v4_sock_setattr(struct sock *sk,
1734 buf_len - CIPSO_V4_HDR_LEN); 1713 buf_len - CIPSO_V4_HDR_LEN);
1735 break; 1714 break;
1736 default: 1715 default:
1737 ret_val = -EPERM; 1716 return -EPERM;
1738 goto socket_setattr_failure;
1739 } 1717 }
1740 1718
1741 iter++; 1719 iter++;
@@ -1743,9 +1721,58 @@ int cipso_v4_sock_setattr(struct sock *sk,
1743 iter < CIPSO_V4_TAG_MAXCNT && 1721 iter < CIPSO_V4_TAG_MAXCNT &&
1744 doi_def->tags[iter] != CIPSO_V4_TAG_INVALID); 1722 doi_def->tags[iter] != CIPSO_V4_TAG_INVALID);
1745 if (ret_val < 0) 1723 if (ret_val < 0)
1746 goto socket_setattr_failure; 1724 return ret_val;
1747 cipso_v4_gentag_hdr(doi_def, buf, ret_val); 1725 cipso_v4_gentag_hdr(doi_def, buf, ret_val);
1748 buf_len = CIPSO_V4_HDR_LEN + ret_val; 1726 return CIPSO_V4_HDR_LEN + ret_val;
1727}
1728
1729/**
1730 * cipso_v4_sock_setattr - Add a CIPSO option to a socket
1731 * @sk: the socket
1732 * @doi_def: the CIPSO DOI to use
1733 * @secattr: the specific security attributes of the socket
1734 *
1735 * Description:
1736 * Set the CIPSO option on the given socket using the DOI definition and
1737 * security attributes passed to the function. This function requires
1738 * exclusive access to @sk, which means it either needs to be in the
1739 * process of being created or locked. Returns zero on success and negative
1740 * values on failure.
1741 *
1742 */
1743int cipso_v4_sock_setattr(struct sock *sk,
1744 const struct cipso_v4_doi *doi_def,
1745 const struct netlbl_lsm_secattr *secattr)
1746{
1747 int ret_val = -EPERM;
1748 unsigned char *buf = NULL;
1749 u32 buf_len;
1750 u32 opt_len;
1751 struct ip_options *opt = NULL;
1752 struct inet_sock *sk_inet;
1753 struct inet_connection_sock *sk_conn;
1754
1755 /* In the case of sock_create_lite(), the sock->sk field is not
1756 * defined yet but it is not a problem as the only users of these
1757 * "lite" PF_INET sockets are functions which do an accept() call
1758 * afterwards so we will label the socket as part of the accept(). */
1759 if (sk == NULL)
1760 return 0;
1761
1762 /* We allocate the maximum CIPSO option size here so we are probably
1763 * being a little wasteful, but it makes our life _much_ easier later
1764 * on and after all we are only talking about 40 bytes. */
1765 buf_len = CIPSO_V4_OPT_LEN_MAX;
1766 buf = kmalloc(buf_len, GFP_ATOMIC);
1767 if (buf == NULL) {
1768 ret_val = -ENOMEM;
1769 goto socket_setattr_failure;
1770 }
1771
1772 ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
1773 if (ret_val < 0)
1774 goto socket_setattr_failure;
1775 buf_len = ret_val;
1749 1776
1750 /* We can't use ip_options_get() directly because it makes a call to 1777 /* We can't use ip_options_get() directly because it makes a call to
1751 * ip_options_get_alloc() which allocates memory with GFP_KERNEL and 1778 * ip_options_get_alloc() which allocates memory with GFP_KERNEL and
@@ -1854,6 +1881,123 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
1854} 1881}
1855 1882
1856/** 1883/**
1884 * cipso_v4_skbuff_setattr - Set the CIPSO option on a packet
1885 * @skb: the packet
1886 * @secattr: the security attributes
1887 *
1888 * Description:
1889 * Set the CIPSO option on the given packet based on the security attributes.
1890 * Returns a pointer to the IP header on success and NULL on failure.
1891 *
1892 */
1893int cipso_v4_skbuff_setattr(struct sk_buff *skb,
1894 const struct cipso_v4_doi *doi_def,
1895 const struct netlbl_lsm_secattr *secattr)
1896{
1897 int ret_val;
1898 struct iphdr *iph;
1899 struct ip_options *opt = &IPCB(skb)->opt;
1900 unsigned char buf[CIPSO_V4_OPT_LEN_MAX];
1901 u32 buf_len = CIPSO_V4_OPT_LEN_MAX;
1902 u32 opt_len;
1903 int len_delta;
1904
1905 buf_len = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
1906 if (buf_len < 0)
1907 return buf_len;
1908 opt_len = (buf_len + 3) & ~3;
1909
1910 /* we overwrite any existing options to ensure that we have enough
1911 * room for the CIPSO option, the reason is that we _need_ to guarantee
1912 * that the security label is applied to the packet - we do the same
1913 * thing when using the socket options and it hasn't caused a problem,
1914 * if we need to we can always revisit this choice later */
1915
1916 len_delta = opt_len - opt->optlen;
1917 /* if we don't ensure enough headroom we could panic on the skb_push()
1918 * call below so make sure we have enough, we are also "mangling" the
1919 * packet so we should probably do a copy-on-write call anyway */
1920 ret_val = skb_cow(skb, skb_headroom(skb) + len_delta);
1921 if (ret_val < 0)
1922 return ret_val;
1923
1924 if (len_delta > 0) {
1925 /* we assume that the header + opt->optlen have already been
1926 * "pushed" in ip_options_build() or similar */
1927 iph = ip_hdr(skb);
1928 skb_push(skb, len_delta);
1929 memmove((char *)iph - len_delta, iph, iph->ihl << 2);
1930 skb_reset_network_header(skb);
1931 iph = ip_hdr(skb);
1932 } else if (len_delta < 0) {
1933 iph = ip_hdr(skb);
1934 memset(iph + 1, IPOPT_NOP, opt->optlen);
1935 } else
1936 iph = ip_hdr(skb);
1937
1938 if (opt->optlen > 0)
1939 memset(opt, 0, sizeof(*opt));
1940 opt->optlen = opt_len;
1941 opt->cipso = sizeof(struct iphdr);
1942 opt->is_changed = 1;
1943
1944 /* we have to do the following because we are being called from a
1945 * netfilter hook which means the packet already has had the header
1946 * fields populated and the checksum calculated - yes this means we
1947 * are doing more work than needed but we do it to keep the core
1948 * stack clean and tidy */
1949 memcpy(iph + 1, buf, buf_len);
1950 if (opt_len > buf_len)
1951 memset((char *)(iph + 1) + buf_len, 0, opt_len - buf_len);
1952 if (len_delta != 0) {
1953 iph->ihl = 5 + (opt_len >> 2);
1954 iph->tot_len = htons(skb->len);
1955 }
1956 ip_send_check(iph);
1957
1958 return 0;
1959}
1960
1961/**
1962 * cipso_v4_skbuff_delattr - Delete any CIPSO options from a packet
1963 * @skb: the packet
1964 *
1965 * Description:
1966 * Removes any and all CIPSO options from the given packet. Returns zero on
1967 * success, negative values on failure.
1968 *
1969 */
1970int cipso_v4_skbuff_delattr(struct sk_buff *skb)
1971{
1972 int ret_val;
1973 struct iphdr *iph;
1974 struct ip_options *opt = &IPCB(skb)->opt;
1975 unsigned char *cipso_ptr;
1976
1977 if (opt->cipso == 0)
1978 return 0;
1979
1980 /* since we are changing the packet we should make a copy */
1981 ret_val = skb_cow(skb, skb_headroom(skb));
1982 if (ret_val < 0)
1983 return ret_val;
1984
1985 /* the easiest thing to do is just replace the cipso option with noop
1986 * options since we don't change the size of the packet, although we
1987 * still need to recalculate the checksum */
1988
1989 iph = ip_hdr(skb);
1990 cipso_ptr = (unsigned char *)iph + opt->cipso;
1991 memset(cipso_ptr, IPOPT_NOOP, cipso_ptr[1]);
1992 opt->cipso = 0;
1993 opt->is_changed = 1;
1994
1995 ip_send_check(iph);
1996
1997 return 0;
1998}
1999
2000/**
1857 * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option 2001 * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option
1858 * @skb: the packet 2002 * @skb: the packet
1859 * @secattr: the security attributes 2003 * @secattr: the security attributes
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
index 8b820dc98060..cc8047d1f505 100644
--- a/net/netlabel/netlabel_kapi.c
+++ b/net/netlabel/netlabel_kapi.c
@@ -473,6 +473,66 @@ int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
473} 473}
474 474
475/** 475/**
476 * netlbl_skbuff_setattr - Label a packet using the correct protocol
477 * @skb: the packet
478 * @family: protocol family
479 * @secattr: the security attributes
480 *
481 * Description:
482 * Attach the correct label to the given packet using the security attributes
483 * specified in @secattr. Returns zero on success, negative values on failure.
484 *
485 */
486int netlbl_skbuff_setattr(struct sk_buff *skb,
487 u16 family,
488 const struct netlbl_lsm_secattr *secattr)
489{
490 int ret_val;
491 struct iphdr *hdr4;
492 struct netlbl_domaddr4_map *af4_entry;
493
494 rcu_read_lock();
495 switch (family) {
496 case AF_INET:
497 hdr4 = ip_hdr(skb);
498 af4_entry = netlbl_domhsh_getentry_af4(secattr->domain,
499 hdr4->daddr);
500 if (af4_entry == NULL) {
501 ret_val = -ENOENT;
502 goto skbuff_setattr_return;
503 }
504 switch (af4_entry->type) {
505 case NETLBL_NLTYPE_CIPSOV4:
506 ret_val = cipso_v4_skbuff_setattr(skb,
507 af4_entry->type_def.cipsov4,
508 secattr);
509 break;
510 case NETLBL_NLTYPE_UNLABELED:
511 /* just delete the protocols we support for right now
512 * but we could remove other protocols if needed */
513 ret_val = cipso_v4_skbuff_delattr(skb);
514 break;
515 default:
516 ret_val = -ENOENT;
517 }
518 break;
519#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
520 case AF_INET6:
521 /* since we don't support any IPv6 labeling protocols right
522 * now we can optimize everything away until we do */
523 ret_val = 0;
524 break;
525#endif /* IPv6 */
526 default:
527 ret_val = 0;
528 }
529
530skbuff_setattr_return:
531 rcu_read_unlock();
532 return ret_val;
533}
534
535/**
476 * netlbl_skbuff_getattr - Determine the security attributes of a packet 536 * netlbl_skbuff_getattr - Determine the security attributes of a packet
477 * @skb: the packet 537 * @skb: the packet
478 * @family: protocol family 538 * @family: protocol family
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index a91146a6b37d..7432bdd5d367 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4407,13 +4407,15 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4407 u32 peer_sid; 4407 u32 peer_sid;
4408 struct avc_audit_data ad; 4408 struct avc_audit_data ad;
4409 u8 secmark_active; 4409 u8 secmark_active;
4410 u8 netlbl_active;
4410 u8 peerlbl_active; 4411 u8 peerlbl_active;
4411 4412
4412 if (!selinux_policycap_netpeer) 4413 if (!selinux_policycap_netpeer)
4413 return NF_ACCEPT; 4414 return NF_ACCEPT;
4414 4415
4415 secmark_active = selinux_secmark_enabled(); 4416 secmark_active = selinux_secmark_enabled();
4416 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); 4417 netlbl_active = netlbl_enabled();
4418 peerlbl_active = netlbl_active || selinux_xfrm_enabled();
4417 if (!secmark_active && !peerlbl_active) 4419 if (!secmark_active && !peerlbl_active)
4418 return NF_ACCEPT; 4420 return NF_ACCEPT;
4419 4421
@@ -4440,6 +4442,14 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4440 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad)) 4442 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
4441 return NF_DROP; 4443 return NF_DROP;
4442 4444
4445 if (netlbl_active)
4446 /* we do this in the FORWARD path and not the POST_ROUTING
4447 * path because we want to make sure we apply the necessary
4448 * labeling before IPsec is applied so we can leverage AH
4449 * protection */
4450 if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
4451 return NF_DROP;
4452
4443 return NF_ACCEPT; 4453 return NF_ACCEPT;
4444} 4454}
4445 4455
@@ -4463,6 +4473,37 @@ static unsigned int selinux_ipv6_forward(unsigned int hooknum,
4463} 4473}
4464#endif /* IPV6 */ 4474#endif /* IPV6 */
4465 4475
4476static unsigned int selinux_ip_output(struct sk_buff *skb,
4477 u16 family)
4478{
4479 u32 sid;
4480
4481 if (!netlbl_enabled())
4482 return NF_ACCEPT;
4483
4484 /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
4485 * because we want to make sure we apply the necessary labeling
4486 * before IPsec is applied so we can leverage AH protection */
4487 if (skb->sk) {
4488 struct sk_security_struct *sksec = skb->sk->sk_security;
4489 sid = sksec->sid;
4490 } else
4491 sid = SECINITSID_KERNEL;
4492 if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
4493 return NF_DROP;
4494
4495 return NF_ACCEPT;
4496}
4497
4498static unsigned int selinux_ipv4_output(unsigned int hooknum,
4499 struct sk_buff *skb,
4500 const struct net_device *in,
4501 const struct net_device *out,
4502 int (*okfn)(struct sk_buff *))
4503{
4504 return selinux_ip_output(skb, PF_INET);
4505}
4506
4466static int selinux_ip_postroute_iptables_compat(struct sock *sk, 4507static int selinux_ip_postroute_iptables_compat(struct sock *sk,
4467 int ifindex, 4508 int ifindex,
4468 struct avc_audit_data *ad, 4509 struct avc_audit_data *ad,
@@ -5700,6 +5741,13 @@ static struct nf_hook_ops selinux_ipv4_ops[] = {
5700 .pf = PF_INET, 5741 .pf = PF_INET,
5701 .hooknum = NF_INET_FORWARD, 5742 .hooknum = NF_INET_FORWARD,
5702 .priority = NF_IP_PRI_SELINUX_FIRST, 5743 .priority = NF_IP_PRI_SELINUX_FIRST,
5744 },
5745 {
5746 .hook = selinux_ipv4_output,
5747 .owner = THIS_MODULE,
5748 .pf = PF_INET,
5749 .hooknum = NF_INET_LOCAL_OUT,
5750 .priority = NF_IP_PRI_SELINUX_FIRST,
5703 } 5751 }
5704}; 5752};
5705 5753
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h
index d4e3ac8a7fbf..b3e6ae071fc3 100644
--- a/security/selinux/include/netlabel.h
+++ b/security/selinux/include/netlabel.h
@@ -48,6 +48,9 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
48 u16 family, 48 u16 family,
49 u32 *type, 49 u32 *type,
50 u32 *sid); 50 u32 *sid);
51int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
52 u16 family,
53 u32 sid);
51 54
52void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock); 55void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock);
53int selinux_netlbl_socket_post_create(struct socket *sock); 56int selinux_netlbl_socket_post_create(struct socket *sock);
@@ -88,6 +91,12 @@ static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
88 *sid = SECSID_NULL; 91 *sid = SECSID_NULL;
89 return 0; 92 return 0;
90} 93}
94static inline int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
95 u16 family,
96 u32 sid)
97{
98 return 0;
99}
91 100
92static inline void selinux_netlbl_sock_graft(struct sock *sk, 101static inline void selinux_netlbl_sock_graft(struct sock *sk,
93 struct socket *sock) 102 struct socket *sock)
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 91070ab874ce..f46dd1c3d01c 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -117,6 +117,7 @@ struct sk_security_struct {
117 NLBL_UNSET = 0, 117 NLBL_UNSET = 0,
118 NLBL_REQUIRE, 118 NLBL_REQUIRE,
119 NLBL_LABELED, 119 NLBL_LABELED,
120 NLBL_REQSKB,
120 } nlbl_state; 121 } nlbl_state;
121#endif 122#endif
122}; 123};
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index 4053f7fc95fb..090404d6e512 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -9,7 +9,7 @@
9 */ 9 */
10 10
11/* 11/*
12 * (c) Copyright Hewlett-Packard Development Company, L.P., 2007 12 * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008
13 * 13 *
14 * This program is free software; you can redistribute it and/or modify 14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by 15 * it under the terms of the GNU General Public License as published by
@@ -31,6 +31,8 @@
31#include <linux/rcupdate.h> 31#include <linux/rcupdate.h>
32#include <net/sock.h> 32#include <net/sock.h>
33#include <net/netlabel.h> 33#include <net/netlabel.h>
34#include <net/inet_sock.h>
35#include <net/inet_connection_sock.h>
34 36
35#include "objsec.h" 37#include "objsec.h"
36#include "security.h" 38#include "security.h"
@@ -77,6 +79,8 @@ static int selinux_netlbl_sock_setsid(struct sock *sk)
77 int rc; 79 int rc;
78 struct sk_security_struct *sksec = sk->sk_security; 80 struct sk_security_struct *sksec = sk->sk_security;
79 struct netlbl_lsm_secattr secattr; 81 struct netlbl_lsm_secattr secattr;
82 struct inet_sock *sk_inet;
83 struct inet_connection_sock *sk_conn;
80 84
81 if (sksec->nlbl_state != NLBL_REQUIRE) 85 if (sksec->nlbl_state != NLBL_REQUIRE)
82 return 0; 86 return 0;
@@ -87,8 +91,29 @@ static int selinux_netlbl_sock_setsid(struct sock *sk)
87 if (rc != 0) 91 if (rc != 0)
88 goto sock_setsid_return; 92 goto sock_setsid_return;
89 rc = netlbl_sock_setattr(sk, &secattr); 93 rc = netlbl_sock_setattr(sk, &secattr);
90 if (rc == 0) 94 switch (rc) {
95 case 0:
91 sksec->nlbl_state = NLBL_LABELED; 96 sksec->nlbl_state = NLBL_LABELED;
97 break;
98 case -EDESTADDRREQ:
99 /* we are going to possibly end up labeling the individual
100 * packets later which is problematic for stream sockets
101 * because of the additional IP header size, our solution is to
102 * allow for the maximum IP header length (40 bytes for IPv4,
103 * we don't have to worry about IPv6 yet) just in case */
104 sk_inet = inet_sk(sk);
105 if (sk_inet->is_icsk) {
106 sk_conn = inet_csk(sk);
107 if (sk_inet->opt)
108 sk_conn->icsk_ext_hdr_len -=
109 sk_inet->opt->optlen;
110 sk_conn->icsk_ext_hdr_len += 40;
111 sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
112 }
113 sksec->nlbl_state = NLBL_REQSKB;
114 rc = 0;
115 break;
116 }
92 117
93sock_setsid_return: 118sock_setsid_return:
94 netlbl_secattr_destroy(&secattr); 119 netlbl_secattr_destroy(&secattr);
@@ -183,6 +208,45 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
183} 208}
184 209
185/** 210/**
211 * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid
212 * @skb: the packet
213 * @family: protocol family
214 * @sid: the SID
215 *
216 * Description
217 * Call the NetLabel mechanism to set the label of a packet using @sid.
218 * Returns zero on auccess, negative values on failure.
219 *
220 */
221int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
222 u16 family,
223 u32 sid)
224{
225 int rc;
226 struct netlbl_lsm_secattr secattr;
227 struct sock *sk;
228
229 /* if this is a locally generated packet check to see if it is already
230 * being labeled by it's parent socket, if it is just exit */
231 sk = skb->sk;
232 if (sk != NULL) {
233 struct sk_security_struct *sksec = sk->sk_security;
234 if (sksec->nlbl_state != NLBL_REQSKB)
235 return 0;
236 }
237
238 netlbl_secattr_init(&secattr);
239 rc = security_netlbl_sid_to_secattr(sid, &secattr);
240 if (rc != 0)
241 goto skbuff_setsid_return;
242 rc = netlbl_skbuff_setattr(skb, family, &secattr);
243
244skbuff_setsid_return:
245 netlbl_secattr_destroy(&secattr);
246 return rc;
247}
248
249/**
186 * selinux_netlbl_sock_graft - Netlabel the new socket 250 * selinux_netlbl_sock_graft - Netlabel the new socket
187 * @sk: the new connection 251 * @sk: the new connection
188 * @sock: the new socket 252 * @sock: the new socket