aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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