diff options
-rw-r--r-- | Documentation/Smack.txt | 42 | ||||
-rw-r--r-- | Documentation/feature-removal-schedule.txt | 11 | ||||
-rw-r--r-- | Documentation/kernel-parameters.txt | 9 | ||||
-rw-r--r-- | include/linux/security.h | 13 | ||||
-rw-r--r-- | include/net/cipso_ipv4.h | 17 | ||||
-rw-r--r-- | include/net/netlabel.h | 17 | ||||
-rw-r--r-- | net/ipv4/cipso_ipv4.c | 130 | ||||
-rw-r--r-- | net/ipv4/syncookies.c | 9 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 7 | ||||
-rw-r--r-- | net/netlabel/netlabel_kapi.c | 165 | ||||
-rw-r--r-- | net/socket.c | 2 | ||||
-rw-r--r-- | security/capability.c | 5 | ||||
-rw-r--r-- | security/security.c | 5 | ||||
-rw-r--r-- | security/selinux/hooks.c | 207 | ||||
-rw-r--r-- | security/selinux/include/netlabel.h | 27 | ||||
-rw-r--r-- | security/selinux/netlabel.c | 186 | ||||
-rw-r--r-- | security/selinux/selinuxfs.c | 68 | ||||
-rw-r--r-- | security/smack/smack.h | 32 | ||||
-rw-r--r-- | security/smack/smack_access.c | 66 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 282 | ||||
-rw-r--r-- | security/smack/smackfs.c | 218 | ||||
-rw-r--r-- | security/tomoyo/common.h | 2 |
22 files changed, 783 insertions, 737 deletions
diff --git a/Documentation/Smack.txt b/Documentation/Smack.txt index 989c2fcd8111..629c92e99783 100644 --- a/Documentation/Smack.txt +++ b/Documentation/Smack.txt | |||
@@ -184,14 +184,16 @@ length. Single character labels using special characters, that being anything | |||
184 | other than a letter or digit, are reserved for use by the Smack development | 184 | other than a letter or digit, are reserved for use by the Smack development |
185 | team. Smack labels are unstructured, case sensitive, and the only operation | 185 | team. Smack labels are unstructured, case sensitive, and the only operation |
186 | ever performed on them is comparison for equality. Smack labels cannot | 186 | ever performed on them is comparison for equality. Smack labels cannot |
187 | contain unprintable characters or the "/" (slash) character. | 187 | contain unprintable characters or the "/" (slash) character. Smack labels |
188 | cannot begin with a '-', which is reserved for special options. | ||
188 | 189 | ||
189 | There are some predefined labels: | 190 | There are some predefined labels: |
190 | 191 | ||
191 | _ Pronounced "floor", a single underscore character. | 192 | _ Pronounced "floor", a single underscore character. |
192 | ^ Pronounced "hat", a single circumflex character. | 193 | ^ Pronounced "hat", a single circumflex character. |
193 | * Pronounced "star", a single asterisk character. | 194 | * Pronounced "star", a single asterisk character. |
194 | ? Pronounced "huh", a single question mark character. | 195 | ? Pronounced "huh", a single question mark character. |
196 | @ Pronounced "Internet", a single at sign character. | ||
195 | 197 | ||
196 | Every task on a Smack system is assigned a label. System tasks, such as | 198 | Every task on a Smack system is assigned a label. System tasks, such as |
197 | init(8) and systems daemons, are run with the floor ("_") label. User tasks | 199 | init(8) and systems daemons, are run with the floor ("_") label. User tasks |
@@ -412,6 +414,36 @@ sockets. | |||
412 | A privileged program may set this to match the label of another | 414 | A privileged program may set this to match the label of another |
413 | task with which it hopes to communicate. | 415 | task with which it hopes to communicate. |
414 | 416 | ||
417 | Smack Netlabel Exceptions | ||
418 | |||
419 | You will often find that your labeled application has to talk to the outside, | ||
420 | unlabeled world. To do this there's a special file /smack/netlabel where you can | ||
421 | add some exceptions in the form of : | ||
422 | @IP1 LABEL1 or | ||
423 | @IP2/MASK LABEL2 | ||
424 | |||
425 | It means that your application will have unlabeled access to @IP1 if it has | ||
426 | write access on LABEL1, and access to the subnet @IP2/MASK if it has write | ||
427 | access on LABEL2. | ||
428 | |||
429 | Entries in the /smack/netlabel file are matched by longest mask first, like in | ||
430 | classless IPv4 routing. | ||
431 | |||
432 | A special label '@' and an option '-CIPSO' can be used there : | ||
433 | @ means Internet, any application with any label has access to it | ||
434 | -CIPSO means standard CIPSO networking | ||
435 | |||
436 | If you don't know what CIPSO is and don't plan to use it, you can just do : | ||
437 | echo 127.0.0.1 -CIPSO > /smack/netlabel | ||
438 | echo 0.0.0.0/0 @ > /smack/netlabel | ||
439 | |||
440 | If you use CIPSO on your 192.168.0.0/16 local network and need also unlabeled | ||
441 | Internet access, you can have : | ||
442 | echo 127.0.0.1 -CIPSO > /smack/netlabel | ||
443 | echo 192.168.0.0/16 -CIPSO > /smack/netlabel | ||
444 | echo 0.0.0.0/0 @ > /smack/netlabel | ||
445 | |||
446 | |||
415 | Writing Applications for Smack | 447 | Writing Applications for Smack |
416 | 448 | ||
417 | There are three sorts of applications that will run on a Smack system. How an | 449 | There are three sorts of applications that will run on a Smack system. How an |
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 7907586c6e08..1135996bec8b 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt | |||
@@ -356,17 +356,6 @@ Who: Hans de Goede <hdegoede@redhat.com> | |||
356 | 356 | ||
357 | --------------------------- | 357 | --------------------------- |
358 | 358 | ||
359 | What: SELinux "compat_net" functionality | ||
360 | When: 2.6.30 at the earliest | ||
361 | Why: In 2.6.18 the Secmark concept was introduced to replace the "compat_net" | ||
362 | network access control functionality of SELinux. Secmark offers both | ||
363 | better performance and greater flexibility than the "compat_net" | ||
364 | mechanism. Now that the major Linux distributions have moved to | ||
365 | Secmark, it is time to deprecate the older mechanism and start the | ||
366 | process of removing the old code. | ||
367 | Who: Paul Moore <paul.moore@hp.com> | ||
368 | --------------------------- | ||
369 | |||
370 | What: sysfs ui for changing p4-clockmod parameters | 359 | What: sysfs ui for changing p4-clockmod parameters |
371 | When: September 2009 | 360 | When: September 2009 |
372 | Why: See commits 129f8ae9b1b5be94517da76009ea956e89104ce8 and | 361 | Why: See commits 129f8ae9b1b5be94517da76009ea956e89104ce8 and |
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index d1e2fcb6298b..be3bde51b564 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -2030,15 +2030,6 @@ and is between 256 and 4096 characters. It is defined in the file | |||
2030 | If enabled at boot time, /selinux/disable can be used | 2030 | If enabled at boot time, /selinux/disable can be used |
2031 | later to disable prior to initial policy load. | 2031 | later to disable prior to initial policy load. |
2032 | 2032 | ||
2033 | selinux_compat_net = | ||
2034 | [SELINUX] Set initial selinux_compat_net flag value. | ||
2035 | Format: { "0" | "1" } | ||
2036 | 0 -- use new secmark-based packet controls | ||
2037 | 1 -- use legacy packet controls | ||
2038 | Default value is 0 (preferred). | ||
2039 | Value can be changed at runtime via | ||
2040 | /selinux/compat_net. | ||
2041 | |||
2042 | serialnumber [BUGS=X86-32] | 2033 | serialnumber [BUGS=X86-32] |
2043 | 2034 | ||
2044 | shapers= [NET] | 2035 | shapers= [NET] |
diff --git a/include/linux/security.h b/include/linux/security.h index 1f2ab6353c00..54ed15799a83 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -880,11 +880,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
880 | * @sock contains the listening socket structure. | 880 | * @sock contains the listening socket structure. |
881 | * @newsock contains the newly created server socket for connection. | 881 | * @newsock contains the newly created server socket for connection. |
882 | * Return 0 if permission is granted. | 882 | * Return 0 if permission is granted. |
883 | * @socket_post_accept: | ||
884 | * This hook allows a security module to copy security | ||
885 | * information into the newly created socket's inode. | ||
886 | * @sock contains the listening socket structure. | ||
887 | * @newsock contains the newly created server socket for connection. | ||
888 | * @socket_sendmsg: | 883 | * @socket_sendmsg: |
889 | * Check permission before transmitting a message to another socket. | 884 | * Check permission before transmitting a message to another socket. |
890 | * @sock contains the socket structure. | 885 | * @sock contains the socket structure. |
@@ -1554,8 +1549,6 @@ struct security_operations { | |||
1554 | struct sockaddr *address, int addrlen); | 1549 | struct sockaddr *address, int addrlen); |
1555 | int (*socket_listen) (struct socket *sock, int backlog); | 1550 | int (*socket_listen) (struct socket *sock, int backlog); |
1556 | int (*socket_accept) (struct socket *sock, struct socket *newsock); | 1551 | int (*socket_accept) (struct socket *sock, struct socket *newsock); |
1557 | void (*socket_post_accept) (struct socket *sock, | ||
1558 | struct socket *newsock); | ||
1559 | int (*socket_sendmsg) (struct socket *sock, | 1552 | int (*socket_sendmsg) (struct socket *sock, |
1560 | struct msghdr *msg, int size); | 1553 | struct msghdr *msg, int size); |
1561 | int (*socket_recvmsg) (struct socket *sock, | 1554 | int (*socket_recvmsg) (struct socket *sock, |
@@ -2537,7 +2530,6 @@ int security_socket_bind(struct socket *sock, struct sockaddr *address, int addr | |||
2537 | int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen); | 2530 | int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen); |
2538 | int security_socket_listen(struct socket *sock, int backlog); | 2531 | int security_socket_listen(struct socket *sock, int backlog); |
2539 | int security_socket_accept(struct socket *sock, struct socket *newsock); | 2532 | int security_socket_accept(struct socket *sock, struct socket *newsock); |
2540 | void security_socket_post_accept(struct socket *sock, struct socket *newsock); | ||
2541 | int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size); | 2533 | int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size); |
2542 | int security_socket_recvmsg(struct socket *sock, struct msghdr *msg, | 2534 | int security_socket_recvmsg(struct socket *sock, struct msghdr *msg, |
2543 | int size, int flags); | 2535 | int size, int flags); |
@@ -2616,11 +2608,6 @@ static inline int security_socket_accept(struct socket *sock, | |||
2616 | return 0; | 2608 | return 0; |
2617 | } | 2609 | } |
2618 | 2610 | ||
2619 | static inline void security_socket_post_accept(struct socket *sock, | ||
2620 | struct socket *newsock) | ||
2621 | { | ||
2622 | } | ||
2623 | |||
2624 | static inline int security_socket_sendmsg(struct socket *sock, | 2611 | static inline int security_socket_sendmsg(struct socket *sock, |
2625 | struct msghdr *msg, int size) | 2612 | struct msghdr *msg, int size) |
2626 | { | 2613 | { |
diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h index bedc7f62e35d..abd443604c9f 100644 --- a/include/net/cipso_ipv4.h +++ b/include/net/cipso_ipv4.h | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/net.h> | 40 | #include <linux/net.h> |
41 | #include <linux/skbuff.h> | 41 | #include <linux/skbuff.h> |
42 | #include <net/netlabel.h> | 42 | #include <net/netlabel.h> |
43 | #include <net/request_sock.h> | ||
43 | #include <asm/atomic.h> | 44 | #include <asm/atomic.h> |
44 | 45 | ||
45 | /* known doi values */ | 46 | /* known doi values */ |
@@ -215,6 +216,10 @@ int cipso_v4_sock_setattr(struct sock *sk, | |||
215 | const struct netlbl_lsm_secattr *secattr); | 216 | const struct netlbl_lsm_secattr *secattr); |
216 | void cipso_v4_sock_delattr(struct sock *sk); | 217 | void cipso_v4_sock_delattr(struct sock *sk); |
217 | int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr); | 218 | int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr); |
219 | int cipso_v4_req_setattr(struct request_sock *req, | ||
220 | const struct cipso_v4_doi *doi_def, | ||
221 | const struct netlbl_lsm_secattr *secattr); | ||
222 | void cipso_v4_req_delattr(struct request_sock *req); | ||
218 | int cipso_v4_skbuff_setattr(struct sk_buff *skb, | 223 | int cipso_v4_skbuff_setattr(struct sk_buff *skb, |
219 | const struct cipso_v4_doi *doi_def, | 224 | const struct cipso_v4_doi *doi_def, |
220 | const struct netlbl_lsm_secattr *secattr); | 225 | const struct netlbl_lsm_secattr *secattr); |
@@ -247,6 +252,18 @@ static inline int cipso_v4_sock_getattr(struct sock *sk, | |||
247 | return -ENOSYS; | 252 | return -ENOSYS; |
248 | } | 253 | } |
249 | 254 | ||
255 | static inline int cipso_v4_req_setattr(struct request_sock *req, | ||
256 | const struct cipso_v4_doi *doi_def, | ||
257 | const struct netlbl_lsm_secattr *secattr) | ||
258 | { | ||
259 | return -ENOSYS; | ||
260 | } | ||
261 | |||
262 | static inline void cipso_v4_req_delattr(struct request_sock *req) | ||
263 | { | ||
264 | return; | ||
265 | } | ||
266 | |||
250 | static inline int cipso_v4_skbuff_setattr(struct sk_buff *skb, | 267 | static inline int cipso_v4_skbuff_setattr(struct sk_buff *skb, |
251 | const struct cipso_v4_doi *doi_def, | 268 | const struct cipso_v4_doi *doi_def, |
252 | const struct netlbl_lsm_secattr *secattr) | 269 | const struct netlbl_lsm_secattr *secattr) |
diff --git a/include/net/netlabel.h b/include/net/netlabel.h index 749011eedc0b..60ebbc1fef46 100644 --- a/include/net/netlabel.h +++ b/include/net/netlabel.h | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/in.h> | 36 | #include <linux/in.h> |
37 | #include <linux/in6.h> | 37 | #include <linux/in6.h> |
38 | #include <net/netlink.h> | 38 | #include <net/netlink.h> |
39 | #include <net/request_sock.h> | ||
39 | #include <asm/atomic.h> | 40 | #include <asm/atomic.h> |
40 | 41 | ||
41 | struct cipso_v4_doi; | 42 | struct cipso_v4_doi; |
@@ -406,6 +407,7 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap, | |||
406 | */ | 407 | */ |
407 | int netlbl_enabled(void); | 408 | int netlbl_enabled(void); |
408 | int netlbl_sock_setattr(struct sock *sk, | 409 | int netlbl_sock_setattr(struct sock *sk, |
410 | u16 family, | ||
409 | const struct netlbl_lsm_secattr *secattr); | 411 | const struct netlbl_lsm_secattr *secattr); |
410 | void netlbl_sock_delattr(struct sock *sk); | 412 | void netlbl_sock_delattr(struct sock *sk); |
411 | int netlbl_sock_getattr(struct sock *sk, | 413 | int netlbl_sock_getattr(struct sock *sk, |
@@ -413,6 +415,9 @@ int netlbl_sock_getattr(struct sock *sk, | |||
413 | int netlbl_conn_setattr(struct sock *sk, | 415 | int netlbl_conn_setattr(struct sock *sk, |
414 | struct sockaddr *addr, | 416 | struct sockaddr *addr, |
415 | const struct netlbl_lsm_secattr *secattr); | 417 | const struct netlbl_lsm_secattr *secattr); |
418 | int netlbl_req_setattr(struct request_sock *req, | ||
419 | const struct netlbl_lsm_secattr *secattr); | ||
420 | void netlbl_req_delattr(struct request_sock *req); | ||
416 | int netlbl_skbuff_setattr(struct sk_buff *skb, | 421 | int netlbl_skbuff_setattr(struct sk_buff *skb, |
417 | u16 family, | 422 | u16 family, |
418 | const struct netlbl_lsm_secattr *secattr); | 423 | const struct netlbl_lsm_secattr *secattr); |
@@ -519,7 +524,8 @@ static inline int netlbl_enabled(void) | |||
519 | return 0; | 524 | return 0; |
520 | } | 525 | } |
521 | static inline int netlbl_sock_setattr(struct sock *sk, | 526 | static inline int netlbl_sock_setattr(struct sock *sk, |
522 | const struct netlbl_lsm_secattr *secattr) | 527 | u16 family, |
528 | const struct netlbl_lsm_secattr *secattr) | ||
523 | { | 529 | { |
524 | return -ENOSYS; | 530 | return -ENOSYS; |
525 | } | 531 | } |
@@ -537,6 +543,15 @@ static inline int netlbl_conn_setattr(struct sock *sk, | |||
537 | { | 543 | { |
538 | return -ENOSYS; | 544 | return -ENOSYS; |
539 | } | 545 | } |
546 | static inline int netlbl_req_setattr(struct request_sock *req, | ||
547 | const struct netlbl_lsm_secattr *secattr) | ||
548 | { | ||
549 | return -ENOSYS; | ||
550 | } | ||
551 | static inline void netlbl_req_delattr(struct request_sock *req) | ||
552 | { | ||
553 | return; | ||
554 | } | ||
540 | static inline int netlbl_skbuff_setattr(struct sk_buff *skb, | 555 | static inline int netlbl_skbuff_setattr(struct sk_buff *skb, |
541 | u16 family, | 556 | u16 family, |
542 | const struct netlbl_lsm_secattr *secattr) | 557 | const struct netlbl_lsm_secattr *secattr) |
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 7bc992976d29..039cc1ffe977 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c | |||
@@ -1942,23 +1942,85 @@ socket_setattr_failure: | |||
1942 | } | 1942 | } |
1943 | 1943 | ||
1944 | /** | 1944 | /** |
1945 | * cipso_v4_sock_delattr - Delete the CIPSO option from a socket | 1945 | * cipso_v4_req_setattr - Add a CIPSO option to a connection request socket |
1946 | * @sk: the socket | 1946 | * @req: the connection request socket |
1947 | * @doi_def: the CIPSO DOI to use | ||
1948 | * @secattr: the specific security attributes of the socket | ||
1947 | * | 1949 | * |
1948 | * Description: | 1950 | * Description: |
1949 | * Removes the CIPSO option from a socket, if present. | 1951 | * Set the CIPSO option on the given socket using the DOI definition and |
1952 | * security attributes passed to the function. Returns zero on success and | ||
1953 | * negative values on failure. | ||
1950 | * | 1954 | * |
1951 | */ | 1955 | */ |
1952 | void cipso_v4_sock_delattr(struct sock *sk) | 1956 | int cipso_v4_req_setattr(struct request_sock *req, |
1957 | const struct cipso_v4_doi *doi_def, | ||
1958 | const struct netlbl_lsm_secattr *secattr) | ||
1953 | { | 1959 | { |
1954 | u8 hdr_delta; | 1960 | int ret_val = -EPERM; |
1955 | struct ip_options *opt; | 1961 | unsigned char *buf = NULL; |
1956 | struct inet_sock *sk_inet; | 1962 | u32 buf_len; |
1963 | u32 opt_len; | ||
1964 | struct ip_options *opt = NULL; | ||
1965 | struct inet_request_sock *req_inet; | ||
1957 | 1966 | ||
1958 | sk_inet = inet_sk(sk); | 1967 | /* We allocate the maximum CIPSO option size here so we are probably |
1959 | opt = sk_inet->opt; | 1968 | * being a little wasteful, but it makes our life _much_ easier later |
1960 | if (opt == NULL || opt->cipso == 0) | 1969 | * on and after all we are only talking about 40 bytes. */ |
1961 | return; | 1970 | buf_len = CIPSO_V4_OPT_LEN_MAX; |
1971 | buf = kmalloc(buf_len, GFP_ATOMIC); | ||
1972 | if (buf == NULL) { | ||
1973 | ret_val = -ENOMEM; | ||
1974 | goto req_setattr_failure; | ||
1975 | } | ||
1976 | |||
1977 | ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr); | ||
1978 | if (ret_val < 0) | ||
1979 | goto req_setattr_failure; | ||
1980 | buf_len = ret_val; | ||
1981 | |||
1982 | /* We can't use ip_options_get() directly because it makes a call to | ||
1983 | * ip_options_get_alloc() which allocates memory with GFP_KERNEL and | ||
1984 | * we won't always have CAP_NET_RAW even though we _always_ want to | ||
1985 | * set the IPOPT_CIPSO option. */ | ||
1986 | opt_len = (buf_len + 3) & ~3; | ||
1987 | opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC); | ||
1988 | if (opt == NULL) { | ||
1989 | ret_val = -ENOMEM; | ||
1990 | goto req_setattr_failure; | ||
1991 | } | ||
1992 | memcpy(opt->__data, buf, buf_len); | ||
1993 | opt->optlen = opt_len; | ||
1994 | opt->cipso = sizeof(struct iphdr); | ||
1995 | kfree(buf); | ||
1996 | buf = NULL; | ||
1997 | |||
1998 | req_inet = inet_rsk(req); | ||
1999 | opt = xchg(&req_inet->opt, opt); | ||
2000 | kfree(opt); | ||
2001 | |||
2002 | return 0; | ||
2003 | |||
2004 | req_setattr_failure: | ||
2005 | kfree(buf); | ||
2006 | kfree(opt); | ||
2007 | return ret_val; | ||
2008 | } | ||
2009 | |||
2010 | /** | ||
2011 | * cipso_v4_delopt - Delete the CIPSO option from a set of IP options | ||
2012 | * @opt_ptr: IP option pointer | ||
2013 | * | ||
2014 | * Description: | ||
2015 | * Deletes the CIPSO IP option from a set of IP options and makes the necessary | ||
2016 | * adjustments to the IP option structure. Returns zero on success, negative | ||
2017 | * values on failure. | ||
2018 | * | ||
2019 | */ | ||
2020 | int cipso_v4_delopt(struct ip_options **opt_ptr) | ||
2021 | { | ||
2022 | int hdr_delta = 0; | ||
2023 | struct ip_options *opt = *opt_ptr; | ||
1962 | 2024 | ||
1963 | if (opt->srr || opt->rr || opt->ts || opt->router_alert) { | 2025 | if (opt->srr || opt->rr || opt->ts || opt->router_alert) { |
1964 | u8 cipso_len; | 2026 | u8 cipso_len; |
@@ -2003,11 +2065,34 @@ void cipso_v4_sock_delattr(struct sock *sk) | |||
2003 | } else { | 2065 | } else { |
2004 | /* only the cipso option was present on the socket so we can | 2066 | /* only the cipso option was present on the socket so we can |
2005 | * remove the entire option struct */ | 2067 | * remove the entire option struct */ |
2006 | sk_inet->opt = NULL; | 2068 | *opt_ptr = NULL; |
2007 | hdr_delta = opt->optlen; | 2069 | hdr_delta = opt->optlen; |
2008 | kfree(opt); | 2070 | kfree(opt); |
2009 | } | 2071 | } |
2010 | 2072 | ||
2073 | return hdr_delta; | ||
2074 | } | ||
2075 | |||
2076 | /** | ||
2077 | * cipso_v4_sock_delattr - Delete the CIPSO option from a socket | ||
2078 | * @sk: the socket | ||
2079 | * | ||
2080 | * Description: | ||
2081 | * Removes the CIPSO option from a socket, if present. | ||
2082 | * | ||
2083 | */ | ||
2084 | void cipso_v4_sock_delattr(struct sock *sk) | ||
2085 | { | ||
2086 | int hdr_delta; | ||
2087 | struct ip_options *opt; | ||
2088 | struct inet_sock *sk_inet; | ||
2089 | |||
2090 | sk_inet = inet_sk(sk); | ||
2091 | opt = sk_inet->opt; | ||
2092 | if (opt == NULL || opt->cipso == 0) | ||
2093 | return; | ||
2094 | |||
2095 | hdr_delta = cipso_v4_delopt(&sk_inet->opt); | ||
2011 | if (sk_inet->is_icsk && hdr_delta > 0) { | 2096 | if (sk_inet->is_icsk && hdr_delta > 0) { |
2012 | struct inet_connection_sock *sk_conn = inet_csk(sk); | 2097 | struct inet_connection_sock *sk_conn = inet_csk(sk); |
2013 | sk_conn->icsk_ext_hdr_len -= hdr_delta; | 2098 | sk_conn->icsk_ext_hdr_len -= hdr_delta; |
@@ -2016,6 +2101,27 @@ void cipso_v4_sock_delattr(struct sock *sk) | |||
2016 | } | 2101 | } |
2017 | 2102 | ||
2018 | /** | 2103 | /** |
2104 | * cipso_v4_req_delattr - Delete the CIPSO option from a request socket | ||
2105 | * @reg: the request socket | ||
2106 | * | ||
2107 | * Description: | ||
2108 | * Removes the CIPSO option from a request socket, if present. | ||
2109 | * | ||
2110 | */ | ||
2111 | void cipso_v4_req_delattr(struct request_sock *req) | ||
2112 | { | ||
2113 | struct ip_options *opt; | ||
2114 | struct inet_request_sock *req_inet; | ||
2115 | |||
2116 | req_inet = inet_rsk(req); | ||
2117 | opt = req_inet->opt; | ||
2118 | if (opt == NULL || opt->cipso == 0) | ||
2119 | return; | ||
2120 | |||
2121 | cipso_v4_delopt(&req_inet->opt); | ||
2122 | } | ||
2123 | |||
2124 | /** | ||
2019 | * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions | 2125 | * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions |
2020 | * @cipso: the CIPSO v4 option | 2126 | * @cipso: the CIPSO v4 option |
2021 | * @secattr: the security attributes | 2127 | * @secattr: the security attributes |
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index d346c22aa6ae..b35a950d2e06 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c | |||
@@ -288,10 +288,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | |||
288 | if (!req) | 288 | if (!req) |
289 | goto out; | 289 | goto out; |
290 | 290 | ||
291 | if (security_inet_conn_request(sk, skb, req)) { | ||
292 | reqsk_free(req); | ||
293 | goto out; | ||
294 | } | ||
295 | ireq = inet_rsk(req); | 291 | ireq = inet_rsk(req); |
296 | treq = tcp_rsk(req); | 292 | treq = tcp_rsk(req); |
297 | treq->rcv_isn = ntohl(th->seq) - 1; | 293 | treq->rcv_isn = ntohl(th->seq) - 1; |
@@ -322,6 +318,11 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | |||
322 | } | 318 | } |
323 | } | 319 | } |
324 | 320 | ||
321 | if (security_inet_conn_request(sk, skb, req)) { | ||
322 | reqsk_free(req); | ||
323 | goto out; | ||
324 | } | ||
325 | |||
325 | req->expires = 0UL; | 326 | req->expires = 0UL; |
326 | req->retrans = 0; | 327 | req->retrans = 0; |
327 | 328 | ||
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index d0a314879d81..5d427f86b414 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -1230,14 +1230,15 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1230 | 1230 | ||
1231 | tcp_openreq_init(req, &tmp_opt, skb); | 1231 | tcp_openreq_init(req, &tmp_opt, skb); |
1232 | 1232 | ||
1233 | if (security_inet_conn_request(sk, skb, req)) | ||
1234 | goto drop_and_free; | ||
1235 | |||
1236 | ireq = inet_rsk(req); | 1233 | ireq = inet_rsk(req); |
1237 | ireq->loc_addr = daddr; | 1234 | ireq->loc_addr = daddr; |
1238 | ireq->rmt_addr = saddr; | 1235 | ireq->rmt_addr = saddr; |
1239 | ireq->no_srccheck = inet_sk(sk)->transparent; | 1236 | ireq->no_srccheck = inet_sk(sk)->transparent; |
1240 | ireq->opt = tcp_v4_save_options(sk, skb); | 1237 | ireq->opt = tcp_v4_save_options(sk, skb); |
1238 | |||
1239 | if (security_inet_conn_request(sk, skb, req)) | ||
1240 | goto drop_and_free; | ||
1241 | |||
1241 | if (!want_cookie) | 1242 | if (!want_cookie) |
1242 | TCP_ECN_create_request(req, tcp_hdr(skb)); | 1243 | TCP_ECN_create_request(req, tcp_hdr(skb)); |
1243 | 1244 | ||
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index fd9229db075c..b0e582f2d37a 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c | |||
@@ -619,8 +619,9 @@ int netlbl_enabled(void) | |||
619 | } | 619 | } |
620 | 620 | ||
621 | /** | 621 | /** |
622 | * netlbl_socket_setattr - Label a socket using the correct protocol | 622 | * netlbl_sock_setattr - Label a socket using the correct protocol |
623 | * @sk: the socket to label | 623 | * @sk: the socket to label |
624 | * @family: protocol family | ||
624 | * @secattr: the security attributes | 625 | * @secattr: the security attributes |
625 | * | 626 | * |
626 | * Description: | 627 | * Description: |
@@ -633,29 +634,45 @@ int netlbl_enabled(void) | |||
633 | * | 634 | * |
634 | */ | 635 | */ |
635 | int netlbl_sock_setattr(struct sock *sk, | 636 | int netlbl_sock_setattr(struct sock *sk, |
637 | u16 family, | ||
636 | const struct netlbl_lsm_secattr *secattr) | 638 | const struct netlbl_lsm_secattr *secattr) |
637 | { | 639 | { |
638 | int ret_val = -ENOENT; | 640 | int ret_val; |
639 | struct netlbl_dom_map *dom_entry; | 641 | struct netlbl_dom_map *dom_entry; |
640 | 642 | ||
641 | rcu_read_lock(); | 643 | rcu_read_lock(); |
642 | dom_entry = netlbl_domhsh_getentry(secattr->domain); | 644 | dom_entry = netlbl_domhsh_getentry(secattr->domain); |
643 | if (dom_entry == NULL) | 645 | if (dom_entry == NULL) { |
646 | ret_val = -ENOENT; | ||
644 | goto socket_setattr_return; | 647 | goto socket_setattr_return; |
645 | switch (dom_entry->type) { | 648 | } |
646 | case NETLBL_NLTYPE_ADDRSELECT: | 649 | switch (family) { |
647 | ret_val = -EDESTADDRREQ; | 650 | case AF_INET: |
648 | break; | 651 | switch (dom_entry->type) { |
649 | case NETLBL_NLTYPE_CIPSOV4: | 652 | case NETLBL_NLTYPE_ADDRSELECT: |
650 | ret_val = cipso_v4_sock_setattr(sk, | 653 | ret_val = -EDESTADDRREQ; |
651 | dom_entry->type_def.cipsov4, | 654 | break; |
652 | secattr); | 655 | case NETLBL_NLTYPE_CIPSOV4: |
656 | ret_val = cipso_v4_sock_setattr(sk, | ||
657 | dom_entry->type_def.cipsov4, | ||
658 | secattr); | ||
659 | break; | ||
660 | case NETLBL_NLTYPE_UNLABELED: | ||
661 | ret_val = 0; | ||
662 | break; | ||
663 | default: | ||
664 | ret_val = -ENOENT; | ||
665 | } | ||
653 | break; | 666 | break; |
654 | case NETLBL_NLTYPE_UNLABELED: | 667 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
668 | case AF_INET6: | ||
669 | /* since we don't support any IPv6 labeling protocols right | ||
670 | * now we can optimize everything away until we do */ | ||
655 | ret_val = 0; | 671 | ret_val = 0; |
656 | break; | 672 | break; |
673 | #endif /* IPv6 */ | ||
657 | default: | 674 | default: |
658 | ret_val = -ENOENT; | 675 | ret_val = -EPROTONOSUPPORT; |
659 | } | 676 | } |
660 | 677 | ||
661 | socket_setattr_return: | 678 | socket_setattr_return: |
@@ -689,9 +706,25 @@ void netlbl_sock_delattr(struct sock *sk) | |||
689 | * on failure. | 706 | * on failure. |
690 | * | 707 | * |
691 | */ | 708 | */ |
692 | int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) | 709 | int netlbl_sock_getattr(struct sock *sk, |
710 | struct netlbl_lsm_secattr *secattr) | ||
693 | { | 711 | { |
694 | return cipso_v4_sock_getattr(sk, secattr); | 712 | int ret_val; |
713 | |||
714 | switch (sk->sk_family) { | ||
715 | case AF_INET: | ||
716 | ret_val = cipso_v4_sock_getattr(sk, secattr); | ||
717 | break; | ||
718 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
719 | case AF_INET6: | ||
720 | ret_val = -ENOMSG; | ||
721 | break; | ||
722 | #endif /* IPv6 */ | ||
723 | default: | ||
724 | ret_val = -EPROTONOSUPPORT; | ||
725 | } | ||
726 | |||
727 | return ret_val; | ||
695 | } | 728 | } |
696 | 729 | ||
697 | /** | 730 | /** |
@@ -748,7 +781,7 @@ int netlbl_conn_setattr(struct sock *sk, | |||
748 | break; | 781 | break; |
749 | #endif /* IPv6 */ | 782 | #endif /* IPv6 */ |
750 | default: | 783 | default: |
751 | ret_val = 0; | 784 | ret_val = -EPROTONOSUPPORT; |
752 | } | 785 | } |
753 | 786 | ||
754 | conn_setattr_return: | 787 | conn_setattr_return: |
@@ -757,6 +790,90 @@ conn_setattr_return: | |||
757 | } | 790 | } |
758 | 791 | ||
759 | /** | 792 | /** |
793 | * netlbl_req_setattr - Label a request socket using the correct protocol | ||
794 | * @req: the request socket to label | ||
795 | * @secattr: the security attributes | ||
796 | * | ||
797 | * Description: | ||
798 | * Attach the correct label to the given socket using the security attributes | ||
799 | * specified in @secattr. Returns zero on success, negative values on failure. | ||
800 | * | ||
801 | */ | ||
802 | int netlbl_req_setattr(struct request_sock *req, | ||
803 | const struct netlbl_lsm_secattr *secattr) | ||
804 | { | ||
805 | int ret_val; | ||
806 | struct netlbl_dom_map *dom_entry; | ||
807 | struct netlbl_domaddr4_map *af4_entry; | ||
808 | u32 proto_type; | ||
809 | struct cipso_v4_doi *proto_cv4; | ||
810 | |||
811 | rcu_read_lock(); | ||
812 | dom_entry = netlbl_domhsh_getentry(secattr->domain); | ||
813 | if (dom_entry == NULL) { | ||
814 | ret_val = -ENOENT; | ||
815 | goto req_setattr_return; | ||
816 | } | ||
817 | switch (req->rsk_ops->family) { | ||
818 | case AF_INET: | ||
819 | if (dom_entry->type == NETLBL_NLTYPE_ADDRSELECT) { | ||
820 | struct inet_request_sock *req_inet = inet_rsk(req); | ||
821 | af4_entry = netlbl_domhsh_getentry_af4(secattr->domain, | ||
822 | req_inet->rmt_addr); | ||
823 | if (af4_entry == NULL) { | ||
824 | ret_val = -ENOENT; | ||
825 | goto req_setattr_return; | ||
826 | } | ||
827 | proto_type = af4_entry->type; | ||
828 | proto_cv4 = af4_entry->type_def.cipsov4; | ||
829 | } else { | ||
830 | proto_type = dom_entry->type; | ||
831 | proto_cv4 = dom_entry->type_def.cipsov4; | ||
832 | } | ||
833 | switch (proto_type) { | ||
834 | case NETLBL_NLTYPE_CIPSOV4: | ||
835 | ret_val = cipso_v4_req_setattr(req, proto_cv4, secattr); | ||
836 | break; | ||
837 | case NETLBL_NLTYPE_UNLABELED: | ||
838 | /* just delete the protocols we support for right now | ||
839 | * but we could remove other protocols if needed */ | ||
840 | cipso_v4_req_delattr(req); | ||
841 | ret_val = 0; | ||
842 | break; | ||
843 | default: | ||
844 | ret_val = -ENOENT; | ||
845 | } | ||
846 | break; | ||
847 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
848 | case AF_INET6: | ||
849 | /* since we don't support any IPv6 labeling protocols right | ||
850 | * now we can optimize everything away until we do */ | ||
851 | ret_val = 0; | ||
852 | break; | ||
853 | #endif /* IPv6 */ | ||
854 | default: | ||
855 | ret_val = -EPROTONOSUPPORT; | ||
856 | } | ||
857 | |||
858 | req_setattr_return: | ||
859 | rcu_read_unlock(); | ||
860 | return ret_val; | ||
861 | } | ||
862 | |||
863 | /** | ||
864 | * netlbl_req_delattr - Delete all the NetLabel labels on a socket | ||
865 | * @req: the socket | ||
866 | * | ||
867 | * Description: | ||
868 | * Remove all the NetLabel labeling from @req. | ||
869 | * | ||
870 | */ | ||
871 | void netlbl_req_delattr(struct request_sock *req) | ||
872 | { | ||
873 | cipso_v4_req_delattr(req); | ||
874 | } | ||
875 | |||
876 | /** | ||
760 | * netlbl_skbuff_setattr - Label a packet using the correct protocol | 877 | * netlbl_skbuff_setattr - Label a packet using the correct protocol |
761 | * @skb: the packet | 878 | * @skb: the packet |
762 | * @family: protocol family | 879 | * @family: protocol family |
@@ -808,7 +925,7 @@ int netlbl_skbuff_setattr(struct sk_buff *skb, | |||
808 | break; | 925 | break; |
809 | #endif /* IPv6 */ | 926 | #endif /* IPv6 */ |
810 | default: | 927 | default: |
811 | ret_val = 0; | 928 | ret_val = -EPROTONOSUPPORT; |
812 | } | 929 | } |
813 | 930 | ||
814 | skbuff_setattr_return: | 931 | skbuff_setattr_return: |
@@ -833,9 +950,17 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb, | |||
833 | u16 family, | 950 | u16 family, |
834 | struct netlbl_lsm_secattr *secattr) | 951 | struct netlbl_lsm_secattr *secattr) |
835 | { | 952 | { |
836 | if (CIPSO_V4_OPTEXIST(skb) && | 953 | switch (family) { |
837 | cipso_v4_skbuff_getattr(skb, secattr) == 0) | 954 | case AF_INET: |
838 | return 0; | 955 | if (CIPSO_V4_OPTEXIST(skb) && |
956 | cipso_v4_skbuff_getattr(skb, secattr) == 0) | ||
957 | return 0; | ||
958 | break; | ||
959 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
960 | case AF_INET6: | ||
961 | break; | ||
962 | #endif /* IPv6 */ | ||
963 | } | ||
839 | 964 | ||
840 | return netlbl_unlabel_getattr(skb, family, secattr); | 965 | return netlbl_unlabel_getattr(skb, family, secattr); |
841 | } | 966 | } |
diff --git a/net/socket.c b/net/socket.c index 0b14b79c03af..91d0c0254ffe 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -1536,8 +1536,6 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr, | |||
1536 | fd_install(newfd, newfile); | 1536 | fd_install(newfd, newfile); |
1537 | err = newfd; | 1537 | err = newfd; |
1538 | 1538 | ||
1539 | security_socket_post_accept(sock, newsock); | ||
1540 | |||
1541 | out_put: | 1539 | out_put: |
1542 | fput_light(sock->file, fput_needed); | 1540 | fput_light(sock->file, fput_needed); |
1543 | out: | 1541 | out: |
diff --git a/security/capability.c b/security/capability.c index c545bd1300b5..21b6cead6a8e 100644 --- a/security/capability.c +++ b/security/capability.c | |||
@@ -620,10 +620,6 @@ static int cap_socket_accept(struct socket *sock, struct socket *newsock) | |||
620 | return 0; | 620 | return 0; |
621 | } | 621 | } |
622 | 622 | ||
623 | static void cap_socket_post_accept(struct socket *sock, struct socket *newsock) | ||
624 | { | ||
625 | } | ||
626 | |||
627 | static int cap_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size) | 623 | static int cap_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size) |
628 | { | 624 | { |
629 | return 0; | 625 | return 0; |
@@ -1014,7 +1010,6 @@ void security_fixup_ops(struct security_operations *ops) | |||
1014 | set_to_cap_if_null(ops, socket_connect); | 1010 | set_to_cap_if_null(ops, socket_connect); |
1015 | set_to_cap_if_null(ops, socket_listen); | 1011 | set_to_cap_if_null(ops, socket_listen); |
1016 | set_to_cap_if_null(ops, socket_accept); | 1012 | set_to_cap_if_null(ops, socket_accept); |
1017 | set_to_cap_if_null(ops, socket_post_accept); | ||
1018 | set_to_cap_if_null(ops, socket_sendmsg); | 1013 | set_to_cap_if_null(ops, socket_sendmsg); |
1019 | set_to_cap_if_null(ops, socket_recvmsg); | 1014 | set_to_cap_if_null(ops, socket_recvmsg); |
1020 | set_to_cap_if_null(ops, socket_getsockname); | 1015 | set_to_cap_if_null(ops, socket_getsockname); |
diff --git a/security/security.c b/security/security.c index c3586c0d97e2..206e53844d2f 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -1007,11 +1007,6 @@ int security_socket_accept(struct socket *sock, struct socket *newsock) | |||
1007 | return security_ops->socket_accept(sock, newsock); | 1007 | return security_ops->socket_accept(sock, newsock); |
1008 | } | 1008 | } |
1009 | 1009 | ||
1010 | void security_socket_post_accept(struct socket *sock, struct socket *newsock) | ||
1011 | { | ||
1012 | security_ops->socket_post_accept(sock, newsock); | ||
1013 | } | ||
1014 | |||
1015 | int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size) | 1010 | int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size) |
1016 | { | 1011 | { |
1017 | return security_ops->socket_sendmsg(sock, msg, size); | 1012 | return security_ops->socket_sendmsg(sock, msg, size); |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 7c52ba243c64..ba808ef6babb 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -93,7 +93,6 @@ | |||
93 | 93 | ||
94 | extern unsigned int policydb_loaded_version; | 94 | extern unsigned int policydb_loaded_version; |
95 | extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); | 95 | extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); |
96 | extern int selinux_compat_net; | ||
97 | extern struct security_operations *security_ops; | 96 | extern struct security_operations *security_ops; |
98 | 97 | ||
99 | /* SECMARK reference count */ | 98 | /* SECMARK reference count */ |
@@ -311,7 +310,7 @@ static int sk_alloc_security(struct sock *sk, int family, gfp_t priority) | |||
311 | ssec->sid = SECINITSID_UNLABELED; | 310 | ssec->sid = SECINITSID_UNLABELED; |
312 | sk->sk_security = ssec; | 311 | sk->sk_security = ssec; |
313 | 312 | ||
314 | selinux_netlbl_sk_security_reset(ssec, family); | 313 | selinux_netlbl_sk_security_reset(ssec); |
315 | 314 | ||
316 | return 0; | 315 | return 0; |
317 | } | 316 | } |
@@ -2945,7 +2944,6 @@ static void selinux_inode_getsecid(const struct inode *inode, u32 *secid) | |||
2945 | static int selinux_revalidate_file_permission(struct file *file, int mask) | 2944 | static int selinux_revalidate_file_permission(struct file *file, int mask) |
2946 | { | 2945 | { |
2947 | const struct cred *cred = current_cred(); | 2946 | const struct cred *cred = current_cred(); |
2948 | int rc; | ||
2949 | struct inode *inode = file->f_path.dentry->d_inode; | 2947 | struct inode *inode = file->f_path.dentry->d_inode; |
2950 | 2948 | ||
2951 | if (!mask) { | 2949 | if (!mask) { |
@@ -2957,29 +2955,15 @@ static int selinux_revalidate_file_permission(struct file *file, int mask) | |||
2957 | if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE)) | 2955 | if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE)) |
2958 | mask |= MAY_APPEND; | 2956 | mask |= MAY_APPEND; |
2959 | 2957 | ||
2960 | rc = file_has_perm(cred, file, | 2958 | return file_has_perm(cred, file, |
2961 | file_mask_to_av(inode->i_mode, mask)); | 2959 | file_mask_to_av(inode->i_mode, mask)); |
2962 | if (rc) | ||
2963 | return rc; | ||
2964 | |||
2965 | return selinux_netlbl_inode_permission(inode, mask); | ||
2966 | } | 2960 | } |
2967 | 2961 | ||
2968 | static int selinux_file_permission(struct file *file, int mask) | 2962 | static int selinux_file_permission(struct file *file, int mask) |
2969 | { | 2963 | { |
2970 | struct inode *inode = file->f_path.dentry->d_inode; | 2964 | if (!mask) |
2971 | struct file_security_struct *fsec = file->f_security; | ||
2972 | struct inode_security_struct *isec = inode->i_security; | ||
2973 | u32 sid = current_sid(); | ||
2974 | |||
2975 | if (!mask) { | ||
2976 | /* No permission to check. Existence test. */ | 2965 | /* No permission to check. Existence test. */ |
2977 | return 0; | 2966 | return 0; |
2978 | } | ||
2979 | |||
2980 | if (sid == fsec->sid && fsec->isid == isec->sid | ||
2981 | && fsec->pseqno == avc_policy_seqno()) | ||
2982 | return selinux_netlbl_inode_permission(inode, mask); | ||
2983 | 2967 | ||
2984 | return selinux_revalidate_file_permission(file, mask); | 2968 | return selinux_revalidate_file_permission(file, mask); |
2985 | } | 2969 | } |
@@ -3723,7 +3707,7 @@ static int selinux_socket_post_create(struct socket *sock, int family, | |||
3723 | sksec = sock->sk->sk_security; | 3707 | sksec = sock->sk->sk_security; |
3724 | sksec->sid = isec->sid; | 3708 | sksec->sid = isec->sid; |
3725 | sksec->sclass = isec->sclass; | 3709 | sksec->sclass = isec->sclass; |
3726 | err = selinux_netlbl_socket_post_create(sock); | 3710 | err = selinux_netlbl_socket_post_create(sock->sk, family); |
3727 | } | 3711 | } |
3728 | 3712 | ||
3729 | return err; | 3713 | return err; |
@@ -3914,13 +3898,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock) | |||
3914 | static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg, | 3898 | static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg, |
3915 | int size) | 3899 | int size) |
3916 | { | 3900 | { |
3917 | int rc; | 3901 | return socket_has_perm(current, sock, SOCKET__WRITE); |
3918 | |||
3919 | rc = socket_has_perm(current, sock, SOCKET__WRITE); | ||
3920 | if (rc) | ||
3921 | return rc; | ||
3922 | |||
3923 | return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE); | ||
3924 | } | 3902 | } |
3925 | 3903 | ||
3926 | static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg, | 3904 | static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg, |
@@ -4040,72 +4018,6 @@ static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family, | |||
4040 | SECCLASS_NODE, NODE__RECVFROM, ad); | 4018 | SECCLASS_NODE, NODE__RECVFROM, ad); |
4041 | } | 4019 | } |
4042 | 4020 | ||
4043 | static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk, | ||
4044 | struct sk_buff *skb, | ||
4045 | struct avc_audit_data *ad, | ||
4046 | u16 family, | ||
4047 | char *addrp) | ||
4048 | { | ||
4049 | int err; | ||
4050 | struct sk_security_struct *sksec = sk->sk_security; | ||
4051 | u16 sk_class; | ||
4052 | u32 netif_perm, node_perm, recv_perm; | ||
4053 | u32 port_sid, node_sid, if_sid, sk_sid; | ||
4054 | |||
4055 | sk_sid = sksec->sid; | ||
4056 | sk_class = sksec->sclass; | ||
4057 | |||
4058 | switch (sk_class) { | ||
4059 | case SECCLASS_UDP_SOCKET: | ||
4060 | netif_perm = NETIF__UDP_RECV; | ||
4061 | node_perm = NODE__UDP_RECV; | ||
4062 | recv_perm = UDP_SOCKET__RECV_MSG; | ||
4063 | break; | ||
4064 | case SECCLASS_TCP_SOCKET: | ||
4065 | netif_perm = NETIF__TCP_RECV; | ||
4066 | node_perm = NODE__TCP_RECV; | ||
4067 | recv_perm = TCP_SOCKET__RECV_MSG; | ||
4068 | break; | ||
4069 | case SECCLASS_DCCP_SOCKET: | ||
4070 | netif_perm = NETIF__DCCP_RECV; | ||
4071 | node_perm = NODE__DCCP_RECV; | ||
4072 | recv_perm = DCCP_SOCKET__RECV_MSG; | ||
4073 | break; | ||
4074 | default: | ||
4075 | netif_perm = NETIF__RAWIP_RECV; | ||
4076 | node_perm = NODE__RAWIP_RECV; | ||
4077 | recv_perm = 0; | ||
4078 | break; | ||
4079 | } | ||
4080 | |||
4081 | err = sel_netif_sid(skb->iif, &if_sid); | ||
4082 | if (err) | ||
4083 | return err; | ||
4084 | err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad); | ||
4085 | if (err) | ||
4086 | return err; | ||
4087 | |||
4088 | err = sel_netnode_sid(addrp, family, &node_sid); | ||
4089 | if (err) | ||
4090 | return err; | ||
4091 | err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad); | ||
4092 | if (err) | ||
4093 | return err; | ||
4094 | |||
4095 | if (!recv_perm) | ||
4096 | return 0; | ||
4097 | err = sel_netport_sid(sk->sk_protocol, | ||
4098 | ntohs(ad->u.net.sport), &port_sid); | ||
4099 | if (unlikely(err)) { | ||
4100 | printk(KERN_WARNING | ||
4101 | "SELinux: failure in" | ||
4102 | " selinux_sock_rcv_skb_iptables_compat()," | ||
4103 | " network port label not found\n"); | ||
4104 | return err; | ||
4105 | } | ||
4106 | return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad); | ||
4107 | } | ||
4108 | |||
4109 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | 4021 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, |
4110 | u16 family) | 4022 | u16 family) |
4111 | { | 4023 | { |
@@ -4123,14 +4035,12 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | |||
4123 | if (err) | 4035 | if (err) |
4124 | return err; | 4036 | return err; |
4125 | 4037 | ||
4126 | if (selinux_compat_net) | 4038 | if (selinux_secmark_enabled()) { |
4127 | err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad, | ||
4128 | family, addrp); | ||
4129 | else if (selinux_secmark_enabled()) | ||
4130 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, | 4039 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, |
4131 | PACKET__RECV, &ad); | 4040 | PACKET__RECV, &ad); |
4132 | if (err) | 4041 | if (err) |
4133 | return err; | 4042 | return err; |
4043 | } | ||
4134 | 4044 | ||
4135 | if (selinux_policycap_netpeer) { | 4045 | if (selinux_policycap_netpeer) { |
4136 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); | 4046 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); |
@@ -4172,7 +4082,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
4172 | * to the selinux_sock_rcv_skb_compat() function to deal with the | 4082 | * to the selinux_sock_rcv_skb_compat() function to deal with the |
4173 | * special handling. We do this in an attempt to keep this function | 4083 | * special handling. We do this in an attempt to keep this function |
4174 | * as fast and as clean as possible. */ | 4084 | * as fast and as clean as possible. */ |
4175 | if (selinux_compat_net || !selinux_policycap_netpeer) | 4085 | if (!selinux_policycap_netpeer) |
4176 | return selinux_sock_rcv_skb_compat(sk, skb, family); | 4086 | return selinux_sock_rcv_skb_compat(sk, skb, family); |
4177 | 4087 | ||
4178 | secmark_active = selinux_secmark_enabled(); | 4088 | secmark_active = selinux_secmark_enabled(); |
@@ -4304,7 +4214,7 @@ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk) | |||
4304 | newssec->peer_sid = ssec->peer_sid; | 4214 | newssec->peer_sid = ssec->peer_sid; |
4305 | newssec->sclass = ssec->sclass; | 4215 | newssec->sclass = ssec->sclass; |
4306 | 4216 | ||
4307 | selinux_netlbl_sk_security_reset(newssec, newsk->sk_family); | 4217 | selinux_netlbl_sk_security_reset(newssec); |
4308 | } | 4218 | } |
4309 | 4219 | ||
4310 | static void selinux_sk_getsecid(struct sock *sk, u32 *secid) | 4220 | static void selinux_sk_getsecid(struct sock *sk, u32 *secid) |
@@ -4348,16 +4258,15 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
4348 | if (peersid == SECSID_NULL) { | 4258 | if (peersid == SECSID_NULL) { |
4349 | req->secid = sksec->sid; | 4259 | req->secid = sksec->sid; |
4350 | req->peer_secid = SECSID_NULL; | 4260 | req->peer_secid = SECSID_NULL; |
4351 | return 0; | 4261 | } else { |
4262 | err = security_sid_mls_copy(sksec->sid, peersid, &newsid); | ||
4263 | if (err) | ||
4264 | return err; | ||
4265 | req->secid = newsid; | ||
4266 | req->peer_secid = peersid; | ||
4352 | } | 4267 | } |
4353 | 4268 | ||
4354 | err = security_sid_mls_copy(sksec->sid, peersid, &newsid); | 4269 | return selinux_netlbl_inet_conn_request(req, family); |
4355 | if (err) | ||
4356 | return err; | ||
4357 | |||
4358 | req->secid = newsid; | ||
4359 | req->peer_secid = peersid; | ||
4360 | return 0; | ||
4361 | } | 4270 | } |
4362 | 4271 | ||
4363 | static void selinux_inet_csk_clone(struct sock *newsk, | 4272 | static void selinux_inet_csk_clone(struct sock *newsk, |
@@ -4374,7 +4283,7 @@ static void selinux_inet_csk_clone(struct sock *newsk, | |||
4374 | 4283 | ||
4375 | /* We don't need to take any sort of lock here as we are the only | 4284 | /* We don't need to take any sort of lock here as we are the only |
4376 | * thread with access to newsksec */ | 4285 | * thread with access to newsksec */ |
4377 | selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family); | 4286 | selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family); |
4378 | } | 4287 | } |
4379 | 4288 | ||
4380 | static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) | 4289 | static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) |
@@ -4387,8 +4296,6 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) | |||
4387 | family = PF_INET; | 4296 | family = PF_INET; |
4388 | 4297 | ||
4389 | selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); | 4298 | selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); |
4390 | |||
4391 | selinux_netlbl_inet_conn_established(sk, family); | ||
4392 | } | 4299 | } |
4393 | 4300 | ||
4394 | static void selinux_req_classify_flow(const struct request_sock *req, | 4301 | static void selinux_req_classify_flow(const struct request_sock *req, |
@@ -4540,71 +4447,6 @@ static unsigned int selinux_ipv4_output(unsigned int hooknum, | |||
4540 | return selinux_ip_output(skb, PF_INET); | 4447 | return selinux_ip_output(skb, PF_INET); |
4541 | } | 4448 | } |
4542 | 4449 | ||
4543 | static int selinux_ip_postroute_iptables_compat(struct sock *sk, | ||
4544 | int ifindex, | ||
4545 | struct avc_audit_data *ad, | ||
4546 | u16 family, char *addrp) | ||
4547 | { | ||
4548 | int err; | ||
4549 | struct sk_security_struct *sksec = sk->sk_security; | ||
4550 | u16 sk_class; | ||
4551 | u32 netif_perm, node_perm, send_perm; | ||
4552 | u32 port_sid, node_sid, if_sid, sk_sid; | ||
4553 | |||
4554 | sk_sid = sksec->sid; | ||
4555 | sk_class = sksec->sclass; | ||
4556 | |||
4557 | switch (sk_class) { | ||
4558 | case SECCLASS_UDP_SOCKET: | ||
4559 | netif_perm = NETIF__UDP_SEND; | ||
4560 | node_perm = NODE__UDP_SEND; | ||
4561 | send_perm = UDP_SOCKET__SEND_MSG; | ||
4562 | break; | ||
4563 | case SECCLASS_TCP_SOCKET: | ||
4564 | netif_perm = NETIF__TCP_SEND; | ||
4565 | node_perm = NODE__TCP_SEND; | ||
4566 | send_perm = TCP_SOCKET__SEND_MSG; | ||
4567 | break; | ||
4568 | case SECCLASS_DCCP_SOCKET: | ||
4569 | netif_perm = NETIF__DCCP_SEND; | ||
4570 | node_perm = NODE__DCCP_SEND; | ||
4571 | send_perm = DCCP_SOCKET__SEND_MSG; | ||
4572 | break; | ||
4573 | default: | ||
4574 | netif_perm = NETIF__RAWIP_SEND; | ||
4575 | node_perm = NODE__RAWIP_SEND; | ||
4576 | send_perm = 0; | ||
4577 | break; | ||
4578 | } | ||
4579 | |||
4580 | err = sel_netif_sid(ifindex, &if_sid); | ||
4581 | if (err) | ||
4582 | return err; | ||
4583 | err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad); | ||
4584 | return err; | ||
4585 | |||
4586 | err = sel_netnode_sid(addrp, family, &node_sid); | ||
4587 | if (err) | ||
4588 | return err; | ||
4589 | err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad); | ||
4590 | if (err) | ||
4591 | return err; | ||
4592 | |||
4593 | if (send_perm != 0) | ||
4594 | return 0; | ||
4595 | |||
4596 | err = sel_netport_sid(sk->sk_protocol, | ||
4597 | ntohs(ad->u.net.dport), &port_sid); | ||
4598 | if (unlikely(err)) { | ||
4599 | printk(KERN_WARNING | ||
4600 | "SELinux: failure in" | ||
4601 | " selinux_ip_postroute_iptables_compat()," | ||
4602 | " network port label not found\n"); | ||
4603 | return err; | ||
4604 | } | ||
4605 | return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad); | ||
4606 | } | ||
4607 | |||
4608 | static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | 4450 | static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, |
4609 | int ifindex, | 4451 | int ifindex, |
4610 | u16 family) | 4452 | u16 family) |
@@ -4625,15 +4467,10 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | |||
4625 | if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) | 4467 | if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) |
4626 | return NF_DROP; | 4468 | return NF_DROP; |
4627 | 4469 | ||
4628 | if (selinux_compat_net) { | 4470 | if (selinux_secmark_enabled()) |
4629 | if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex, | ||
4630 | &ad, family, addrp)) | ||
4631 | return NF_DROP; | ||
4632 | } else if (selinux_secmark_enabled()) { | ||
4633 | if (avc_has_perm(sksec->sid, skb->secmark, | 4471 | if (avc_has_perm(sksec->sid, skb->secmark, |
4634 | SECCLASS_PACKET, PACKET__SEND, &ad)) | 4472 | SECCLASS_PACKET, PACKET__SEND, &ad)) |
4635 | return NF_DROP; | 4473 | return NF_DROP; |
4636 | } | ||
4637 | 4474 | ||
4638 | if (selinux_policycap_netpeer) | 4475 | if (selinux_policycap_netpeer) |
4639 | if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto)) | 4476 | if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto)) |
@@ -4657,7 +4494,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
4657 | * to the selinux_ip_postroute_compat() function to deal with the | 4494 | * to the selinux_ip_postroute_compat() function to deal with the |
4658 | * special handling. We do this in an attempt to keep this function | 4495 | * special handling. We do this in an attempt to keep this function |
4659 | * as fast and as clean as possible. */ | 4496 | * as fast and as clean as possible. */ |
4660 | if (selinux_compat_net || !selinux_policycap_netpeer) | 4497 | if (!selinux_policycap_netpeer) |
4661 | return selinux_ip_postroute_compat(skb, ifindex, family); | 4498 | return selinux_ip_postroute_compat(skb, ifindex, family); |
4662 | #ifdef CONFIG_XFRM | 4499 | #ifdef CONFIG_XFRM |
4663 | /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec | 4500 | /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec |
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index b913c8d06038..b4b5b9b2f0be 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/net.h> | 32 | #include <linux/net.h> |
33 | #include <linux/skbuff.h> | 33 | #include <linux/skbuff.h> |
34 | #include <net/sock.h> | 34 | #include <net/sock.h> |
35 | #include <net/request_sock.h> | ||
35 | 36 | ||
36 | #include "avc.h" | 37 | #include "avc.h" |
37 | #include "objsec.h" | 38 | #include "objsec.h" |
@@ -42,8 +43,7 @@ void selinux_netlbl_cache_invalidate(void); | |||
42 | void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway); | 43 | void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway); |
43 | 44 | ||
44 | void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec); | 45 | void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec); |
45 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, | 46 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec); |
46 | int family); | ||
47 | 47 | ||
48 | int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | 48 | int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, |
49 | u16 family, | 49 | u16 family, |
@@ -53,9 +53,9 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | |||
53 | u16 family, | 53 | u16 family, |
54 | u32 sid); | 54 | u32 sid); |
55 | 55 | ||
56 | void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family); | 56 | int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family); |
57 | int selinux_netlbl_socket_post_create(struct socket *sock); | 57 | void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family); |
58 | int selinux_netlbl_inode_permission(struct inode *inode, int mask); | 58 | int selinux_netlbl_socket_post_create(struct sock *sk, u16 family); |
59 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | 59 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, |
60 | struct sk_buff *skb, | 60 | struct sk_buff *skb, |
61 | u16 family, | 61 | u16 family, |
@@ -85,8 +85,7 @@ static inline void selinux_netlbl_sk_security_free( | |||
85 | } | 85 | } |
86 | 86 | ||
87 | static inline void selinux_netlbl_sk_security_reset( | 87 | static inline void selinux_netlbl_sk_security_reset( |
88 | struct sk_security_struct *ssec, | 88 | struct sk_security_struct *ssec) |
89 | int family) | ||
90 | { | 89 | { |
91 | return; | 90 | return; |
92 | } | 91 | } |
@@ -113,17 +112,17 @@ static inline int selinux_netlbl_conn_setsid(struct sock *sk, | |||
113 | return 0; | 112 | return 0; |
114 | } | 113 | } |
115 | 114 | ||
116 | static inline void selinux_netlbl_inet_conn_established(struct sock *sk, | 115 | static inline int selinux_netlbl_inet_conn_request(struct request_sock *req, |
117 | u16 family) | 116 | u16 family) |
118 | { | 117 | { |
119 | return; | 118 | return 0; |
120 | } | 119 | } |
121 | static inline int selinux_netlbl_socket_post_create(struct socket *sock) | 120 | static inline void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family) |
122 | { | 121 | { |
123 | return 0; | 122 | return; |
124 | } | 123 | } |
125 | static inline int selinux_netlbl_inode_permission(struct inode *inode, | 124 | static inline int selinux_netlbl_socket_post_create(struct sock *sk, |
126 | int mask) | 125 | u16 family) |
127 | { | 126 | { |
128 | return 0; | 127 | return 0; |
129 | } | 128 | } |
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 350794ab9b42..2e984413c7b2 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c | |||
@@ -100,41 +100,6 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk) | |||
100 | } | 100 | } |
101 | 101 | ||
102 | /** | 102 | /** |
103 | * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism | ||
104 | * @sk: the socket to label | ||
105 | * | ||
106 | * Description: | ||
107 | * Attempt to label a socket using the NetLabel mechanism. Returns zero values | ||
108 | * on success, negative values on failure. | ||
109 | * | ||
110 | */ | ||
111 | static int selinux_netlbl_sock_setsid(struct sock *sk) | ||
112 | { | ||
113 | int rc; | ||
114 | struct sk_security_struct *sksec = sk->sk_security; | ||
115 | struct netlbl_lsm_secattr *secattr; | ||
116 | |||
117 | if (sksec->nlbl_state != NLBL_REQUIRE) | ||
118 | return 0; | ||
119 | |||
120 | secattr = selinux_netlbl_sock_genattr(sk); | ||
121 | if (secattr == NULL) | ||
122 | return -ENOMEM; | ||
123 | rc = netlbl_sock_setattr(sk, secattr); | ||
124 | switch (rc) { | ||
125 | case 0: | ||
126 | sksec->nlbl_state = NLBL_LABELED; | ||
127 | break; | ||
128 | case -EDESTADDRREQ: | ||
129 | sksec->nlbl_state = NLBL_REQSKB; | ||
130 | rc = 0; | ||
131 | break; | ||
132 | } | ||
133 | |||
134 | return rc; | ||
135 | } | ||
136 | |||
137 | /** | ||
138 | * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache | 103 | * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache |
139 | * | 104 | * |
140 | * Description: | 105 | * Description: |
@@ -188,13 +153,9 @@ void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec) | |||
188 | * The caller is responsibile for all the NetLabel sk_security_struct locking. | 153 | * The caller is responsibile for all the NetLabel sk_security_struct locking. |
189 | * | 154 | * |
190 | */ | 155 | */ |
191 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, | 156 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec) |
192 | int family) | ||
193 | { | 157 | { |
194 | if (family == PF_INET) | 158 | ssec->nlbl_state = NLBL_UNSET; |
195 | ssec->nlbl_state = NLBL_REQUIRE; | ||
196 | else | ||
197 | ssec->nlbl_state = NLBL_UNSET; | ||
198 | } | 159 | } |
199 | 160 | ||
200 | /** | 161 | /** |
@@ -281,127 +242,86 @@ skbuff_setsid_return: | |||
281 | } | 242 | } |
282 | 243 | ||
283 | /** | 244 | /** |
284 | * selinux_netlbl_inet_conn_established - Netlabel the newly accepted connection | 245 | * selinux_netlbl_inet_conn_request - Label an incoming stream connection |
285 | * @sk: the new connection | 246 | * @req: incoming connection request socket |
286 | * | 247 | * |
287 | * Description: | 248 | * Description: |
288 | * A new connection has been established on @sk so make sure it is labeled | 249 | * A new incoming connection request is represented by @req, we need to label |
289 | * correctly with the NetLabel susbsystem. | 250 | * the new request_sock here and the stack will ensure the on-the-wire label |
251 | * will get preserved when a full sock is created once the connection handshake | ||
252 | * is complete. Returns zero on success, negative values on failure. | ||
290 | * | 253 | * |
291 | */ | 254 | */ |
292 | void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family) | 255 | int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family) |
293 | { | 256 | { |
294 | int rc; | 257 | int rc; |
295 | struct sk_security_struct *sksec = sk->sk_security; | 258 | struct netlbl_lsm_secattr secattr; |
296 | struct netlbl_lsm_secattr *secattr; | ||
297 | struct inet_sock *sk_inet = inet_sk(sk); | ||
298 | struct sockaddr_in addr; | ||
299 | |||
300 | if (sksec->nlbl_state != NLBL_REQUIRE) | ||
301 | return; | ||
302 | 259 | ||
303 | secattr = selinux_netlbl_sock_genattr(sk); | 260 | if (family != PF_INET) |
304 | if (secattr == NULL) | 261 | return 0; |
305 | return; | ||
306 | 262 | ||
307 | rc = netlbl_sock_setattr(sk, secattr); | 263 | netlbl_secattr_init(&secattr); |
308 | switch (rc) { | 264 | rc = security_netlbl_sid_to_secattr(req->secid, &secattr); |
309 | case 0: | 265 | if (rc != 0) |
310 | sksec->nlbl_state = NLBL_LABELED; | 266 | goto inet_conn_request_return; |
311 | break; | 267 | rc = netlbl_req_setattr(req, &secattr); |
312 | case -EDESTADDRREQ: | 268 | inet_conn_request_return: |
313 | /* no PF_INET6 support yet because we don't support any IPv6 | 269 | netlbl_secattr_destroy(&secattr); |
314 | * labeling protocols */ | 270 | return rc; |
315 | if (family != PF_INET) { | ||
316 | sksec->nlbl_state = NLBL_UNSET; | ||
317 | return; | ||
318 | } | ||
319 | |||
320 | addr.sin_family = family; | ||
321 | addr.sin_addr.s_addr = sk_inet->daddr; | ||
322 | if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr, | ||
323 | secattr) != 0) { | ||
324 | /* we failed to label the connected socket (could be | ||
325 | * for a variety of reasons, the actual "why" isn't | ||
326 | * important here) so we have to go to our backup plan, | ||
327 | * labeling the packets individually in the netfilter | ||
328 | * local output hook. this is okay but we need to | ||
329 | * adjust the MSS of the connection to take into | ||
330 | * account any labeling overhead, since we don't know | ||
331 | * the exact overhead at this point we'll use the worst | ||
332 | * case value which is 40 bytes for IPv4 */ | ||
333 | struct inet_connection_sock *sk_conn = inet_csk(sk); | ||
334 | sk_conn->icsk_ext_hdr_len += 40 - | ||
335 | (sk_inet->opt ? sk_inet->opt->optlen : 0); | ||
336 | sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie); | ||
337 | |||
338 | sksec->nlbl_state = NLBL_REQSKB; | ||
339 | } else | ||
340 | sksec->nlbl_state = NLBL_CONNLABELED; | ||
341 | break; | ||
342 | default: | ||
343 | /* note that we are failing to label the socket which could be | ||
344 | * a bad thing since it means traffic could leave the system | ||
345 | * without the desired labeling, however, all is not lost as | ||
346 | * we have a check in selinux_netlbl_inode_permission() to | ||
347 | * pick up the pieces that we might drop here because we can't | ||
348 | * return an error code */ | ||
349 | break; | ||
350 | } | ||
351 | } | 271 | } |
352 | 272 | ||
353 | /** | 273 | /** |
354 | * selinux_netlbl_socket_post_create - Label a socket using NetLabel | 274 | * selinux_netlbl_inet_csk_clone - Initialize the newly created sock |
355 | * @sock: the socket to label | 275 | * @sk: the new sock |
356 | * | 276 | * |
357 | * Description: | 277 | * Description: |
358 | * Attempt to label a socket using the NetLabel mechanism using the given | 278 | * A new connection has been established using @sk, we've already labeled the |
359 | * SID. Returns zero values on success, negative values on failure. | 279 | * socket via the request_sock struct in selinux_netlbl_inet_conn_request() but |
280 | * we need to set the NetLabel state here since we now have a sock structure. | ||
360 | * | 281 | * |
361 | */ | 282 | */ |
362 | int selinux_netlbl_socket_post_create(struct socket *sock) | 283 | void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family) |
363 | { | 284 | { |
364 | return selinux_netlbl_sock_setsid(sock->sk); | 285 | struct sk_security_struct *sksec = sk->sk_security; |
286 | |||
287 | if (family == PF_INET) | ||
288 | sksec->nlbl_state = NLBL_LABELED; | ||
289 | else | ||
290 | sksec->nlbl_state = NLBL_UNSET; | ||
365 | } | 291 | } |
366 | 292 | ||
367 | /** | 293 | /** |
368 | * selinux_netlbl_inode_permission - Verify the socket is NetLabel labeled | 294 | * selinux_netlbl_socket_post_create - Label a socket using NetLabel |
369 | * @inode: the file descriptor's inode | 295 | * @sock: the socket to label |
370 | * @mask: the permission mask | 296 | * @family: protocol family |
371 | * | 297 | * |
372 | * Description: | 298 | * Description: |
373 | * Looks at a file's inode and if it is marked as a socket protected by | 299 | * Attempt to label a socket using the NetLabel mechanism using the given |
374 | * NetLabel then verify that the socket has been labeled, if not try to label | 300 | * SID. Returns zero values on success, negative values on failure. |
375 | * the socket now with the inode's SID. Returns zero on success, negative | ||
376 | * values on failure. | ||
377 | * | 301 | * |
378 | */ | 302 | */ |
379 | int selinux_netlbl_inode_permission(struct inode *inode, int mask) | 303 | int selinux_netlbl_socket_post_create(struct sock *sk, u16 family) |
380 | { | 304 | { |
381 | int rc; | 305 | int rc; |
382 | struct sock *sk; | 306 | struct sk_security_struct *sksec = sk->sk_security; |
383 | struct socket *sock; | 307 | struct netlbl_lsm_secattr *secattr; |
384 | struct sk_security_struct *sksec; | ||
385 | 308 | ||
386 | if (!S_ISSOCK(inode->i_mode) || | 309 | if (family != PF_INET) |
387 | ((mask & (MAY_WRITE | MAY_APPEND)) == 0)) | ||
388 | return 0; | ||
389 | sock = SOCKET_I(inode); | ||
390 | sk = sock->sk; | ||
391 | if (sk == NULL) | ||
392 | return 0; | ||
393 | sksec = sk->sk_security; | ||
394 | if (sksec == NULL || sksec->nlbl_state != NLBL_REQUIRE) | ||
395 | return 0; | 310 | return 0; |
396 | 311 | ||
397 | local_bh_disable(); | 312 | secattr = selinux_netlbl_sock_genattr(sk); |
398 | bh_lock_sock_nested(sk); | 313 | if (secattr == NULL) |
399 | if (likely(sksec->nlbl_state == NLBL_REQUIRE)) | 314 | return -ENOMEM; |
400 | rc = selinux_netlbl_sock_setsid(sk); | 315 | rc = netlbl_sock_setattr(sk, family, secattr); |
401 | else | 316 | switch (rc) { |
317 | case 0: | ||
318 | sksec->nlbl_state = NLBL_LABELED; | ||
319 | break; | ||
320 | case -EDESTADDRREQ: | ||
321 | sksec->nlbl_state = NLBL_REQSKB; | ||
402 | rc = 0; | 322 | rc = 0; |
403 | bh_unlock_sock(sk); | 323 | break; |
404 | local_bh_enable(); | 324 | } |
405 | 325 | ||
406 | return rc; | 326 | return rc; |
407 | } | 327 | } |
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index d3c8b982cfb0..2d5136ec3d54 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -47,8 +47,6 @@ static char *policycap_names[] = { | |||
47 | 47 | ||
48 | unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE; | 48 | unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE; |
49 | 49 | ||
50 | int selinux_compat_net = 0; | ||
51 | |||
52 | static int __init checkreqprot_setup(char *str) | 50 | static int __init checkreqprot_setup(char *str) |
53 | { | 51 | { |
54 | unsigned long checkreqprot; | 52 | unsigned long checkreqprot; |
@@ -58,16 +56,6 @@ static int __init checkreqprot_setup(char *str) | |||
58 | } | 56 | } |
59 | __setup("checkreqprot=", checkreqprot_setup); | 57 | __setup("checkreqprot=", checkreqprot_setup); |
60 | 58 | ||
61 | static int __init selinux_compat_net_setup(char *str) | ||
62 | { | ||
63 | unsigned long compat_net; | ||
64 | if (!strict_strtoul(str, 0, &compat_net)) | ||
65 | selinux_compat_net = compat_net ? 1 : 0; | ||
66 | return 1; | ||
67 | } | ||
68 | __setup("selinux_compat_net=", selinux_compat_net_setup); | ||
69 | |||
70 | |||
71 | static DEFINE_MUTEX(sel_mutex); | 59 | static DEFINE_MUTEX(sel_mutex); |
72 | 60 | ||
73 | /* global data for booleans */ | 61 | /* global data for booleans */ |
@@ -450,61 +438,6 @@ static const struct file_operations sel_checkreqprot_ops = { | |||
450 | .write = sel_write_checkreqprot, | 438 | .write = sel_write_checkreqprot, |
451 | }; | 439 | }; |
452 | 440 | ||
453 | static ssize_t sel_read_compat_net(struct file *filp, char __user *buf, | ||
454 | size_t count, loff_t *ppos) | ||
455 | { | ||
456 | char tmpbuf[TMPBUFLEN]; | ||
457 | ssize_t length; | ||
458 | |||
459 | length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_compat_net); | ||
460 | return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); | ||
461 | } | ||
462 | |||
463 | static ssize_t sel_write_compat_net(struct file *file, const char __user *buf, | ||
464 | size_t count, loff_t *ppos) | ||
465 | { | ||
466 | char *page; | ||
467 | ssize_t length; | ||
468 | int new_value; | ||
469 | |||
470 | length = task_has_security(current, SECURITY__LOAD_POLICY); | ||
471 | if (length) | ||
472 | return length; | ||
473 | |||
474 | if (count >= PAGE_SIZE) | ||
475 | return -ENOMEM; | ||
476 | if (*ppos != 0) { | ||
477 | /* No partial writes. */ | ||
478 | return -EINVAL; | ||
479 | } | ||
480 | page = (char *)get_zeroed_page(GFP_KERNEL); | ||
481 | if (!page) | ||
482 | return -ENOMEM; | ||
483 | length = -EFAULT; | ||
484 | if (copy_from_user(page, buf, count)) | ||
485 | goto out; | ||
486 | |||
487 | length = -EINVAL; | ||
488 | if (sscanf(page, "%d", &new_value) != 1) | ||
489 | goto out; | ||
490 | |||
491 | if (new_value) { | ||
492 | printk(KERN_NOTICE | ||
493 | "SELinux: compat_net is deprecated, please use secmark" | ||
494 | " instead\n"); | ||
495 | selinux_compat_net = 1; | ||
496 | } else | ||
497 | selinux_compat_net = 0; | ||
498 | length = count; | ||
499 | out: | ||
500 | free_page((unsigned long) page); | ||
501 | return length; | ||
502 | } | ||
503 | static const struct file_operations sel_compat_net_ops = { | ||
504 | .read = sel_read_compat_net, | ||
505 | .write = sel_write_compat_net, | ||
506 | }; | ||
507 | |||
508 | /* | 441 | /* |
509 | * Remaining nodes use transaction based IO methods like nfsd/nfsctl.c | 442 | * Remaining nodes use transaction based IO methods like nfsd/nfsctl.c |
510 | */ | 443 | */ |
@@ -1665,7 +1598,6 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
1665 | [SEL_DISABLE] = {"disable", &sel_disable_ops, S_IWUSR}, | 1598 | [SEL_DISABLE] = {"disable", &sel_disable_ops, S_IWUSR}, |
1666 | [SEL_MEMBER] = {"member", &transaction_ops, S_IRUGO|S_IWUGO}, | 1599 | [SEL_MEMBER] = {"member", &transaction_ops, S_IRUGO|S_IWUGO}, |
1667 | [SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR}, | 1600 | [SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR}, |
1668 | [SEL_COMPAT_NET] = {"compat_net", &sel_compat_net_ops, S_IRUGO|S_IWUSR}, | ||
1669 | [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO}, | 1601 | [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO}, |
1670 | [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO}, | 1602 | [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO}, |
1671 | /* last one */ {""} | 1603 | /* last one */ {""} |
diff --git a/security/smack/smack.h b/security/smack/smack.h index b79582e4fbfd..42ef313f9856 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/security.h> | 18 | #include <linux/security.h> |
19 | #include <linux/in.h> | 19 | #include <linux/in.h> |
20 | #include <net/netlabel.h> | 20 | #include <net/netlabel.h> |
21 | #include <linux/list.h> | ||
22 | #include <linux/rculist.h> | ||
21 | 23 | ||
22 | /* | 24 | /* |
23 | * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is | 25 | * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is |
@@ -40,7 +42,6 @@ struct superblock_smack { | |||
40 | struct socket_smack { | 42 | struct socket_smack { |
41 | char *smk_out; /* outbound label */ | 43 | char *smk_out; /* outbound label */ |
42 | char *smk_in; /* inbound label */ | 44 | char *smk_in; /* inbound label */ |
43 | int smk_labeled; /* label scheme */ | ||
44 | char smk_packet[SMK_LABELLEN]; /* TCP peer label */ | 45 | char smk_packet[SMK_LABELLEN]; /* TCP peer label */ |
45 | }; | 46 | }; |
46 | 47 | ||
@@ -59,17 +60,10 @@ struct inode_smack { | |||
59 | * A label access rule. | 60 | * A label access rule. |
60 | */ | 61 | */ |
61 | struct smack_rule { | 62 | struct smack_rule { |
62 | char *smk_subject; | 63 | struct list_head list; |
63 | char *smk_object; | 64 | char *smk_subject; |
64 | int smk_access; | 65 | char *smk_object; |
65 | }; | 66 | int smk_access; |
66 | |||
67 | /* | ||
68 | * An entry in the table of permitted label accesses. | ||
69 | */ | ||
70 | struct smk_list_entry { | ||
71 | struct smk_list_entry *smk_next; | ||
72 | struct smack_rule smk_rule; | ||
73 | }; | 67 | }; |
74 | 68 | ||
75 | /* | 69 | /* |
@@ -85,7 +79,7 @@ struct smack_cipso { | |||
85 | * An entry in the table identifying hosts. | 79 | * An entry in the table identifying hosts. |
86 | */ | 80 | */ |
87 | struct smk_netlbladdr { | 81 | struct smk_netlbladdr { |
88 | struct smk_netlbladdr *smk_next; | 82 | struct list_head list; |
89 | struct sockaddr_in smk_host; /* network address */ | 83 | struct sockaddr_in smk_host; /* network address */ |
90 | struct in_addr smk_mask; /* network mask */ | 84 | struct in_addr smk_mask; /* network mask */ |
91 | char *smk_label; /* label */ | 85 | char *smk_label; /* label */ |
@@ -113,7 +107,7 @@ struct smk_netlbladdr { | |||
113 | * the cipso direct mapping in used internally. | 107 | * the cipso direct mapping in used internally. |
114 | */ | 108 | */ |
115 | struct smack_known { | 109 | struct smack_known { |
116 | struct smack_known *smk_next; | 110 | struct list_head list; |
117 | char smk_known[SMK_LABELLEN]; | 111 | char smk_known[SMK_LABELLEN]; |
118 | u32 smk_secid; | 112 | u32 smk_secid; |
119 | struct smack_cipso *smk_cipso; | 113 | struct smack_cipso *smk_cipso; |
@@ -138,6 +132,8 @@ struct smack_known { | |||
138 | #define XATTR_NAME_SMACKIPIN XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN | 132 | #define XATTR_NAME_SMACKIPIN XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN |
139 | #define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT | 133 | #define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT |
140 | 134 | ||
135 | #define SMACK_CIPSO_OPTION "-CIPSO" | ||
136 | |||
141 | /* | 137 | /* |
142 | * How communications on this socket are treated. | 138 | * How communications on this socket are treated. |
143 | * Usually it's determined by the underlying netlabel code | 139 | * Usually it's determined by the underlying netlabel code |
@@ -205,8 +201,8 @@ u32 smack_to_secid(const char *); | |||
205 | extern int smack_cipso_direct; | 201 | extern int smack_cipso_direct; |
206 | extern char *smack_net_ambient; | 202 | extern char *smack_net_ambient; |
207 | extern char *smack_onlycap; | 203 | extern char *smack_onlycap; |
204 | extern const char *smack_cipso_option; | ||
208 | 205 | ||
209 | extern struct smack_known *smack_known; | ||
210 | extern struct smack_known smack_known_floor; | 206 | extern struct smack_known smack_known_floor; |
211 | extern struct smack_known smack_known_hat; | 207 | extern struct smack_known smack_known_hat; |
212 | extern struct smack_known smack_known_huh; | 208 | extern struct smack_known smack_known_huh; |
@@ -214,8 +210,10 @@ extern struct smack_known smack_known_invalid; | |||
214 | extern struct smack_known smack_known_star; | 210 | extern struct smack_known smack_known_star; |
215 | extern struct smack_known smack_known_web; | 211 | extern struct smack_known smack_known_web; |
216 | 212 | ||
217 | extern struct smk_list_entry *smack_list; | 213 | extern struct list_head smack_known_list; |
218 | extern struct smk_netlbladdr *smack_netlbladdrs; | 214 | extern struct list_head smack_rule_list; |
215 | extern struct list_head smk_netlbladdr_list; | ||
216 | |||
219 | extern struct security_operations smack_ops; | 217 | extern struct security_operations smack_ops; |
220 | 218 | ||
221 | /* | 219 | /* |
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index cfa19ca125e3..ac0a2707f6d4 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c | |||
@@ -16,48 +16,42 @@ | |||
16 | #include "smack.h" | 16 | #include "smack.h" |
17 | 17 | ||
18 | struct smack_known smack_known_huh = { | 18 | struct smack_known smack_known_huh = { |
19 | .smk_next = NULL, | ||
20 | .smk_known = "?", | 19 | .smk_known = "?", |
21 | .smk_secid = 2, | 20 | .smk_secid = 2, |
22 | .smk_cipso = NULL, | 21 | .smk_cipso = NULL, |
23 | }; | 22 | }; |
24 | 23 | ||
25 | struct smack_known smack_known_hat = { | 24 | struct smack_known smack_known_hat = { |
26 | .smk_next = &smack_known_huh, | ||
27 | .smk_known = "^", | 25 | .smk_known = "^", |
28 | .smk_secid = 3, | 26 | .smk_secid = 3, |
29 | .smk_cipso = NULL, | 27 | .smk_cipso = NULL, |
30 | }; | 28 | }; |
31 | 29 | ||
32 | struct smack_known smack_known_star = { | 30 | struct smack_known smack_known_star = { |
33 | .smk_next = &smack_known_hat, | ||
34 | .smk_known = "*", | 31 | .smk_known = "*", |
35 | .smk_secid = 4, | 32 | .smk_secid = 4, |
36 | .smk_cipso = NULL, | 33 | .smk_cipso = NULL, |
37 | }; | 34 | }; |
38 | 35 | ||
39 | struct smack_known smack_known_floor = { | 36 | struct smack_known smack_known_floor = { |
40 | .smk_next = &smack_known_star, | ||
41 | .smk_known = "_", | 37 | .smk_known = "_", |
42 | .smk_secid = 5, | 38 | .smk_secid = 5, |
43 | .smk_cipso = NULL, | 39 | .smk_cipso = NULL, |
44 | }; | 40 | }; |
45 | 41 | ||
46 | struct smack_known smack_known_invalid = { | 42 | struct smack_known smack_known_invalid = { |
47 | .smk_next = &smack_known_floor, | ||
48 | .smk_known = "", | 43 | .smk_known = "", |
49 | .smk_secid = 6, | 44 | .smk_secid = 6, |
50 | .smk_cipso = NULL, | 45 | .smk_cipso = NULL, |
51 | }; | 46 | }; |
52 | 47 | ||
53 | struct smack_known smack_known_web = { | 48 | struct smack_known smack_known_web = { |
54 | .smk_next = &smack_known_invalid, | ||
55 | .smk_known = "@", | 49 | .smk_known = "@", |
56 | .smk_secid = 7, | 50 | .smk_secid = 7, |
57 | .smk_cipso = NULL, | 51 | .smk_cipso = NULL, |
58 | }; | 52 | }; |
59 | 53 | ||
60 | struct smack_known *smack_known = &smack_known_web; | 54 | LIST_HEAD(smack_known_list); |
61 | 55 | ||
62 | /* | 56 | /* |
63 | * The initial value needs to be bigger than any of the | 57 | * The initial value needs to be bigger than any of the |
@@ -87,7 +81,6 @@ static u32 smack_next_secid = 10; | |||
87 | int smk_access(char *subject_label, char *object_label, int request) | 81 | int smk_access(char *subject_label, char *object_label, int request) |
88 | { | 82 | { |
89 | u32 may = MAY_NOT; | 83 | u32 may = MAY_NOT; |
90 | struct smk_list_entry *sp; | ||
91 | struct smack_rule *srp; | 84 | struct smack_rule *srp; |
92 | 85 | ||
93 | /* | 86 | /* |
@@ -139,9 +132,8 @@ int smk_access(char *subject_label, char *object_label, int request) | |||
139 | * access (e.g. read is included in readwrite) it's | 132 | * access (e.g. read is included in readwrite) it's |
140 | * good. | 133 | * good. |
141 | */ | 134 | */ |
142 | for (sp = smack_list; sp != NULL; sp = sp->smk_next) { | 135 | rcu_read_lock(); |
143 | srp = &sp->smk_rule; | 136 | list_for_each_entry_rcu(srp, &smack_rule_list, list) { |
144 | |||
145 | if (srp->smk_subject == subject_label || | 137 | if (srp->smk_subject == subject_label || |
146 | strcmp(srp->smk_subject, subject_label) == 0) { | 138 | strcmp(srp->smk_subject, subject_label) == 0) { |
147 | if (srp->smk_object == object_label || | 139 | if (srp->smk_object == object_label || |
@@ -151,6 +143,7 @@ int smk_access(char *subject_label, char *object_label, int request) | |||
151 | } | 143 | } |
152 | } | 144 | } |
153 | } | 145 | } |
146 | rcu_read_unlock(); | ||
154 | /* | 147 | /* |
155 | * This is a bit map operation. | 148 | * This is a bit map operation. |
156 | */ | 149 | */ |
@@ -228,14 +221,17 @@ struct smack_known *smk_import_entry(const char *string, int len) | |||
228 | 221 | ||
229 | mutex_lock(&smack_known_lock); | 222 | mutex_lock(&smack_known_lock); |
230 | 223 | ||
231 | for (skp = smack_known; skp != NULL; skp = skp->smk_next) | 224 | found = 0; |
232 | if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) | 225 | list_for_each_entry_rcu(skp, &smack_known_list, list) { |
226 | if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) { | ||
227 | found = 1; | ||
233 | break; | 228 | break; |
229 | } | ||
230 | } | ||
234 | 231 | ||
235 | if (skp == NULL) { | 232 | if (found == 0) { |
236 | skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL); | 233 | skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL); |
237 | if (skp != NULL) { | 234 | if (skp != NULL) { |
238 | skp->smk_next = smack_known; | ||
239 | strncpy(skp->smk_known, smack, SMK_MAXLEN); | 235 | strncpy(skp->smk_known, smack, SMK_MAXLEN); |
240 | skp->smk_secid = smack_next_secid++; | 236 | skp->smk_secid = smack_next_secid++; |
241 | skp->smk_cipso = NULL; | 237 | skp->smk_cipso = NULL; |
@@ -244,8 +240,7 @@ struct smack_known *smk_import_entry(const char *string, int len) | |||
244 | * Make sure that the entry is actually | 240 | * Make sure that the entry is actually |
245 | * filled before putting it on the list. | 241 | * filled before putting it on the list. |
246 | */ | 242 | */ |
247 | smp_mb(); | 243 | list_add_rcu(&skp->list, &smack_known_list); |
248 | smack_known = skp; | ||
249 | } | 244 | } |
250 | } | 245 | } |
251 | 246 | ||
@@ -266,6 +261,9 @@ char *smk_import(const char *string, int len) | |||
266 | { | 261 | { |
267 | struct smack_known *skp; | 262 | struct smack_known *skp; |
268 | 263 | ||
264 | /* labels cannot begin with a '-' */ | ||
265 | if (string[0] == '-') | ||
266 | return NULL; | ||
269 | skp = smk_import_entry(string, len); | 267 | skp = smk_import_entry(string, len); |
270 | if (skp == NULL) | 268 | if (skp == NULL) |
271 | return NULL; | 269 | return NULL; |
@@ -283,14 +281,19 @@ char *smack_from_secid(const u32 secid) | |||
283 | { | 281 | { |
284 | struct smack_known *skp; | 282 | struct smack_known *skp; |
285 | 283 | ||
286 | for (skp = smack_known; skp != NULL; skp = skp->smk_next) | 284 | rcu_read_lock(); |
287 | if (skp->smk_secid == secid) | 285 | list_for_each_entry_rcu(skp, &smack_known_list, list) { |
286 | if (skp->smk_secid == secid) { | ||
287 | rcu_read_unlock(); | ||
288 | return skp->smk_known; | 288 | return skp->smk_known; |
289 | } | ||
290 | } | ||
289 | 291 | ||
290 | /* | 292 | /* |
291 | * If we got this far someone asked for the translation | 293 | * If we got this far someone asked for the translation |
292 | * of a secid that is not on the list. | 294 | * of a secid that is not on the list. |
293 | */ | 295 | */ |
296 | rcu_read_unlock(); | ||
294 | return smack_known_invalid.smk_known; | 297 | return smack_known_invalid.smk_known; |
295 | } | 298 | } |
296 | 299 | ||
@@ -305,9 +308,14 @@ u32 smack_to_secid(const char *smack) | |||
305 | { | 308 | { |
306 | struct smack_known *skp; | 309 | struct smack_known *skp; |
307 | 310 | ||
308 | for (skp = smack_known; skp != NULL; skp = skp->smk_next) | 311 | rcu_read_lock(); |
309 | if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) | 312 | list_for_each_entry_rcu(skp, &smack_known_list, list) { |
313 | if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) { | ||
314 | rcu_read_unlock(); | ||
310 | return skp->smk_secid; | 315 | return skp->smk_secid; |
316 | } | ||
317 | } | ||
318 | rcu_read_unlock(); | ||
311 | return 0; | 319 | return 0; |
312 | } | 320 | } |
313 | 321 | ||
@@ -332,7 +340,8 @@ void smack_from_cipso(u32 level, char *cp, char *result) | |||
332 | struct smack_known *kp; | 340 | struct smack_known *kp; |
333 | char *final = NULL; | 341 | char *final = NULL; |
334 | 342 | ||
335 | for (kp = smack_known; final == NULL && kp != NULL; kp = kp->smk_next) { | 343 | rcu_read_lock(); |
344 | list_for_each_entry(kp, &smack_known_list, list) { | ||
336 | if (kp->smk_cipso == NULL) | 345 | if (kp->smk_cipso == NULL) |
337 | continue; | 346 | continue; |
338 | 347 | ||
@@ -344,6 +353,7 @@ void smack_from_cipso(u32 level, char *cp, char *result) | |||
344 | 353 | ||
345 | spin_unlock_bh(&kp->smk_cipsolock); | 354 | spin_unlock_bh(&kp->smk_cipsolock); |
346 | } | 355 | } |
356 | rcu_read_unlock(); | ||
347 | if (final == NULL) | 357 | if (final == NULL) |
348 | final = smack_known_huh.smk_known; | 358 | final = smack_known_huh.smk_known; |
349 | strncpy(result, final, SMK_MAXLEN); | 359 | strncpy(result, final, SMK_MAXLEN); |
@@ -360,13 +370,19 @@ void smack_from_cipso(u32 level, char *cp, char *result) | |||
360 | int smack_to_cipso(const char *smack, struct smack_cipso *cp) | 370 | int smack_to_cipso(const char *smack, struct smack_cipso *cp) |
361 | { | 371 | { |
362 | struct smack_known *kp; | 372 | struct smack_known *kp; |
373 | int found = 0; | ||
363 | 374 | ||
364 | for (kp = smack_known; kp != NULL; kp = kp->smk_next) | 375 | rcu_read_lock(); |
376 | list_for_each_entry_rcu(kp, &smack_known_list, list) { | ||
365 | if (kp->smk_known == smack || | 377 | if (kp->smk_known == smack || |
366 | strcmp(kp->smk_known, smack) == 0) | 378 | strcmp(kp->smk_known, smack) == 0) { |
379 | found = 1; | ||
367 | break; | 380 | break; |
381 | } | ||
382 | } | ||
383 | rcu_read_unlock(); | ||
368 | 384 | ||
369 | if (kp == NULL || kp->smk_cipso == NULL) | 385 | if (found == 0 || kp->smk_cipso == NULL) |
370 | return -ENOENT; | 386 | return -ENOENT; |
371 | 387 | ||
372 | memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso)); | 388 | memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso)); |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 84b62b5e9e2c..921514902eca 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -7,6 +7,8 @@ | |||
7 | * Casey Schaufler <casey@schaufler-ca.com> | 7 | * Casey Schaufler <casey@schaufler-ca.com> |
8 | * | 8 | * |
9 | * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com> | 9 | * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com> |
10 | * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. | ||
11 | * Paul Moore <paul.moore@hp.com> | ||
10 | * | 12 | * |
11 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2, | 14 | * it under the terms of the GNU General Public License version 2, |
@@ -20,6 +22,7 @@ | |||
20 | #include <linux/ext2_fs.h> | 22 | #include <linux/ext2_fs.h> |
21 | #include <linux/kd.h> | 23 | #include <linux/kd.h> |
22 | #include <asm/ioctls.h> | 24 | #include <asm/ioctls.h> |
25 | #include <linux/ip.h> | ||
23 | #include <linux/tcp.h> | 26 | #include <linux/tcp.h> |
24 | #include <linux/udp.h> | 27 | #include <linux/udp.h> |
25 | #include <linux/mutex.h> | 28 | #include <linux/mutex.h> |
@@ -606,6 +609,9 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, | |||
606 | strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) { | 609 | strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) { |
607 | if (!capable(CAP_MAC_ADMIN)) | 610 | if (!capable(CAP_MAC_ADMIN)) |
608 | rc = -EPERM; | 611 | rc = -EPERM; |
612 | /* a label cannot be void and cannot begin with '-' */ | ||
613 | if (size == 0 || (size > 0 && ((char *)value)[0] == '-')) | ||
614 | rc = -EINVAL; | ||
609 | } else | 615 | } else |
610 | rc = cap_inode_setxattr(dentry, name, value, size, flags); | 616 | rc = cap_inode_setxattr(dentry, name, value, size, flags); |
611 | 617 | ||
@@ -1275,7 +1281,6 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags) | |||
1275 | 1281 | ||
1276 | ssp->smk_in = csp; | 1282 | ssp->smk_in = csp; |
1277 | ssp->smk_out = csp; | 1283 | ssp->smk_out = csp; |
1278 | ssp->smk_labeled = SMACK_CIPSO_SOCKET; | ||
1279 | ssp->smk_packet[0] = '\0'; | 1284 | ssp->smk_packet[0] = '\0'; |
1280 | 1285 | ||
1281 | sk->sk_security = ssp; | 1286 | sk->sk_security = ssp; |
@@ -1295,6 +1300,43 @@ static void smack_sk_free_security(struct sock *sk) | |||
1295 | } | 1300 | } |
1296 | 1301 | ||
1297 | /** | 1302 | /** |
1303 | * smack_host_label - check host based restrictions | ||
1304 | * @sip: the object end | ||
1305 | * | ||
1306 | * looks for host based access restrictions | ||
1307 | * | ||
1308 | * This version will only be appropriate for really small sets of single label | ||
1309 | * hosts. The caller is responsible for ensuring that the RCU read lock is | ||
1310 | * taken before calling this function. | ||
1311 | * | ||
1312 | * Returns the label of the far end or NULL if it's not special. | ||
1313 | */ | ||
1314 | static char *smack_host_label(struct sockaddr_in *sip) | ||
1315 | { | ||
1316 | struct smk_netlbladdr *snp; | ||
1317 | struct in_addr *siap = &sip->sin_addr; | ||
1318 | |||
1319 | if (siap->s_addr == 0) | ||
1320 | return NULL; | ||
1321 | |||
1322 | list_for_each_entry_rcu(snp, &smk_netlbladdr_list, list) | ||
1323 | /* | ||
1324 | * we break after finding the first match because | ||
1325 | * the list is sorted from longest to shortest mask | ||
1326 | * so we have found the most specific match | ||
1327 | */ | ||
1328 | if ((&snp->smk_host.sin_addr)->s_addr == | ||
1329 | (siap->s_addr & (&snp->smk_mask)->s_addr)) { | ||
1330 | /* we have found the special CIPSO option */ | ||
1331 | if (snp->smk_label == smack_cipso_option) | ||
1332 | return NULL; | ||
1333 | return snp->smk_label; | ||
1334 | } | ||
1335 | |||
1336 | return NULL; | ||
1337 | } | ||
1338 | |||
1339 | /** | ||
1298 | * smack_set_catset - convert a capset to netlabel mls categories | 1340 | * smack_set_catset - convert a capset to netlabel mls categories |
1299 | * @catset: the Smack categories | 1341 | * @catset: the Smack categories |
1300 | * @sap: where to put the netlabel categories | 1342 | * @sap: where to put the netlabel categories |
@@ -1365,11 +1407,10 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp) | |||
1365 | */ | 1407 | */ |
1366 | static int smack_netlabel(struct sock *sk, int labeled) | 1408 | static int smack_netlabel(struct sock *sk, int labeled) |
1367 | { | 1409 | { |
1368 | struct socket_smack *ssp; | 1410 | struct socket_smack *ssp = sk->sk_security; |
1369 | struct netlbl_lsm_secattr secattr; | 1411 | struct netlbl_lsm_secattr secattr; |
1370 | int rc = 0; | 1412 | int rc = 0; |
1371 | 1413 | ||
1372 | ssp = sk->sk_security; | ||
1373 | /* | 1414 | /* |
1374 | * Usually the netlabel code will handle changing the | 1415 | * Usually the netlabel code will handle changing the |
1375 | * packet labeling based on the label. | 1416 | * packet labeling based on the label. |
@@ -1387,27 +1428,51 @@ static int smack_netlabel(struct sock *sk, int labeled) | |||
1387 | else { | 1428 | else { |
1388 | netlbl_secattr_init(&secattr); | 1429 | netlbl_secattr_init(&secattr); |
1389 | smack_to_secattr(ssp->smk_out, &secattr); | 1430 | smack_to_secattr(ssp->smk_out, &secattr); |
1390 | rc = netlbl_sock_setattr(sk, &secattr); | 1431 | rc = netlbl_sock_setattr(sk, sk->sk_family, &secattr); |
1391 | netlbl_secattr_destroy(&secattr); | 1432 | netlbl_secattr_destroy(&secattr); |
1392 | } | 1433 | } |
1393 | 1434 | ||
1394 | bh_unlock_sock(sk); | 1435 | bh_unlock_sock(sk); |
1395 | local_bh_enable(); | 1436 | local_bh_enable(); |
1396 | /* | ||
1397 | * Remember the label scheme used so that it is not | ||
1398 | * necessary to do the netlabel setting if it has not | ||
1399 | * changed the next time through. | ||
1400 | * | ||
1401 | * The -EDESTADDRREQ case is an indication that there's | ||
1402 | * a single level host involved. | ||
1403 | */ | ||
1404 | if (rc == 0) | ||
1405 | ssp->smk_labeled = labeled; | ||
1406 | 1437 | ||
1407 | return rc; | 1438 | return rc; |
1408 | } | 1439 | } |
1409 | 1440 | ||
1410 | /** | 1441 | /** |
1442 | * smack_netlbel_send - Set the secattr on a socket and perform access checks | ||
1443 | * @sk: the socket | ||
1444 | * @sap: the destination address | ||
1445 | * | ||
1446 | * Set the correct secattr for the given socket based on the destination | ||
1447 | * address and perform any outbound access checks needed. | ||
1448 | * | ||
1449 | * Returns 0 on success or an error code. | ||
1450 | * | ||
1451 | */ | ||
1452 | static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) | ||
1453 | { | ||
1454 | int rc; | ||
1455 | int sk_lbl; | ||
1456 | char *hostsp; | ||
1457 | struct socket_smack *ssp = sk->sk_security; | ||
1458 | |||
1459 | rcu_read_lock(); | ||
1460 | hostsp = smack_host_label(sap); | ||
1461 | if (hostsp != NULL) { | ||
1462 | sk_lbl = SMACK_UNLABELED_SOCKET; | ||
1463 | rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE); | ||
1464 | } else { | ||
1465 | sk_lbl = SMACK_CIPSO_SOCKET; | ||
1466 | rc = 0; | ||
1467 | } | ||
1468 | rcu_read_unlock(); | ||
1469 | if (rc != 0) | ||
1470 | return rc; | ||
1471 | |||
1472 | return smack_netlabel(sk, sk_lbl); | ||
1473 | } | ||
1474 | |||
1475 | /** | ||
1411 | * smack_inode_setsecurity - set smack xattrs | 1476 | * smack_inode_setsecurity - set smack xattrs |
1412 | * @inode: the object | 1477 | * @inode: the object |
1413 | * @name: attribute name | 1478 | * @name: attribute name |
@@ -1428,7 +1493,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, | |||
1428 | struct socket *sock; | 1493 | struct socket *sock; |
1429 | int rc = 0; | 1494 | int rc = 0; |
1430 | 1495 | ||
1431 | if (value == NULL || size > SMK_LABELLEN) | 1496 | if (value == NULL || size > SMK_LABELLEN || size == 0) |
1432 | return -EACCES; | 1497 | return -EACCES; |
1433 | 1498 | ||
1434 | sp = smk_import(value, size); | 1499 | sp = smk_import(value, size); |
@@ -1488,41 +1553,6 @@ static int smack_socket_post_create(struct socket *sock, int family, | |||
1488 | return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); | 1553 | return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); |
1489 | } | 1554 | } |
1490 | 1555 | ||
1491 | |||
1492 | /** | ||
1493 | * smack_host_label - check host based restrictions | ||
1494 | * @sip: the object end | ||
1495 | * | ||
1496 | * looks for host based access restrictions | ||
1497 | * | ||
1498 | * This version will only be appropriate for really small | ||
1499 | * sets of single label hosts. | ||
1500 | * | ||
1501 | * Returns the label of the far end or NULL if it's not special. | ||
1502 | */ | ||
1503 | static char *smack_host_label(struct sockaddr_in *sip) | ||
1504 | { | ||
1505 | struct smk_netlbladdr *snp; | ||
1506 | struct in_addr *siap = &sip->sin_addr; | ||
1507 | |||
1508 | if (siap->s_addr == 0) | ||
1509 | return NULL; | ||
1510 | |||
1511 | for (snp = smack_netlbladdrs; snp != NULL; snp = snp->smk_next) { | ||
1512 | /* | ||
1513 | * we break after finding the first match because | ||
1514 | * the list is sorted from longest to shortest mask | ||
1515 | * so we have found the most specific match | ||
1516 | */ | ||
1517 | if ((&snp->smk_host.sin_addr)->s_addr == | ||
1518 | (siap->s_addr & (&snp->smk_mask)->s_addr)) { | ||
1519 | return snp->smk_label; | ||
1520 | } | ||
1521 | } | ||
1522 | |||
1523 | return NULL; | ||
1524 | } | ||
1525 | |||
1526 | /** | 1556 | /** |
1527 | * smack_socket_connect - connect access check | 1557 | * smack_socket_connect - connect access check |
1528 | * @sock: the socket | 1558 | * @sock: the socket |
@@ -1536,30 +1566,12 @@ static char *smack_host_label(struct sockaddr_in *sip) | |||
1536 | static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, | 1566 | static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, |
1537 | int addrlen) | 1567 | int addrlen) |
1538 | { | 1568 | { |
1539 | struct socket_smack *ssp = sock->sk->sk_security; | ||
1540 | char *hostsp; | ||
1541 | int rc; | ||
1542 | |||
1543 | if (sock->sk == NULL || sock->sk->sk_family != PF_INET) | 1569 | if (sock->sk == NULL || sock->sk->sk_family != PF_INET) |
1544 | return 0; | 1570 | return 0; |
1545 | |||
1546 | if (addrlen < sizeof(struct sockaddr_in)) | 1571 | if (addrlen < sizeof(struct sockaddr_in)) |
1547 | return -EINVAL; | 1572 | return -EINVAL; |
1548 | 1573 | ||
1549 | hostsp = smack_host_label((struct sockaddr_in *)sap); | 1574 | return smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap); |
1550 | if (hostsp == NULL) { | ||
1551 | if (ssp->smk_labeled != SMACK_CIPSO_SOCKET) | ||
1552 | return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); | ||
1553 | return 0; | ||
1554 | } | ||
1555 | |||
1556 | rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE); | ||
1557 | if (rc != 0) | ||
1558 | return rc; | ||
1559 | |||
1560 | if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET) | ||
1561 | return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET); | ||
1562 | return 0; | ||
1563 | } | 1575 | } |
1564 | 1576 | ||
1565 | /** | 1577 | /** |
@@ -2260,9 +2272,6 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, | |||
2260 | int size) | 2272 | int size) |
2261 | { | 2273 | { |
2262 | struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name; | 2274 | struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name; |
2263 | struct socket_smack *ssp = sock->sk->sk_security; | ||
2264 | char *hostsp; | ||
2265 | int rc; | ||
2266 | 2275 | ||
2267 | /* | 2276 | /* |
2268 | * Perfectly reasonable for this to be NULL | 2277 | * Perfectly reasonable for this to be NULL |
@@ -2270,22 +2279,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, | |||
2270 | if (sip == NULL || sip->sin_family != PF_INET) | 2279 | if (sip == NULL || sip->sin_family != PF_INET) |
2271 | return 0; | 2280 | return 0; |
2272 | 2281 | ||
2273 | hostsp = smack_host_label(sip); | 2282 | return smack_netlabel_send(sock->sk, sip); |
2274 | if (hostsp == NULL) { | ||
2275 | if (ssp->smk_labeled != SMACK_CIPSO_SOCKET) | ||
2276 | return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); | ||
2277 | return 0; | ||
2278 | } | ||
2279 | |||
2280 | rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE); | ||
2281 | if (rc != 0) | ||
2282 | return rc; | ||
2283 | |||
2284 | if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET) | ||
2285 | return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET); | ||
2286 | |||
2287 | return 0; | ||
2288 | |||
2289 | } | 2283 | } |
2290 | 2284 | ||
2291 | 2285 | ||
@@ -2490,31 +2484,24 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, | |||
2490 | } | 2484 | } |
2491 | 2485 | ||
2492 | /** | 2486 | /** |
2493 | * smack_sock_graft - graft access state between two sockets | 2487 | * smack_sock_graft - Initialize a newly created socket with an existing sock |
2494 | * @sk: fresh sock | 2488 | * @sk: child sock |
2495 | * @parent: donor socket | 2489 | * @parent: parent socket |
2496 | * | 2490 | * |
2497 | * Sets the netlabel socket state on sk from parent | 2491 | * Set the smk_{in,out} state of an existing sock based on the process that |
2492 | * is creating the new socket. | ||
2498 | */ | 2493 | */ |
2499 | static void smack_sock_graft(struct sock *sk, struct socket *parent) | 2494 | static void smack_sock_graft(struct sock *sk, struct socket *parent) |
2500 | { | 2495 | { |
2501 | struct socket_smack *ssp; | 2496 | struct socket_smack *ssp; |
2502 | int rc; | ||
2503 | 2497 | ||
2504 | if (sk == NULL) | 2498 | if (sk == NULL || |
2505 | return; | 2499 | (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)) |
2506 | |||
2507 | if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6) | ||
2508 | return; | 2500 | return; |
2509 | 2501 | ||
2510 | ssp = sk->sk_security; | 2502 | ssp = sk->sk_security; |
2511 | ssp->smk_in = ssp->smk_out = current_security(); | 2503 | ssp->smk_in = ssp->smk_out = current_security(); |
2512 | ssp->smk_packet[0] = '\0'; | 2504 | /* cssp->smk_packet is already set in smack_inet_csk_clone() */ |
2513 | |||
2514 | rc = smack_netlabel(sk, SMACK_CIPSO_SOCKET); | ||
2515 | if (rc != 0) | ||
2516 | printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n", | ||
2517 | __func__, -rc); | ||
2518 | } | 2505 | } |
2519 | 2506 | ||
2520 | /** | 2507 | /** |
@@ -2529,35 +2516,82 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent) | |||
2529 | static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, | 2516 | static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, |
2530 | struct request_sock *req) | 2517 | struct request_sock *req) |
2531 | { | 2518 | { |
2532 | struct netlbl_lsm_secattr skb_secattr; | 2519 | u16 family = sk->sk_family; |
2533 | struct socket_smack *ssp = sk->sk_security; | 2520 | struct socket_smack *ssp = sk->sk_security; |
2521 | struct netlbl_lsm_secattr secattr; | ||
2522 | struct sockaddr_in addr; | ||
2523 | struct iphdr *hdr; | ||
2534 | char smack[SMK_LABELLEN]; | 2524 | char smack[SMK_LABELLEN]; |
2535 | int rc; | 2525 | int rc; |
2536 | 2526 | ||
2537 | if (skb == NULL) | 2527 | /* handle mapped IPv4 packets arriving via IPv6 sockets */ |
2538 | return -EACCES; | 2528 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) |
2529 | family = PF_INET; | ||
2539 | 2530 | ||
2540 | netlbl_secattr_init(&skb_secattr); | 2531 | netlbl_secattr_init(&secattr); |
2541 | rc = netlbl_skbuff_getattr(skb, sk->sk_family, &skb_secattr); | 2532 | rc = netlbl_skbuff_getattr(skb, family, &secattr); |
2542 | if (rc == 0) | 2533 | if (rc == 0) |
2543 | smack_from_secattr(&skb_secattr, smack); | 2534 | smack_from_secattr(&secattr, smack); |
2544 | else | 2535 | else |
2545 | strncpy(smack, smack_known_huh.smk_known, SMK_MAXLEN); | 2536 | strncpy(smack, smack_known_huh.smk_known, SMK_MAXLEN); |
2546 | netlbl_secattr_destroy(&skb_secattr); | 2537 | netlbl_secattr_destroy(&secattr); |
2538 | |||
2547 | /* | 2539 | /* |
2548 | * Receiving a packet requires that the other end | 2540 | * Receiving a packet requires that the other end be able to write |
2549 | * be able to write here. Read access is not required. | 2541 | * here. Read access is not required. |
2550 | * | ||
2551 | * If the request is successful save the peer's label | ||
2552 | * so that SO_PEERCRED can report it. | ||
2553 | */ | 2542 | */ |
2554 | rc = smk_access(smack, ssp->smk_in, MAY_WRITE); | 2543 | rc = smk_access(smack, ssp->smk_in, MAY_WRITE); |
2555 | if (rc == 0) | 2544 | if (rc != 0) |
2556 | strncpy(ssp->smk_packet, smack, SMK_MAXLEN); | 2545 | return rc; |
2546 | |||
2547 | /* | ||
2548 | * Save the peer's label in the request_sock so we can later setup | ||
2549 | * smk_packet in the child socket so that SO_PEERCRED can report it. | ||
2550 | */ | ||
2551 | req->peer_secid = smack_to_secid(smack); | ||
2552 | |||
2553 | /* | ||
2554 | * We need to decide if we want to label the incoming connection here | ||
2555 | * if we do we only need to label the request_sock and the stack will | ||
2556 | * propogate the wire-label to the sock when it is created. | ||
2557 | */ | ||
2558 | hdr = ip_hdr(skb); | ||
2559 | addr.sin_addr.s_addr = hdr->saddr; | ||
2560 | rcu_read_lock(); | ||
2561 | if (smack_host_label(&addr) == NULL) { | ||
2562 | rcu_read_unlock(); | ||
2563 | netlbl_secattr_init(&secattr); | ||
2564 | smack_to_secattr(smack, &secattr); | ||
2565 | rc = netlbl_req_setattr(req, &secattr); | ||
2566 | netlbl_secattr_destroy(&secattr); | ||
2567 | } else { | ||
2568 | rcu_read_unlock(); | ||
2569 | netlbl_req_delattr(req); | ||
2570 | } | ||
2557 | 2571 | ||
2558 | return rc; | 2572 | return rc; |
2559 | } | 2573 | } |
2560 | 2574 | ||
2575 | /** | ||
2576 | * smack_inet_csk_clone - Copy the connection information to the new socket | ||
2577 | * @sk: the new socket | ||
2578 | * @req: the connection's request_sock | ||
2579 | * | ||
2580 | * Transfer the connection's peer label to the newly created socket. | ||
2581 | */ | ||
2582 | static void smack_inet_csk_clone(struct sock *sk, | ||
2583 | const struct request_sock *req) | ||
2584 | { | ||
2585 | struct socket_smack *ssp = sk->sk_security; | ||
2586 | char *smack; | ||
2587 | |||
2588 | if (req->peer_secid != 0) { | ||
2589 | smack = smack_from_secid(req->peer_secid); | ||
2590 | strncpy(ssp->smk_packet, smack, SMK_MAXLEN); | ||
2591 | } else | ||
2592 | ssp->smk_packet[0] = '\0'; | ||
2593 | } | ||
2594 | |||
2561 | /* | 2595 | /* |
2562 | * Key management security hooks | 2596 | * Key management security hooks |
2563 | * | 2597 | * |
@@ -2909,6 +2943,7 @@ struct security_operations smack_ops = { | |||
2909 | .sk_free_security = smack_sk_free_security, | 2943 | .sk_free_security = smack_sk_free_security, |
2910 | .sock_graft = smack_sock_graft, | 2944 | .sock_graft = smack_sock_graft, |
2911 | .inet_conn_request = smack_inet_conn_request, | 2945 | .inet_conn_request = smack_inet_conn_request, |
2946 | .inet_csk_clone = smack_inet_csk_clone, | ||
2912 | 2947 | ||
2913 | /* key management security hooks */ | 2948 | /* key management security hooks */ |
2914 | #ifdef CONFIG_KEYS | 2949 | #ifdef CONFIG_KEYS |
@@ -2930,6 +2965,17 @@ struct security_operations smack_ops = { | |||
2930 | .release_secctx = smack_release_secctx, | 2965 | .release_secctx = smack_release_secctx, |
2931 | }; | 2966 | }; |
2932 | 2967 | ||
2968 | |||
2969 | static __init void init_smack_know_list(void) | ||
2970 | { | ||
2971 | list_add(&smack_known_huh.list, &smack_known_list); | ||
2972 | list_add(&smack_known_hat.list, &smack_known_list); | ||
2973 | list_add(&smack_known_star.list, &smack_known_list); | ||
2974 | list_add(&smack_known_floor.list, &smack_known_list); | ||
2975 | list_add(&smack_known_invalid.list, &smack_known_list); | ||
2976 | list_add(&smack_known_web.list, &smack_known_list); | ||
2977 | } | ||
2978 | |||
2933 | /** | 2979 | /** |
2934 | * smack_init - initialize the smack system | 2980 | * smack_init - initialize the smack system |
2935 | * | 2981 | * |
@@ -2950,6 +2996,8 @@ static __init int smack_init(void) | |||
2950 | cred = (struct cred *) current->cred; | 2996 | cred = (struct cred *) current->cred; |
2951 | cred->security = &smack_known_floor.smk_known; | 2997 | cred->security = &smack_known_floor.smk_known; |
2952 | 2998 | ||
2999 | /* initilize the smack_know_list */ | ||
3000 | init_smack_know_list(); | ||
2953 | /* | 3001 | /* |
2954 | * Initialize locks | 3002 | * Initialize locks |
2955 | */ | 3003 | */ |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index a1b57e4dba3e..e03a7e19c73b 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -80,10 +80,14 @@ char *smack_onlycap; | |||
80 | * Packets are sent there unlabeled, but only from tasks that | 80 | * Packets are sent there unlabeled, but only from tasks that |
81 | * can write to the specified label. | 81 | * can write to the specified label. |
82 | */ | 82 | */ |
83 | struct smk_netlbladdr *smack_netlbladdrs; | 83 | |
84 | LIST_HEAD(smk_netlbladdr_list); | ||
85 | LIST_HEAD(smack_rule_list); | ||
84 | 86 | ||
85 | static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; | 87 | static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; |
86 | struct smk_list_entry *smack_list; | 88 | |
89 | const char *smack_cipso_option = SMACK_CIPSO_OPTION; | ||
90 | |||
87 | 91 | ||
88 | #define SEQ_READ_FINISHED 1 | 92 | #define SEQ_READ_FINISHED 1 |
89 | 93 | ||
@@ -134,24 +138,27 @@ static void *load_seq_start(struct seq_file *s, loff_t *pos) | |||
134 | { | 138 | { |
135 | if (*pos == SEQ_READ_FINISHED) | 139 | if (*pos == SEQ_READ_FINISHED) |
136 | return NULL; | 140 | return NULL; |
137 | 141 | if (list_empty(&smack_rule_list)) | |
138 | return smack_list; | 142 | return NULL; |
143 | return smack_rule_list.next; | ||
139 | } | 144 | } |
140 | 145 | ||
141 | static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos) | 146 | static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos) |
142 | { | 147 | { |
143 | struct smk_list_entry *skp = ((struct smk_list_entry *) v)->smk_next; | 148 | struct list_head *list = v; |
144 | 149 | ||
145 | if (skp == NULL) | 150 | if (list_is_last(list, &smack_rule_list)) { |
146 | *pos = SEQ_READ_FINISHED; | 151 | *pos = SEQ_READ_FINISHED; |
147 | 152 | return NULL; | |
148 | return skp; | 153 | } |
154 | return list->next; | ||
149 | } | 155 | } |
150 | 156 | ||
151 | static int load_seq_show(struct seq_file *s, void *v) | 157 | static int load_seq_show(struct seq_file *s, void *v) |
152 | { | 158 | { |
153 | struct smk_list_entry *slp = (struct smk_list_entry *) v; | 159 | struct list_head *list = v; |
154 | struct smack_rule *srp = &slp->smk_rule; | 160 | struct smack_rule *srp = |
161 | list_entry(list, struct smack_rule, list); | ||
155 | 162 | ||
156 | seq_printf(s, "%s %s", (char *)srp->smk_subject, | 163 | seq_printf(s, "%s %s", (char *)srp->smk_subject, |
157 | (char *)srp->smk_object); | 164 | (char *)srp->smk_object); |
@@ -212,32 +219,23 @@ static int smk_open_load(struct inode *inode, struct file *file) | |||
212 | */ | 219 | */ |
213 | static int smk_set_access(struct smack_rule *srp) | 220 | static int smk_set_access(struct smack_rule *srp) |
214 | { | 221 | { |
215 | struct smk_list_entry *sp; | 222 | struct smack_rule *sp; |
216 | struct smk_list_entry *newp; | ||
217 | int ret = 0; | 223 | int ret = 0; |
218 | 224 | int found; | |
219 | mutex_lock(&smack_list_lock); | 225 | mutex_lock(&smack_list_lock); |
220 | 226 | ||
221 | for (sp = smack_list; sp != NULL; sp = sp->smk_next) | 227 | found = 0; |
222 | if (sp->smk_rule.smk_subject == srp->smk_subject && | 228 | list_for_each_entry_rcu(sp, &smack_rule_list, list) { |
223 | sp->smk_rule.smk_object == srp->smk_object) { | 229 | if (sp->smk_subject == srp->smk_subject && |
224 | sp->smk_rule.smk_access = srp->smk_access; | 230 | sp->smk_object == srp->smk_object) { |
231 | found = 1; | ||
232 | sp->smk_access = srp->smk_access; | ||
225 | break; | 233 | break; |
226 | } | 234 | } |
227 | |||
228 | if (sp == NULL) { | ||
229 | newp = kzalloc(sizeof(struct smk_list_entry), GFP_KERNEL); | ||
230 | if (newp == NULL) { | ||
231 | ret = -ENOMEM; | ||
232 | goto out; | ||
233 | } | ||
234 | |||
235 | newp->smk_rule = *srp; | ||
236 | newp->smk_next = smack_list; | ||
237 | smack_list = newp; | ||
238 | } | 235 | } |
236 | if (found == 0) | ||
237 | list_add_rcu(&srp->list, &smack_rule_list); | ||
239 | 238 | ||
240 | out: | ||
241 | mutex_unlock(&smack_list_lock); | 239 | mutex_unlock(&smack_list_lock); |
242 | 240 | ||
243 | return ret; | 241 | return ret; |
@@ -261,7 +259,7 @@ out: | |||
261 | static ssize_t smk_write_load(struct file *file, const char __user *buf, | 259 | static ssize_t smk_write_load(struct file *file, const char __user *buf, |
262 | size_t count, loff_t *ppos) | 260 | size_t count, loff_t *ppos) |
263 | { | 261 | { |
264 | struct smack_rule rule; | 262 | struct smack_rule *rule; |
265 | char *data; | 263 | char *data; |
266 | int rc = -EINVAL; | 264 | int rc = -EINVAL; |
267 | 265 | ||
@@ -272,9 +270,8 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf, | |||
272 | */ | 270 | */ |
273 | if (!capable(CAP_MAC_ADMIN)) | 271 | if (!capable(CAP_MAC_ADMIN)) |
274 | return -EPERM; | 272 | return -EPERM; |
275 | if (*ppos != 0) | 273 | |
276 | return -EINVAL; | 274 | if (*ppos != 0 || count != SMK_LOADLEN) |
277 | if (count != SMK_LOADLEN) | ||
278 | return -EINVAL; | 275 | return -EINVAL; |
279 | 276 | ||
280 | data = kzalloc(count, GFP_KERNEL); | 277 | data = kzalloc(count, GFP_KERNEL); |
@@ -286,25 +283,31 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf, | |||
286 | goto out; | 283 | goto out; |
287 | } | 284 | } |
288 | 285 | ||
289 | rule.smk_subject = smk_import(data, 0); | 286 | rule = kzalloc(sizeof(*rule), GFP_KERNEL); |
290 | if (rule.smk_subject == NULL) | 287 | if (rule == NULL) { |
288 | rc = -ENOMEM; | ||
291 | goto out; | 289 | goto out; |
290 | } | ||
292 | 291 | ||
293 | rule.smk_object = smk_import(data + SMK_LABELLEN, 0); | 292 | rule->smk_subject = smk_import(data, 0); |
294 | if (rule.smk_object == NULL) | 293 | if (rule->smk_subject == NULL) |
295 | goto out; | 294 | goto out_free_rule; |
296 | 295 | ||
297 | rule.smk_access = 0; | 296 | rule->smk_object = smk_import(data + SMK_LABELLEN, 0); |
297 | if (rule->smk_object == NULL) | ||
298 | goto out_free_rule; | ||
299 | |||
300 | rule->smk_access = 0; | ||
298 | 301 | ||
299 | switch (data[SMK_LABELLEN + SMK_LABELLEN]) { | 302 | switch (data[SMK_LABELLEN + SMK_LABELLEN]) { |
300 | case '-': | 303 | case '-': |
301 | break; | 304 | break; |
302 | case 'r': | 305 | case 'r': |
303 | case 'R': | 306 | case 'R': |
304 | rule.smk_access |= MAY_READ; | 307 | rule->smk_access |= MAY_READ; |
305 | break; | 308 | break; |
306 | default: | 309 | default: |
307 | goto out; | 310 | goto out_free_rule; |
308 | } | 311 | } |
309 | 312 | ||
310 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) { | 313 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) { |
@@ -312,10 +315,10 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf, | |||
312 | break; | 315 | break; |
313 | case 'w': | 316 | case 'w': |
314 | case 'W': | 317 | case 'W': |
315 | rule.smk_access |= MAY_WRITE; | 318 | rule->smk_access |= MAY_WRITE; |
316 | break; | 319 | break; |
317 | default: | 320 | default: |
318 | goto out; | 321 | goto out_free_rule; |
319 | } | 322 | } |
320 | 323 | ||
321 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) { | 324 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) { |
@@ -323,10 +326,10 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf, | |||
323 | break; | 326 | break; |
324 | case 'x': | 327 | case 'x': |
325 | case 'X': | 328 | case 'X': |
326 | rule.smk_access |= MAY_EXEC; | 329 | rule->smk_access |= MAY_EXEC; |
327 | break; | 330 | break; |
328 | default: | 331 | default: |
329 | goto out; | 332 | goto out_free_rule; |
330 | } | 333 | } |
331 | 334 | ||
332 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) { | 335 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) { |
@@ -334,17 +337,20 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf, | |||
334 | break; | 337 | break; |
335 | case 'a': | 338 | case 'a': |
336 | case 'A': | 339 | case 'A': |
337 | rule.smk_access |= MAY_APPEND; | 340 | rule->smk_access |= MAY_APPEND; |
338 | break; | 341 | break; |
339 | default: | 342 | default: |
340 | goto out; | 343 | goto out_free_rule; |
341 | } | 344 | } |
342 | 345 | ||
343 | rc = smk_set_access(&rule); | 346 | rc = smk_set_access(rule); |
344 | 347 | ||
345 | if (!rc) | 348 | if (!rc) |
346 | rc = count; | 349 | rc = count; |
350 | goto out; | ||
347 | 351 | ||
352 | out_free_rule: | ||
353 | kfree(rule); | ||
348 | out: | 354 | out: |
349 | kfree(data); | 355 | kfree(data); |
350 | return rc; | 356 | return rc; |
@@ -433,24 +439,26 @@ static void *cipso_seq_start(struct seq_file *s, loff_t *pos) | |||
433 | { | 439 | { |
434 | if (*pos == SEQ_READ_FINISHED) | 440 | if (*pos == SEQ_READ_FINISHED) |
435 | return NULL; | 441 | return NULL; |
442 | if (list_empty(&smack_known_list)) | ||
443 | return NULL; | ||
436 | 444 | ||
437 | return smack_known; | 445 | return smack_known_list.next; |
438 | } | 446 | } |
439 | 447 | ||
440 | static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos) | 448 | static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos) |
441 | { | 449 | { |
442 | struct smack_known *skp = ((struct smack_known *) v)->smk_next; | 450 | struct list_head *list = v; |
443 | 451 | ||
444 | /* | 452 | /* |
445 | * Omit labels with no associated cipso value | 453 | * labels with no associated cipso value wont be printed |
454 | * in cipso_seq_show | ||
446 | */ | 455 | */ |
447 | while (skp != NULL && !skp->smk_cipso) | 456 | if (list_is_last(list, &smack_known_list)) { |
448 | skp = skp->smk_next; | ||
449 | |||
450 | if (skp == NULL) | ||
451 | *pos = SEQ_READ_FINISHED; | 457 | *pos = SEQ_READ_FINISHED; |
458 | return NULL; | ||
459 | } | ||
452 | 460 | ||
453 | return skp; | 461 | return list->next; |
454 | } | 462 | } |
455 | 463 | ||
456 | /* | 464 | /* |
@@ -459,7 +467,9 @@ static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos) | |||
459 | */ | 467 | */ |
460 | static int cipso_seq_show(struct seq_file *s, void *v) | 468 | static int cipso_seq_show(struct seq_file *s, void *v) |
461 | { | 469 | { |
462 | struct smack_known *skp = (struct smack_known *) v; | 470 | struct list_head *list = v; |
471 | struct smack_known *skp = | ||
472 | list_entry(list, struct smack_known, list); | ||
463 | struct smack_cipso *scp = skp->smk_cipso; | 473 | struct smack_cipso *scp = skp->smk_cipso; |
464 | char *cbp; | 474 | char *cbp; |
465 | char sep = '/'; | 475 | char sep = '/'; |
@@ -558,6 +568,11 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf, | |||
558 | goto unlockedout; | 568 | goto unlockedout; |
559 | } | 569 | } |
560 | 570 | ||
571 | /* labels cannot begin with a '-' */ | ||
572 | if (data[0] == '-') { | ||
573 | rc = -EINVAL; | ||
574 | goto unlockedout; | ||
575 | } | ||
561 | data[count] = '\0'; | 576 | data[count] = '\0'; |
562 | rule = data; | 577 | rule = data; |
563 | /* | 578 | /* |
@@ -638,18 +653,21 @@ static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos) | |||
638 | { | 653 | { |
639 | if (*pos == SEQ_READ_FINISHED) | 654 | if (*pos == SEQ_READ_FINISHED) |
640 | return NULL; | 655 | return NULL; |
641 | 656 | if (list_empty(&smk_netlbladdr_list)) | |
642 | return smack_netlbladdrs; | 657 | return NULL; |
658 | return smk_netlbladdr_list.next; | ||
643 | } | 659 | } |
644 | 660 | ||
645 | static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos) | 661 | static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos) |
646 | { | 662 | { |
647 | struct smk_netlbladdr *skp = ((struct smk_netlbladdr *) v)->smk_next; | 663 | struct list_head *list = v; |
648 | 664 | ||
649 | if (skp == NULL) | 665 | if (list_is_last(list, &smk_netlbladdr_list)) { |
650 | *pos = SEQ_READ_FINISHED; | 666 | *pos = SEQ_READ_FINISHED; |
667 | return NULL; | ||
668 | } | ||
651 | 669 | ||
652 | return skp; | 670 | return list->next; |
653 | } | 671 | } |
654 | #define BEBITS (sizeof(__be32) * 8) | 672 | #define BEBITS (sizeof(__be32) * 8) |
655 | 673 | ||
@@ -658,7 +676,9 @@ static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos) | |||
658 | */ | 676 | */ |
659 | static int netlbladdr_seq_show(struct seq_file *s, void *v) | 677 | static int netlbladdr_seq_show(struct seq_file *s, void *v) |
660 | { | 678 | { |
661 | struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v; | 679 | struct list_head *list = v; |
680 | struct smk_netlbladdr *skp = | ||
681 | list_entry(list, struct smk_netlbladdr, list); | ||
662 | unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr; | 682 | unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr; |
663 | int maskn; | 683 | int maskn; |
664 | u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr); | 684 | u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr); |
@@ -702,30 +722,36 @@ static int smk_open_netlbladdr(struct inode *inode, struct file *file) | |||
702 | * | 722 | * |
703 | * This helper insert netlabel in the smack_netlbladdrs list | 723 | * This helper insert netlabel in the smack_netlbladdrs list |
704 | * sorted by netmask length (longest to smallest) | 724 | * sorted by netmask length (longest to smallest) |
725 | * locked by &smk_netlbladdr_lock in smk_write_netlbladdr | ||
726 | * | ||
705 | */ | 727 | */ |
706 | static void smk_netlbladdr_insert(struct smk_netlbladdr *new) | 728 | static void smk_netlbladdr_insert(struct smk_netlbladdr *new) |
707 | { | 729 | { |
708 | struct smk_netlbladdr *m; | 730 | struct smk_netlbladdr *m, *m_next; |
709 | 731 | ||
710 | if (smack_netlbladdrs == NULL) { | 732 | if (list_empty(&smk_netlbladdr_list)) { |
711 | smack_netlbladdrs = new; | 733 | list_add_rcu(&new->list, &smk_netlbladdr_list); |
712 | return; | 734 | return; |
713 | } | 735 | } |
714 | 736 | ||
737 | m = list_entry(rcu_dereference(smk_netlbladdr_list.next), | ||
738 | struct smk_netlbladdr, list); | ||
739 | |||
715 | /* the comparison '>' is a bit hacky, but works */ | 740 | /* the comparison '>' is a bit hacky, but works */ |
716 | if (new->smk_mask.s_addr > smack_netlbladdrs->smk_mask.s_addr) { | 741 | if (new->smk_mask.s_addr > m->smk_mask.s_addr) { |
717 | new->smk_next = smack_netlbladdrs; | 742 | list_add_rcu(&new->list, &smk_netlbladdr_list); |
718 | smack_netlbladdrs = new; | ||
719 | return; | 743 | return; |
720 | } | 744 | } |
721 | for (m = smack_netlbladdrs; m != NULL; m = m->smk_next) { | 745 | |
722 | if (m->smk_next == NULL) { | 746 | list_for_each_entry_rcu(m, &smk_netlbladdr_list, list) { |
723 | m->smk_next = new; | 747 | if (list_is_last(&m->list, &smk_netlbladdr_list)) { |
748 | list_add_rcu(&new->list, &m->list); | ||
724 | return; | 749 | return; |
725 | } | 750 | } |
726 | if (new->smk_mask.s_addr > m->smk_next->smk_mask.s_addr) { | 751 | m_next = list_entry(rcu_dereference(m->list.next), |
727 | new->smk_next = m->smk_next; | 752 | struct smk_netlbladdr, list); |
728 | m->smk_next = new; | 753 | if (new->smk_mask.s_addr > m_next->smk_mask.s_addr) { |
754 | list_add_rcu(&new->list, &m->list); | ||
729 | return; | 755 | return; |
730 | } | 756 | } |
731 | } | 757 | } |
@@ -755,6 +781,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
755 | struct netlbl_audit audit_info; | 781 | struct netlbl_audit audit_info; |
756 | struct in_addr mask; | 782 | struct in_addr mask; |
757 | unsigned int m; | 783 | unsigned int m; |
784 | int found; | ||
758 | u32 mask_bits = (1<<31); | 785 | u32 mask_bits = (1<<31); |
759 | __be32 nsa; | 786 | __be32 nsa; |
760 | u32 temp_mask; | 787 | u32 temp_mask; |
@@ -789,9 +816,18 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
789 | if (m > BEBITS) | 816 | if (m > BEBITS) |
790 | return -EINVAL; | 817 | return -EINVAL; |
791 | 818 | ||
792 | sp = smk_import(smack, 0); | 819 | /* if smack begins with '-', its an option, don't import it */ |
793 | if (sp == NULL) | 820 | if (smack[0] != '-') { |
794 | return -EINVAL; | 821 | sp = smk_import(smack, 0); |
822 | if (sp == NULL) | ||
823 | return -EINVAL; | ||
824 | } else { | ||
825 | /* check known options */ | ||
826 | if (strcmp(smack, smack_cipso_option) == 0) | ||
827 | sp = (char *)smack_cipso_option; | ||
828 | else | ||
829 | return -EINVAL; | ||
830 | } | ||
795 | 831 | ||
796 | for (temp_mask = 0; m > 0; m--) { | 832 | for (temp_mask = 0; m > 0; m--) { |
797 | temp_mask |= mask_bits; | 833 | temp_mask |= mask_bits; |
@@ -808,14 +844,17 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
808 | 844 | ||
809 | nsa = newname.sin_addr.s_addr; | 845 | nsa = newname.sin_addr.s_addr; |
810 | /* try to find if the prefix is already in the list */ | 846 | /* try to find if the prefix is already in the list */ |
811 | for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next) | 847 | found = 0; |
848 | list_for_each_entry_rcu(skp, &smk_netlbladdr_list, list) { | ||
812 | if (skp->smk_host.sin_addr.s_addr == nsa && | 849 | if (skp->smk_host.sin_addr.s_addr == nsa && |
813 | skp->smk_mask.s_addr == mask.s_addr) | 850 | skp->smk_mask.s_addr == mask.s_addr) { |
851 | found = 1; | ||
814 | break; | 852 | break; |
815 | 853 | } | |
854 | } | ||
816 | smk_netlabel_audit_set(&audit_info); | 855 | smk_netlabel_audit_set(&audit_info); |
817 | 856 | ||
818 | if (skp == NULL) { | 857 | if (found == 0) { |
819 | skp = kzalloc(sizeof(*skp), GFP_KERNEL); | 858 | skp = kzalloc(sizeof(*skp), GFP_KERNEL); |
820 | if (skp == NULL) | 859 | if (skp == NULL) |
821 | rc = -ENOMEM; | 860 | rc = -ENOMEM; |
@@ -827,18 +866,23 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
827 | smk_netlbladdr_insert(skp); | 866 | smk_netlbladdr_insert(skp); |
828 | } | 867 | } |
829 | } else { | 868 | } else { |
830 | rc = netlbl_cfg_unlbl_static_del(&init_net, NULL, | 869 | /* we delete the unlabeled entry, only if the previous label |
831 | &skp->smk_host.sin_addr, &skp->smk_mask, | 870 | * wasnt the special CIPSO option */ |
832 | PF_INET, &audit_info); | 871 | if (skp->smk_label != smack_cipso_option) |
872 | rc = netlbl_cfg_unlbl_static_del(&init_net, NULL, | ||
873 | &skp->smk_host.sin_addr, &skp->smk_mask, | ||
874 | PF_INET, &audit_info); | ||
875 | else | ||
876 | rc = 0; | ||
833 | skp->smk_label = sp; | 877 | skp->smk_label = sp; |
834 | } | 878 | } |
835 | 879 | ||
836 | /* | 880 | /* |
837 | * Now tell netlabel about the single label nature of | 881 | * Now tell netlabel about the single label nature of |
838 | * this host so that incoming packets get labeled. | 882 | * this host so that incoming packets get labeled. |
883 | * but only if we didn't get the special CIPSO option | ||
839 | */ | 884 | */ |
840 | 885 | if (rc == 0 && sp != smack_cipso_option) | |
841 | if (rc == 0) | ||
842 | rc = netlbl_cfg_unlbl_static_add(&init_net, NULL, | 886 | rc = netlbl_cfg_unlbl_static_add(&init_net, NULL, |
843 | &skp->smk_host.sin_addr, &skp->smk_mask, PF_INET, | 887 | &skp->smk_host.sin_addr, &skp->smk_mask, PF_INET, |
844 | smack_to_secid(skp->smk_label), &audit_info); | 888 | smack_to_secid(skp->smk_label), &audit_info); |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 6dcb7cc0ed1d..26a76d67aa1c 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -55,7 +55,7 @@ struct tomoyo_path_info { | |||
55 | struct tomoyo_path_info_with_data { | 55 | struct tomoyo_path_info_with_data { |
56 | /* Keep "head" first, for this pointer is passed to tomoyo_free(). */ | 56 | /* Keep "head" first, for this pointer is passed to tomoyo_free(). */ |
57 | struct tomoyo_path_info head; | 57 | struct tomoyo_path_info head; |
58 | char bariier1[16]; /* Safeguard for overrun. */ | 58 | char barrier1[16]; /* Safeguard for overrun. */ |
59 | char body[TOMOYO_MAX_PATHNAME_LEN]; | 59 | char body[TOMOYO_MAX_PATHNAME_LEN]; |
60 | char barrier2[16]; /* Safeguard for overrun. */ | 60 | char barrier2[16]; /* Safeguard for overrun. */ |
61 | }; | 61 | }; |