diff options
Diffstat (limited to 'net/ipv4/cipso_ipv4.c')
-rw-r--r-- | net/ipv4/cipso_ipv4.c | 222 |
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 | */ |
1681 | int cipso_v4_sock_setattr(struct sock *sk, | 1680 | static 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 | */ | ||
1743 | int 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 | */ | ||
1893 | int 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 | */ | ||
1970 | int 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 |