diff options
-rw-r--r-- | include/net/cipso_ipv4.h | 5 | ||||
-rw-r--r-- | include/net/netlabel.h | 13 | ||||
-rw-r--r-- | net/ipv4/cipso_ipv4.c | 74 | ||||
-rw-r--r-- | net/netlabel/netlabel_kapi.c | 78 | ||||
-rw-r--r-- | security/selinux/hooks.c | 11 | ||||
-rw-r--r-- | security/selinux/include/netlabel.h | 19 | ||||
-rw-r--r-- | security/selinux/include/objsec.h | 1 | ||||
-rw-r--r-- | security/selinux/netlabel.c | 147 |
8 files changed, 311 insertions, 37 deletions
diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h index 2ce093ba553d..811febf97caf 100644 --- a/include/net/cipso_ipv4.h +++ b/include/net/cipso_ipv4.h | |||
@@ -207,6 +207,7 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway); | |||
207 | int cipso_v4_sock_setattr(struct sock *sk, | 207 | 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 | void cipso_v4_sock_delattr(struct sock *sk); | ||
210 | int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr); | 211 | int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr); |
211 | int cipso_v4_skbuff_setattr(struct sk_buff *skb, | 212 | int cipso_v4_skbuff_setattr(struct sk_buff *skb, |
212 | const struct cipso_v4_doi *doi_def, | 213 | const struct cipso_v4_doi *doi_def, |
@@ -230,6 +231,10 @@ static inline int cipso_v4_sock_setattr(struct sock *sk, | |||
230 | return -ENOSYS; | 231 | return -ENOSYS; |
231 | } | 232 | } |
232 | 233 | ||
234 | static inline void cipso_v4_sock_delattr(struct sock *sk) | ||
235 | { | ||
236 | } | ||
237 | |||
233 | static inline int cipso_v4_sock_getattr(struct sock *sk, | 238 | static inline int cipso_v4_sock_getattr(struct sock *sk, |
234 | struct netlbl_lsm_secattr *secattr) | 239 | struct netlbl_lsm_secattr *secattr) |
235 | { | 240 | { |
diff --git a/include/net/netlabel.h b/include/net/netlabel.h index 3f67e6d49e40..074cad40ac66 100644 --- a/include/net/netlabel.h +++ b/include/net/netlabel.h | |||
@@ -380,8 +380,12 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap, | |||
380 | int netlbl_enabled(void); | 380 | int netlbl_enabled(void); |
381 | int netlbl_sock_setattr(struct sock *sk, | 381 | int netlbl_sock_setattr(struct sock *sk, |
382 | const struct netlbl_lsm_secattr *secattr); | 382 | const struct netlbl_lsm_secattr *secattr); |
383 | void netlbl_sock_delattr(struct sock *sk); | ||
383 | int netlbl_sock_getattr(struct sock *sk, | 384 | int netlbl_sock_getattr(struct sock *sk, |
384 | struct netlbl_lsm_secattr *secattr); | 385 | struct netlbl_lsm_secattr *secattr); |
386 | int netlbl_conn_setattr(struct sock *sk, | ||
387 | struct sockaddr *addr, | ||
388 | const struct netlbl_lsm_secattr *secattr); | ||
385 | int netlbl_skbuff_setattr(struct sk_buff *skb, | 389 | int netlbl_skbuff_setattr(struct sk_buff *skb, |
386 | u16 family, | 390 | u16 family, |
387 | const struct netlbl_lsm_secattr *secattr); | 391 | const struct netlbl_lsm_secattr *secattr); |
@@ -449,11 +453,20 @@ static inline int netlbl_sock_setattr(struct sock *sk, | |||
449 | { | 453 | { |
450 | return -ENOSYS; | 454 | return -ENOSYS; |
451 | } | 455 | } |
456 | static inline void netlbl_sock_delattr(struct sock *sk) | ||
457 | { | ||
458 | } | ||
452 | static inline int netlbl_sock_getattr(struct sock *sk, | 459 | static inline int netlbl_sock_getattr(struct sock *sk, |
453 | struct netlbl_lsm_secattr *secattr) | 460 | struct netlbl_lsm_secattr *secattr) |
454 | { | 461 | { |
455 | return -ENOSYS; | 462 | return -ENOSYS; |
456 | } | 463 | } |
464 | static inline int netlbl_conn_setattr(struct sock *sk, | ||
465 | struct sockaddr *addr, | ||
466 | const struct netlbl_lsm_secattr *secattr) | ||
467 | { | ||
468 | return -ENOSYS; | ||
469 | } | ||
457 | static inline int netlbl_skbuff_setattr(struct sk_buff *skb, | 470 | static inline int netlbl_skbuff_setattr(struct sk_buff *skb, |
458 | u16 family, | 471 | u16 family, |
459 | const struct netlbl_lsm_secattr *secattr) | 472 | const struct netlbl_lsm_secattr *secattr) |
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index e13d6dbb66ab..23768b9d6b64 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c | |||
@@ -1810,6 +1810,80 @@ socket_setattr_failure: | |||
1810 | } | 1810 | } |
1811 | 1811 | ||
1812 | /** | 1812 | /** |
1813 | * cipso_v4_sock_delattr - Delete the CIPSO option from a socket | ||
1814 | * @sk: the socket | ||
1815 | * | ||
1816 | * Description: | ||
1817 | * Removes the CIPSO option from a socket, if present. | ||
1818 | * | ||
1819 | */ | ||
1820 | void cipso_v4_sock_delattr(struct sock *sk) | ||
1821 | { | ||
1822 | u8 hdr_delta; | ||
1823 | struct ip_options *opt; | ||
1824 | struct inet_sock *sk_inet; | ||
1825 | |||
1826 | sk_inet = inet_sk(sk); | ||
1827 | opt = sk_inet->opt; | ||
1828 | if (opt == NULL || opt->cipso == 0) | ||
1829 | return; | ||
1830 | |||
1831 | if (opt->srr || opt->rr || opt->ts || opt->router_alert) { | ||
1832 | u8 cipso_len; | ||
1833 | u8 cipso_off; | ||
1834 | unsigned char *cipso_ptr; | ||
1835 | int iter; | ||
1836 | int optlen_new; | ||
1837 | |||
1838 | cipso_off = opt->cipso - sizeof(struct iphdr); | ||
1839 | cipso_ptr = &opt->__data[cipso_off]; | ||
1840 | cipso_len = cipso_ptr[1]; | ||
1841 | |||
1842 | if (opt->srr > opt->cipso) | ||
1843 | opt->srr -= cipso_len; | ||
1844 | if (opt->rr > opt->cipso) | ||
1845 | opt->rr -= cipso_len; | ||
1846 | if (opt->ts > opt->cipso) | ||
1847 | opt->ts -= cipso_len; | ||
1848 | if (opt->router_alert > opt->cipso) | ||
1849 | opt->router_alert -= cipso_len; | ||
1850 | opt->cipso = 0; | ||
1851 | |||
1852 | memmove(cipso_ptr, cipso_ptr + cipso_len, | ||
1853 | opt->optlen - cipso_off - cipso_len); | ||
1854 | |||
1855 | /* determining the new total option length is tricky because of | ||
1856 | * the padding necessary, the only thing i can think to do at | ||
1857 | * this point is walk the options one-by-one, skipping the | ||
1858 | * padding at the end to determine the actual option size and | ||
1859 | * from there we can determine the new total option length */ | ||
1860 | iter = 0; | ||
1861 | optlen_new = 0; | ||
1862 | while (iter < opt->optlen) | ||
1863 | if (opt->__data[iter] != IPOPT_NOP) { | ||
1864 | iter += opt->__data[iter + 1]; | ||
1865 | optlen_new = iter; | ||
1866 | } else | ||
1867 | iter++; | ||
1868 | hdr_delta = opt->optlen; | ||
1869 | opt->optlen = (optlen_new + 3) & ~3; | ||
1870 | hdr_delta -= opt->optlen; | ||
1871 | } else { | ||
1872 | /* only the cipso option was present on the socket so we can | ||
1873 | * remove the entire option struct */ | ||
1874 | sk_inet->opt = NULL; | ||
1875 | hdr_delta = opt->optlen; | ||
1876 | kfree(opt); | ||
1877 | } | ||
1878 | |||
1879 | if (sk_inet->is_icsk && hdr_delta > 0) { | ||
1880 | struct inet_connection_sock *sk_conn = inet_csk(sk); | ||
1881 | sk_conn->icsk_ext_hdr_len -= hdr_delta; | ||
1882 | sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie); | ||
1883 | } | ||
1884 | } | ||
1885 | |||
1886 | /** | ||
1813 | * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions | 1887 | * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions |
1814 | * @cipso: the CIPSO v4 option | 1888 | * @cipso: the CIPSO v4 option |
1815 | * @secattr: the security attributes | 1889 | * @secattr: the security attributes |
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index cc8047d1f505..78fc557689b2 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c | |||
@@ -10,7 +10,7 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | /* | 12 | /* |
13 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | 13 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 |
14 | * | 14 | * |
15 | * This program is free software; you can redistribute it and/or modify | 15 | * This program is free software; you can redistribute it and/or modify |
16 | * it under the terms of the GNU General Public License as published by | 16 | * it under the terms of the GNU General Public License as published by |
@@ -456,6 +456,20 @@ socket_setattr_return: | |||
456 | } | 456 | } |
457 | 457 | ||
458 | /** | 458 | /** |
459 | * netlbl_sock_delattr - Delete all the NetLabel labels on a socket | ||
460 | * @sk: the socket | ||
461 | * | ||
462 | * Description: | ||
463 | * Remove all the NetLabel labeling from @sk. The caller is responsible for | ||
464 | * ensuring that @sk is locked. | ||
465 | * | ||
466 | */ | ||
467 | void netlbl_sock_delattr(struct sock *sk) | ||
468 | { | ||
469 | cipso_v4_sock_delattr(sk); | ||
470 | } | ||
471 | |||
472 | /** | ||
459 | * netlbl_sock_getattr - Determine the security attributes of a sock | 473 | * netlbl_sock_getattr - Determine the security attributes of a sock |
460 | * @sk: the sock | 474 | * @sk: the sock |
461 | * @secattr: the security attributes | 475 | * @secattr: the security attributes |
@@ -473,6 +487,68 @@ int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) | |||
473 | } | 487 | } |
474 | 488 | ||
475 | /** | 489 | /** |
490 | * netlbl_conn_setattr - Label a connected socket using the correct protocol | ||
491 | * @sk: the socket to label | ||
492 | * @addr: the destination address | ||
493 | * @secattr: the security attributes | ||
494 | * | ||
495 | * Description: | ||
496 | * Attach the correct label to the given connected socket using the security | ||
497 | * attributes specified in @secattr. The caller is responsible for ensuring | ||
498 | * that @sk is locked. Returns zero on success, negative values on failure. | ||
499 | * | ||
500 | */ | ||
501 | int netlbl_conn_setattr(struct sock *sk, | ||
502 | struct sockaddr *addr, | ||
503 | const struct netlbl_lsm_secattr *secattr) | ||
504 | { | ||
505 | int ret_val; | ||
506 | struct sockaddr_in *addr4; | ||
507 | struct netlbl_domaddr4_map *af4_entry; | ||
508 | |||
509 | rcu_read_lock(); | ||
510 | switch (addr->sa_family) { | ||
511 | case AF_INET: | ||
512 | addr4 = (struct sockaddr_in *)addr; | ||
513 | af4_entry = netlbl_domhsh_getentry_af4(secattr->domain, | ||
514 | addr4->sin_addr.s_addr); | ||
515 | if (af4_entry == NULL) { | ||
516 | ret_val = -ENOENT; | ||
517 | goto conn_setattr_return; | ||
518 | } | ||
519 | switch (af4_entry->type) { | ||
520 | case NETLBL_NLTYPE_CIPSOV4: | ||
521 | ret_val = cipso_v4_sock_setattr(sk, | ||
522 | af4_entry->type_def.cipsov4, | ||
523 | secattr); | ||
524 | break; | ||
525 | case NETLBL_NLTYPE_UNLABELED: | ||
526 | /* just delete the protocols we support for right now | ||
527 | * but we could remove other protocols if needed */ | ||
528 | cipso_v4_sock_delattr(sk); | ||
529 | ret_val = 0; | ||
530 | break; | ||
531 | default: | ||
532 | ret_val = -ENOENT; | ||
533 | } | ||
534 | break; | ||
535 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
536 | case AF_INET6: | ||
537 | /* since we don't support any IPv6 labeling protocols right | ||
538 | * now we can optimize everything away until we do */ | ||
539 | ret_val = 0; | ||
540 | break; | ||
541 | #endif /* IPv6 */ | ||
542 | default: | ||
543 | ret_val = 0; | ||
544 | } | ||
545 | |||
546 | conn_setattr_return: | ||
547 | rcu_read_unlock(); | ||
548 | return ret_val; | ||
549 | } | ||
550 | |||
551 | /** | ||
476 | * netlbl_skbuff_setattr - Label a packet using the correct protocol | 552 | * netlbl_skbuff_setattr - Label a packet using the correct protocol |
477 | * @skb: the packet | 553 | * @skb: the packet |
478 | * @family: protocol family | 554 | * @family: protocol family |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 7432bdd5d367..632ac3e80a61 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -3794,6 +3794,7 @@ out: | |||
3794 | 3794 | ||
3795 | static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) | 3795 | static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) |
3796 | { | 3796 | { |
3797 | struct sock *sk = sock->sk; | ||
3797 | struct inode_security_struct *isec; | 3798 | struct inode_security_struct *isec; |
3798 | int err; | 3799 | int err; |
3799 | 3800 | ||
@@ -3807,7 +3808,6 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
3807 | isec = SOCK_INODE(sock)->i_security; | 3808 | isec = SOCK_INODE(sock)->i_security; |
3808 | if (isec->sclass == SECCLASS_TCP_SOCKET || | 3809 | if (isec->sclass == SECCLASS_TCP_SOCKET || |
3809 | isec->sclass == SECCLASS_DCCP_SOCKET) { | 3810 | isec->sclass == SECCLASS_DCCP_SOCKET) { |
3810 | struct sock *sk = sock->sk; | ||
3811 | struct avc_audit_data ad; | 3811 | struct avc_audit_data ad; |
3812 | struct sockaddr_in *addr4 = NULL; | 3812 | struct sockaddr_in *addr4 = NULL; |
3813 | struct sockaddr_in6 *addr6 = NULL; | 3813 | struct sockaddr_in6 *addr6 = NULL; |
@@ -3841,6 +3841,8 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
3841 | goto out; | 3841 | goto out; |
3842 | } | 3842 | } |
3843 | 3843 | ||
3844 | err = selinux_netlbl_socket_connect(sk, address); | ||
3845 | |||
3844 | out: | 3846 | out: |
3845 | return err; | 3847 | return err; |
3846 | } | 3848 | } |
@@ -4290,8 +4292,6 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent) | |||
4290 | sk->sk_family == PF_UNIX) | 4292 | sk->sk_family == PF_UNIX) |
4291 | isec->sid = sksec->sid; | 4293 | isec->sid = sksec->sid; |
4292 | sksec->sclass = isec->sclass; | 4294 | sksec->sclass = isec->sclass; |
4293 | |||
4294 | selinux_netlbl_sock_graft(sk, parent); | ||
4295 | } | 4295 | } |
4296 | 4296 | ||
4297 | static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | 4297 | static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, |
@@ -4342,8 +4342,7 @@ static void selinux_inet_csk_clone(struct sock *newsk, | |||
4342 | selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family); | 4342 | selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family); |
4343 | } | 4343 | } |
4344 | 4344 | ||
4345 | static void selinux_inet_conn_established(struct sock *sk, | 4345 | static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) |
4346 | struct sk_buff *skb) | ||
4347 | { | 4346 | { |
4348 | u16 family = sk->sk_family; | 4347 | u16 family = sk->sk_family; |
4349 | struct sk_security_struct *sksec = sk->sk_security; | 4348 | struct sk_security_struct *sksec = sk->sk_security; |
@@ -4353,6 +4352,8 @@ static void selinux_inet_conn_established(struct sock *sk, | |||
4353 | family = PF_INET; | 4352 | family = PF_INET; |
4354 | 4353 | ||
4355 | selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); | 4354 | selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); |
4355 | |||
4356 | selinux_netlbl_inet_conn_established(sk, family); | ||
4356 | } | 4357 | } |
4357 | 4358 | ||
4358 | static void selinux_req_classify_flow(const struct request_sock *req, | 4359 | static void selinux_req_classify_flow(const struct request_sock *req, |
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index b3e6ae071fc3..982bac0ac328 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h | |||
@@ -52,7 +52,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | |||
52 | u16 family, | 52 | u16 family, |
53 | u32 sid); | 53 | u32 sid); |
54 | 54 | ||
55 | void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock); | 55 | void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family); |
56 | int selinux_netlbl_socket_post_create(struct socket *sock); | 56 | int selinux_netlbl_socket_post_create(struct socket *sock); |
57 | int selinux_netlbl_inode_permission(struct inode *inode, int mask); | 57 | int selinux_netlbl_inode_permission(struct inode *inode, int mask); |
58 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | 58 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, |
@@ -62,6 +62,8 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | |||
62 | int selinux_netlbl_socket_setsockopt(struct socket *sock, | 62 | int selinux_netlbl_socket_setsockopt(struct socket *sock, |
63 | int level, | 63 | int level, |
64 | int optname); | 64 | int optname); |
65 | int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr); | ||
66 | |||
65 | #else | 67 | #else |
66 | static inline void selinux_netlbl_cache_invalidate(void) | 68 | static inline void selinux_netlbl_cache_invalidate(void) |
67 | { | 69 | { |
@@ -98,8 +100,14 @@ static inline int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | |||
98 | return 0; | 100 | return 0; |
99 | } | 101 | } |
100 | 102 | ||
101 | static inline void selinux_netlbl_sock_graft(struct sock *sk, | 103 | static inline int selinux_netlbl_conn_setsid(struct sock *sk, |
102 | struct socket *sock) | 104 | struct sockaddr *addr) |
105 | { | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static inline void selinux_netlbl_inet_conn_established(struct sock *sk, | ||
110 | u16 family) | ||
103 | { | 111 | { |
104 | return; | 112 | return; |
105 | } | 113 | } |
@@ -125,6 +133,11 @@ static inline int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
125 | { | 133 | { |
126 | return 0; | 134 | return 0; |
127 | } | 135 | } |
136 | static inline int selinux_netlbl_socket_connect(struct sock *sk, | ||
137 | struct sockaddr *addr) | ||
138 | { | ||
139 | return 0; | ||
140 | } | ||
128 | #endif /* CONFIG_NETLABEL */ | 141 | #endif /* CONFIG_NETLABEL */ |
129 | 142 | ||
130 | #endif | 143 | #endif |
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index f46dd1c3d01c..ad34787c6c02 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
@@ -118,6 +118,7 @@ struct sk_security_struct { | |||
118 | NLBL_REQUIRE, | 118 | NLBL_REQUIRE, |
119 | NLBL_LABELED, | 119 | NLBL_LABELED, |
120 | NLBL_REQSKB, | 120 | NLBL_REQSKB, |
121 | NLBL_CONNLABELED, | ||
121 | } nlbl_state; | 122 | } nlbl_state; |
122 | #endif | 123 | #endif |
123 | }; | 124 | }; |
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 090404d6e512..b22b7dafa0e3 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c | |||
@@ -29,10 +29,12 @@ | |||
29 | 29 | ||
30 | #include <linux/spinlock.h> | 30 | #include <linux/spinlock.h> |
31 | #include <linux/rcupdate.h> | 31 | #include <linux/rcupdate.h> |
32 | #include <linux/ip.h> | ||
33 | #include <linux/ipv6.h> | ||
32 | #include <net/sock.h> | 34 | #include <net/sock.h> |
33 | #include <net/netlabel.h> | 35 | #include <net/netlabel.h> |
34 | #include <net/inet_sock.h> | 36 | #include <net/ip.h> |
35 | #include <net/inet_connection_sock.h> | 37 | #include <net/ipv6.h> |
36 | 38 | ||
37 | #include "objsec.h" | 39 | #include "objsec.h" |
38 | #include "security.h" | 40 | #include "security.h" |
@@ -79,8 +81,6 @@ static int selinux_netlbl_sock_setsid(struct sock *sk) | |||
79 | int rc; | 81 | int rc; |
80 | struct sk_security_struct *sksec = sk->sk_security; | 82 | struct sk_security_struct *sksec = sk->sk_security; |
81 | struct netlbl_lsm_secattr secattr; | 83 | struct netlbl_lsm_secattr secattr; |
82 | struct inet_sock *sk_inet; | ||
83 | struct inet_connection_sock *sk_conn; | ||
84 | 84 | ||
85 | if (sksec->nlbl_state != NLBL_REQUIRE) | 85 | if (sksec->nlbl_state != NLBL_REQUIRE) |
86 | return 0; | 86 | return 0; |
@@ -96,20 +96,6 @@ static int selinux_netlbl_sock_setsid(struct sock *sk) | |||
96 | sksec->nlbl_state = NLBL_LABELED; | 96 | sksec->nlbl_state = NLBL_LABELED; |
97 | break; | 97 | break; |
98 | case -EDESTADDRREQ: | 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; | 99 | sksec->nlbl_state = NLBL_REQSKB; |
114 | rc = 0; | 100 | rc = 0; |
115 | break; | 101 | break; |
@@ -247,21 +233,77 @@ skbuff_setsid_return: | |||
247 | } | 233 | } |
248 | 234 | ||
249 | /** | 235 | /** |
250 | * selinux_netlbl_sock_graft - Netlabel the new socket | 236 | * selinux_netlbl_inet_conn_established - Netlabel the newly accepted connection |
251 | * @sk: the new connection | 237 | * @sk: the new connection |
252 | * @sock: the new socket | ||
253 | * | 238 | * |
254 | * Description: | 239 | * Description: |
255 | * The connection represented by @sk is being grafted onto @sock so set the | 240 | * A new connection has been established on @sk so make sure it is labeled |
256 | * socket's NetLabel to match the SID of @sk. | 241 | * correctly with the NetLabel susbsystem. |
257 | * | 242 | * |
258 | */ | 243 | */ |
259 | void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) | 244 | void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family) |
260 | { | 245 | { |
261 | /* Try to set the NetLabel on the socket to save time later, if we fail | 246 | int rc; |
262 | * here we will pick up the pieces in later calls to | 247 | struct sk_security_struct *sksec = sk->sk_security; |
263 | * selinux_netlbl_inode_permission(). */ | 248 | struct netlbl_lsm_secattr secattr; |
264 | selinux_netlbl_sock_setsid(sk); | 249 | struct inet_sock *sk_inet = inet_sk(sk); |
250 | struct sockaddr_in addr; | ||
251 | |||
252 | if (sksec->nlbl_state != NLBL_REQUIRE) | ||
253 | return; | ||
254 | |||
255 | netlbl_secattr_init(&secattr); | ||
256 | if (security_netlbl_sid_to_secattr(sksec->sid, &secattr) != 0) | ||
257 | goto inet_conn_established_return; | ||
258 | |||
259 | rc = netlbl_sock_setattr(sk, &secattr); | ||
260 | switch (rc) { | ||
261 | case 0: | ||
262 | sksec->nlbl_state = NLBL_LABELED; | ||
263 | break; | ||
264 | case -EDESTADDRREQ: | ||
265 | /* no PF_INET6 support yet because we don't support any IPv6 | ||
266 | * labeling protocols */ | ||
267 | if (family != PF_INET) { | ||
268 | sksec->nlbl_state = NLBL_UNSET; | ||
269 | goto inet_conn_established_return; | ||
270 | } | ||
271 | |||
272 | addr.sin_family = family; | ||
273 | addr.sin_addr.s_addr = sk_inet->daddr; | ||
274 | if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr, | ||
275 | &secattr) != 0) { | ||
276 | /* we failed to label the connected socket (could be | ||
277 | * for a variety of reasons, the actual "why" isn't | ||
278 | * important here) so we have to go to our backup plan, | ||
279 | * labeling the packets individually in the netfilter | ||
280 | * local output hook. this is okay but we need to | ||
281 | * adjust the MSS of the connection to take into | ||
282 | * account any labeling overhead, since we don't know | ||
283 | * the exact overhead at this point we'll use the worst | ||
284 | * case value which is 40 bytes for IPv4 */ | ||
285 | struct inet_connection_sock *sk_conn = inet_csk(sk); | ||
286 | sk_conn->icsk_ext_hdr_len += 40 - | ||
287 | (sk_inet->opt ? sk_inet->opt->optlen : 0); | ||
288 | sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie); | ||
289 | |||
290 | sksec->nlbl_state = NLBL_REQSKB; | ||
291 | } else | ||
292 | sksec->nlbl_state = NLBL_CONNLABELED; | ||
293 | break; | ||
294 | default: | ||
295 | /* note that we are failing to label the socket which could be | ||
296 | * a bad thing since it means traffic could leave the system | ||
297 | * without the desired labeling, however, all is not lost as | ||
298 | * we have a check in selinux_netlbl_inode_permission() to | ||
299 | * pick up the pieces that we might drop here because we can't | ||
300 | * return an error code */ | ||
301 | break; | ||
302 | } | ||
303 | |||
304 | inet_conn_established_return: | ||
305 | netlbl_secattr_destroy(&secattr); | ||
306 | return; | ||
265 | } | 307 | } |
266 | 308 | ||
267 | /** | 309 | /** |
@@ -398,7 +440,8 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
398 | struct netlbl_lsm_secattr secattr; | 440 | struct netlbl_lsm_secattr secattr; |
399 | 441 | ||
400 | if (level == IPPROTO_IP && optname == IP_OPTIONS && | 442 | if (level == IPPROTO_IP && optname == IP_OPTIONS && |
401 | sksec->nlbl_state == NLBL_LABELED) { | 443 | (sksec->nlbl_state == NLBL_LABELED || |
444 | sksec->nlbl_state == NLBL_CONNLABELED)) { | ||
402 | netlbl_secattr_init(&secattr); | 445 | netlbl_secattr_init(&secattr); |
403 | lock_sock(sk); | 446 | lock_sock(sk); |
404 | rc = netlbl_sock_getattr(sk, &secattr); | 447 | rc = netlbl_sock_getattr(sk, &secattr); |
@@ -410,3 +453,51 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
410 | 453 | ||
411 | return rc; | 454 | return rc; |
412 | } | 455 | } |
456 | |||
457 | /** | ||
458 | * selinux_netlbl_socket_connect - Label a client-side socket on connect | ||
459 | * @sk: the socket to label | ||
460 | * @addr: the destination address | ||
461 | * | ||
462 | * Description: | ||
463 | * Attempt to label a connected socket with NetLabel using the given address. | ||
464 | * Returns zero values on success, negative values on failure. | ||
465 | * | ||
466 | */ | ||
467 | int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) | ||
468 | { | ||
469 | int rc; | ||
470 | struct sk_security_struct *sksec = sk->sk_security; | ||
471 | struct netlbl_lsm_secattr secattr; | ||
472 | |||
473 | if (sksec->nlbl_state != NLBL_REQSKB && | ||
474 | sksec->nlbl_state != NLBL_CONNLABELED) | ||
475 | return 0; | ||
476 | |||
477 | netlbl_secattr_init(&secattr); | ||
478 | local_bh_disable(); | ||
479 | bh_lock_sock_nested(sk); | ||
480 | |||
481 | /* connected sockets are allowed to disconnect when the address family | ||
482 | * is set to AF_UNSPEC, if that is what is happening we want to reset | ||
483 | * the socket */ | ||
484 | if (addr->sa_family == AF_UNSPEC) { | ||
485 | netlbl_sock_delattr(sk); | ||
486 | sksec->nlbl_state = NLBL_REQSKB; | ||
487 | rc = 0; | ||
488 | goto socket_connect_return; | ||
489 | } | ||
490 | rc = security_netlbl_sid_to_secattr(sksec->sid, &secattr); | ||
491 | if (rc != 0) | ||
492 | goto socket_connect_return; | ||
493 | rc = netlbl_conn_setattr(sk, addr, &secattr); | ||
494 | if (rc != 0) | ||
495 | goto socket_connect_return; | ||
496 | sksec->nlbl_state = NLBL_CONNLABELED; | ||
497 | |||
498 | socket_connect_return: | ||
499 | bh_unlock_sock(sk); | ||
500 | local_bh_enable(); | ||
501 | netlbl_secattr_destroy(&secattr); | ||
502 | return rc; | ||
503 | } | ||