aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
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 /net/ipv4
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>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/cipso_ipv4.c222
1 files changed, 183 insertions, 39 deletions
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