diff options
-rw-r--r-- | include/net/cipso_ipv4.h | 16 | ||||
-rw-r--r-- | include/net/netlabel.h | 9 | ||||
-rw-r--r-- | net/ipv4/cipso_ipv4.c | 222 | ||||
-rw-r--r-- | net/netlabel/netlabel_kapi.c | 60 | ||||
-rw-r--r-- | security/selinux/hooks.c | 50 | ||||
-rw-r--r-- | security/selinux/include/netlabel.h | 9 | ||||
-rw-r--r-- | security/selinux/include/objsec.h | 1 | ||||
-rw-r--r-- | security/selinux/netlabel.c | 68 |
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); |
210 | int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr); | 210 | int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr); |
211 | int cipso_v4_skbuff_setattr(struct sk_buff *skb, | ||
212 | const struct cipso_v4_doi *doi_def, | ||
213 | const struct netlbl_lsm_secattr *secattr); | ||
214 | int cipso_v4_skbuff_delattr(struct sk_buff *skb); | ||
211 | int cipso_v4_skbuff_getattr(const struct sk_buff *skb, | 215 | int cipso_v4_skbuff_getattr(const struct sk_buff *skb, |
212 | struct netlbl_lsm_secattr *secattr); | 216 | struct netlbl_lsm_secattr *secattr); |
213 | int cipso_v4_validate(unsigned char **option); | 217 | int 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 | ||
239 | static 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 | |||
246 | static inline int cipso_v4_skbuff_delattr(struct sk_buff *skb) | ||
247 | { | ||
248 | return -ENOSYS; | ||
249 | } | ||
250 | |||
235 | static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb, | 251 | static 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); |
383 | int netlbl_sock_getattr(struct sock *sk, | 383 | int netlbl_sock_getattr(struct sock *sk, |
384 | struct netlbl_lsm_secattr *secattr); | 384 | struct netlbl_lsm_secattr *secattr); |
385 | int netlbl_skbuff_setattr(struct sk_buff *skb, | ||
386 | u16 family, | ||
387 | const struct netlbl_lsm_secattr *secattr); | ||
385 | int netlbl_skbuff_getattr(const struct sk_buff *skb, | 388 | int 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 | } |
457 | static inline int netlbl_skbuff_setattr(struct sk_buff *skb, | ||
458 | u16 family, | ||
459 | const struct netlbl_lsm_secattr *secattr) | ||
460 | { | ||
461 | return -ENOSYS; | ||
462 | } | ||
454 | static inline int netlbl_skbuff_getattr(const struct sk_buff *skb, | 463 | static 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 | */ |
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 |
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 | */ | ||
486 | int 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 | |||
530 | skbuff_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 | ||
4476 | static 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 | |||
4498 | static 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 | |||
4466 | static int selinux_ip_postroute_iptables_compat(struct sock *sk, | 4507 | static 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); |
51 | int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | ||
52 | u16 family, | ||
53 | u32 sid); | ||
51 | 54 | ||
52 | void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock); | 55 | void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock); |
53 | int selinux_netlbl_socket_post_create(struct socket *sock); | 56 | int 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 | } |
94 | static inline int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | ||
95 | u16 family, | ||
96 | u32 sid) | ||
97 | { | ||
98 | return 0; | ||
99 | } | ||
91 | 100 | ||
92 | static inline void selinux_netlbl_sock_graft(struct sock *sk, | 101 | static 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 | ||
93 | sock_setsid_return: | 118 | sock_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 | */ | ||
221 | int 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 | |||
244 | skbuff_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 |