diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-03-28 20:30:42 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-03-28 20:30:42 -0400 |
| commit | 7541bba880fb6989f489f0c68fa246a375b44035 (patch) | |
| tree | 19ce55af8e8732aa61cb8db529cf2304d9d738b5 | |
| parent | 795e2fe0a3b69dbc040d7efcf517e0cbad6901d0 (diff) | |
| parent | 4303154e86597885bc3cbc178a48ccbc8213875f (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6:
smack: Add a new '-CIPSO' option to the network address label configuration
netlabel: Cleanup the Smack/NetLabel code to fix incoming TCP connections
lsm: Remove the socket_post_accept() hook
selinux: Remove the "compat_net" compatibility code
netlabel: Label incoming TCP connections correctly in SELinux
lsm: Relocate the IPv4 security_inet_conn_request() hooks
TOMOYO: Fix a typo.
smack: convert smack to standard linux lists
| -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 | }; |
