diff options
-rw-r--r-- | include/linux/security.h | 55 | ||||
-rw-r--r-- | include/net/request_sock.h | 1 | ||||
-rw-r--r-- | include/net/sock.h | 1 | ||||
-rw-r--r-- | net/dccp/ipv4.c | 3 | ||||
-rw-r--r-- | net/dccp/ipv6.c | 7 | ||||
-rw-r--r-- | net/ipv4/inet_connection_sock.c | 4 | ||||
-rw-r--r-- | net/ipv4/syncookies.c | 6 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 3 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 6 | ||||
-rw-r--r-- | security/dummy.c | 24 | ||||
-rw-r--r-- | security/selinux/hooks.c | 137 | ||||
-rw-r--r-- | security/selinux/xfrm.c | 1 |
12 files changed, 197 insertions, 51 deletions
diff --git a/include/linux/security.h b/include/linux/security.h index 8e3dc6c51a6d..bb4c80fdfe7a 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -90,6 +90,7 @@ extern int cap_netlink_recv(struct sk_buff *skb, int cap); | |||
90 | struct nfsctl_arg; | 90 | struct nfsctl_arg; |
91 | struct sched_param; | 91 | struct sched_param; |
92 | struct swap_info_struct; | 92 | struct swap_info_struct; |
93 | struct request_sock; | ||
93 | 94 | ||
94 | /* bprm_apply_creds unsafe reasons */ | 95 | /* bprm_apply_creds unsafe reasons */ |
95 | #define LSM_UNSAFE_SHARE 1 | 96 | #define LSM_UNSAFE_SHARE 1 |
@@ -819,6 +820,14 @@ struct swap_info_struct; | |||
819 | * @sk_getsecid: | 820 | * @sk_getsecid: |
820 | * Retrieve the LSM-specific secid for the sock to enable caching of network | 821 | * Retrieve the LSM-specific secid for the sock to enable caching of network |
821 | * authorizations. | 822 | * authorizations. |
823 | * @sock_graft: | ||
824 | * Sets the socket's isec sid to the sock's sid. | ||
825 | * @inet_conn_request: | ||
826 | * Sets the openreq's sid to socket's sid with MLS portion taken from peer sid. | ||
827 | * @inet_csk_clone: | ||
828 | * Sets the new child socket's sid to the openreq sid. | ||
829 | * @req_classify_flow: | ||
830 | * Sets the flow's sid to the openreq sid. | ||
822 | * | 831 | * |
823 | * Security hooks for XFRM operations. | 832 | * Security hooks for XFRM operations. |
824 | * | 833 | * |
@@ -1358,6 +1367,11 @@ struct security_operations { | |||
1358 | void (*sk_free_security) (struct sock *sk); | 1367 | void (*sk_free_security) (struct sock *sk); |
1359 | void (*sk_clone_security) (const struct sock *sk, struct sock *newsk); | 1368 | void (*sk_clone_security) (const struct sock *sk, struct sock *newsk); |
1360 | void (*sk_getsecid) (struct sock *sk, u32 *secid); | 1369 | void (*sk_getsecid) (struct sock *sk, u32 *secid); |
1370 | void (*sock_graft)(struct sock* sk, struct socket *parent); | ||
1371 | int (*inet_conn_request)(struct sock *sk, struct sk_buff *skb, | ||
1372 | struct request_sock *req); | ||
1373 | void (*inet_csk_clone)(struct sock *newsk, const struct request_sock *req); | ||
1374 | void (*req_classify_flow)(const struct request_sock *req, struct flowi *fl); | ||
1361 | #endif /* CONFIG_SECURITY_NETWORK */ | 1375 | #endif /* CONFIG_SECURITY_NETWORK */ |
1362 | 1376 | ||
1363 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 1377 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
@@ -2926,6 +2940,28 @@ static inline void security_sk_classify_flow(struct sock *sk, struct flowi *fl) | |||
2926 | { | 2940 | { |
2927 | security_ops->sk_getsecid(sk, &fl->secid); | 2941 | security_ops->sk_getsecid(sk, &fl->secid); |
2928 | } | 2942 | } |
2943 | |||
2944 | static inline void security_req_classify_flow(const struct request_sock *req, struct flowi *fl) | ||
2945 | { | ||
2946 | security_ops->req_classify_flow(req, fl); | ||
2947 | } | ||
2948 | |||
2949 | static inline void security_sock_graft(struct sock* sk, struct socket *parent) | ||
2950 | { | ||
2951 | security_ops->sock_graft(sk, parent); | ||
2952 | } | ||
2953 | |||
2954 | static inline int security_inet_conn_request(struct sock *sk, | ||
2955 | struct sk_buff *skb, struct request_sock *req) | ||
2956 | { | ||
2957 | return security_ops->inet_conn_request(sk, skb, req); | ||
2958 | } | ||
2959 | |||
2960 | static inline void security_inet_csk_clone(struct sock *newsk, | ||
2961 | const struct request_sock *req) | ||
2962 | { | ||
2963 | security_ops->inet_csk_clone(newsk, req); | ||
2964 | } | ||
2929 | #else /* CONFIG_SECURITY_NETWORK */ | 2965 | #else /* CONFIG_SECURITY_NETWORK */ |
2930 | static inline int security_unix_stream_connect(struct socket * sock, | 2966 | static inline int security_unix_stream_connect(struct socket * sock, |
2931 | struct socket * other, | 2967 | struct socket * other, |
@@ -3055,6 +3091,25 @@ static inline void security_sk_clone(const struct sock *sk, struct sock *newsk) | |||
3055 | static inline void security_sk_classify_flow(struct sock *sk, struct flowi *fl) | 3091 | static inline void security_sk_classify_flow(struct sock *sk, struct flowi *fl) |
3056 | { | 3092 | { |
3057 | } | 3093 | } |
3094 | |||
3095 | static inline void security_req_classify_flow(const struct request_sock *req, struct flowi *fl) | ||
3096 | { | ||
3097 | } | ||
3098 | |||
3099 | static inline void security_sock_graft(struct sock* sk, struct socket *parent) | ||
3100 | { | ||
3101 | } | ||
3102 | |||
3103 | static inline int security_inet_conn_request(struct sock *sk, | ||
3104 | struct sk_buff *skb, struct request_sock *req) | ||
3105 | { | ||
3106 | return 0; | ||
3107 | } | ||
3108 | |||
3109 | static inline void security_inet_csk_clone(struct sock *newsk, | ||
3110 | const struct request_sock *req) | ||
3111 | { | ||
3112 | } | ||
3058 | #endif /* CONFIG_SECURITY_NETWORK */ | 3113 | #endif /* CONFIG_SECURITY_NETWORK */ |
3059 | 3114 | ||
3060 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 3115 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
diff --git a/include/net/request_sock.h b/include/net/request_sock.h index c5d7f920c352..8e165ca16bd8 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h | |||
@@ -53,6 +53,7 @@ struct request_sock { | |||
53 | unsigned long expires; | 53 | unsigned long expires; |
54 | struct request_sock_ops *rsk_ops; | 54 | struct request_sock_ops *rsk_ops; |
55 | struct sock *sk; | 55 | struct sock *sk; |
56 | u32 secid; | ||
56 | }; | 57 | }; |
57 | 58 | ||
58 | static inline struct request_sock *reqsk_alloc(struct request_sock_ops *ops) | 59 | static inline struct request_sock *reqsk_alloc(struct request_sock_ops *ops) |
diff --git a/include/net/sock.h b/include/net/sock.h index 91cdceb3c028..337ebec84c70 100644 --- a/include/net/sock.h +++ b/include/net/sock.h | |||
@@ -969,6 +969,7 @@ static inline void sock_graft(struct sock *sk, struct socket *parent) | |||
969 | sk->sk_sleep = &parent->wait; | 969 | sk->sk_sleep = &parent->wait; |
970 | parent->sk = sk; | 970 | parent->sk = sk; |
971 | sk->sk_socket = parent; | 971 | sk->sk_socket = parent; |
972 | security_sock_graft(sk, parent); | ||
972 | write_unlock_bh(&sk->sk_callback_lock); | 973 | write_unlock_bh(&sk->sk_callback_lock); |
973 | } | 974 | } |
974 | 975 | ||
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 386498053b1c..171d363876ee 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -501,6 +501,9 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
501 | 501 | ||
502 | dccp_openreq_init(req, &dp, skb); | 502 | dccp_openreq_init(req, &dp, skb); |
503 | 503 | ||
504 | if (security_inet_conn_request(sk, skb, req)) | ||
505 | goto drop_and_free; | ||
506 | |||
504 | ireq = inet_rsk(req); | 507 | ireq = inet_rsk(req); |
505 | ireq->loc_addr = daddr; | 508 | ireq->loc_addr = daddr; |
506 | ireq->rmt_addr = saddr; | 509 | ireq->rmt_addr = saddr; |
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 53d255c01431..231bc7c7e749 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c | |||
@@ -424,7 +424,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, | |||
424 | fl.oif = ireq6->iif; | 424 | fl.oif = ireq6->iif; |
425 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | 425 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; |
426 | fl.fl_ip_sport = inet_sk(sk)->sport; | 426 | fl.fl_ip_sport = inet_sk(sk)->sport; |
427 | security_sk_classify_flow(sk, &fl); | 427 | security_req_classify_flow(req, &fl); |
428 | 428 | ||
429 | if (dst == NULL) { | 429 | if (dst == NULL) { |
430 | opt = np->opt; | 430 | opt = np->opt; |
@@ -626,7 +626,7 @@ static void dccp_v6_reqsk_send_ack(struct sk_buff *rxskb, | |||
626 | fl.oif = inet6_iif(rxskb); | 626 | fl.oif = inet6_iif(rxskb); |
627 | fl.fl_ip_dport = dh->dccph_dport; | 627 | fl.fl_ip_dport = dh->dccph_dport; |
628 | fl.fl_ip_sport = dh->dccph_sport; | 628 | fl.fl_ip_sport = dh->dccph_sport; |
629 | security_skb_classify_flow(rxskb, &fl); | 629 | security_req_classify_flow(req, &fl); |
630 | 630 | ||
631 | if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) { | 631 | if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) { |
632 | if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) { | 632 | if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) { |
@@ -709,6 +709,9 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
709 | 709 | ||
710 | dccp_openreq_init(req, &dp, skb); | 710 | dccp_openreq_init(req, &dp, skb); |
711 | 711 | ||
712 | if (security_inet_conn_request(sk, skb, req)) | ||
713 | goto drop_and_free; | ||
714 | |||
712 | ireq6 = inet6_rsk(req); | 715 | ireq6 = inet6_rsk(req); |
713 | ireq = inet_rsk(req); | 716 | ireq = inet_rsk(req); |
714 | ipv6_addr_copy(&ireq6->rmt_addr, &skb->nh.ipv6h->saddr); | 717 | ipv6_addr_copy(&ireq6->rmt_addr, &skb->nh.ipv6h->saddr); |
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 772b4eac78bc..07204391d083 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c | |||
@@ -327,7 +327,7 @@ struct dst_entry* inet_csk_route_req(struct sock *sk, | |||
327 | { .sport = inet_sk(sk)->sport, | 327 | { .sport = inet_sk(sk)->sport, |
328 | .dport = ireq->rmt_port } } }; | 328 | .dport = ireq->rmt_port } } }; |
329 | 329 | ||
330 | security_sk_classify_flow(sk, &fl); | 330 | security_req_classify_flow(req, &fl); |
331 | if (ip_route_output_flow(&rt, &fl, sk, 0)) { | 331 | if (ip_route_output_flow(&rt, &fl, sk, 0)) { |
332 | IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); | 332 | IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); |
333 | return NULL; | 333 | return NULL; |
@@ -510,6 +510,8 @@ struct sock *inet_csk_clone(struct sock *sk, const struct request_sock *req, | |||
510 | 510 | ||
511 | /* Deinitialize accept_queue to trap illegal accesses. */ | 511 | /* Deinitialize accept_queue to trap illegal accesses. */ |
512 | memset(&newicsk->icsk_accept_queue, 0, sizeof(newicsk->icsk_accept_queue)); | 512 | memset(&newicsk->icsk_accept_queue, 0, sizeof(newicsk->icsk_accept_queue)); |
513 | |||
514 | security_inet_csk_clone(newsk, req); | ||
513 | } | 515 | } |
514 | return newsk; | 516 | return newsk; |
515 | } | 517 | } |
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 307dc3c0d635..661e0a4bca72 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c | |||
@@ -214,6 +214,10 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | |||
214 | if (!req) | 214 | if (!req) |
215 | goto out; | 215 | goto out; |
216 | 216 | ||
217 | if (security_inet_conn_request(sk, skb, req)) { | ||
218 | reqsk_free(req); | ||
219 | goto out; | ||
220 | } | ||
217 | ireq = inet_rsk(req); | 221 | ireq = inet_rsk(req); |
218 | treq = tcp_rsk(req); | 222 | treq = tcp_rsk(req); |
219 | treq->rcv_isn = htonl(skb->h.th->seq) - 1; | 223 | treq->rcv_isn = htonl(skb->h.th->seq) - 1; |
@@ -259,7 +263,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | |||
259 | .uli_u = { .ports = | 263 | .uli_u = { .ports = |
260 | { .sport = skb->h.th->dest, | 264 | { .sport = skb->h.th->dest, |
261 | .dport = skb->h.th->source } } }; | 265 | .dport = skb->h.th->source } } }; |
262 | security_sk_classify_flow(sk, &fl); | 266 | security_req_classify_flow(req, &fl); |
263 | if (ip_route_output_key(&rt, &fl)) { | 267 | if (ip_route_output_key(&rt, &fl)) { |
264 | reqsk_free(req); | 268 | reqsk_free(req); |
265 | goto out; | 269 | goto out; |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 4b04c3edd4a9..43f6740244f8 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -798,6 +798,9 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
798 | 798 | ||
799 | tcp_openreq_init(req, &tmp_opt, skb); | 799 | tcp_openreq_init(req, &tmp_opt, skb); |
800 | 800 | ||
801 | if (security_inet_conn_request(sk, skb, req)) | ||
802 | goto drop_and_free; | ||
803 | |||
801 | ireq = inet_rsk(req); | 804 | ireq = inet_rsk(req); |
802 | ireq->loc_addr = daddr; | 805 | ireq->loc_addr = daddr; |
803 | ireq->rmt_addr = saddr; | 806 | ireq->rmt_addr = saddr; |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 46922e57e311..302786a11cd6 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -470,7 +470,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, | |||
470 | fl.oif = treq->iif; | 470 | fl.oif = treq->iif; |
471 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | 471 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; |
472 | fl.fl_ip_sport = inet_sk(sk)->sport; | 472 | fl.fl_ip_sport = inet_sk(sk)->sport; |
473 | security_sk_classify_flow(sk, &fl); | 473 | security_req_classify_flow(req, &fl); |
474 | 474 | ||
475 | if (dst == NULL) { | 475 | if (dst == NULL) { |
476 | opt = np->opt; | 476 | opt = np->opt; |
@@ -826,6 +826,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
826 | 826 | ||
827 | tcp_rsk(req)->snt_isn = isn; | 827 | tcp_rsk(req)->snt_isn = isn; |
828 | 828 | ||
829 | security_inet_conn_request(sk, skb, req); | ||
830 | |||
829 | if (tcp_v6_send_synack(sk, req, NULL)) | 831 | if (tcp_v6_send_synack(sk, req, NULL)) |
830 | goto drop; | 832 | goto drop; |
831 | 833 | ||
@@ -929,7 +931,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
929 | fl.oif = sk->sk_bound_dev_if; | 931 | fl.oif = sk->sk_bound_dev_if; |
930 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | 932 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; |
931 | fl.fl_ip_sport = inet_sk(sk)->sport; | 933 | fl.fl_ip_sport = inet_sk(sk)->sport; |
932 | security_sk_classify_flow(sk, &fl); | 934 | security_req_classify_flow(req, &fl); |
933 | 935 | ||
934 | if (ip6_dst_lookup(sk, &dst, &fl)) | 936 | if (ip6_dst_lookup(sk, &dst, &fl)) |
935 | goto out; | 937 | goto out; |
diff --git a/security/dummy.c b/security/dummy.c index 66cc06404930..1c45f8e4aad1 100644 --- a/security/dummy.c +++ b/security/dummy.c | |||
@@ -812,6 +812,26 @@ static inline void dummy_sk_clone_security (const struct sock *sk, struct sock * | |||
812 | static inline void dummy_sk_getsecid(struct sock *sk, u32 *secid) | 812 | static inline void dummy_sk_getsecid(struct sock *sk, u32 *secid) |
813 | { | 813 | { |
814 | } | 814 | } |
815 | |||
816 | static inline void dummy_sock_graft(struct sock* sk, struct socket *parent) | ||
817 | { | ||
818 | } | ||
819 | |||
820 | static inline int dummy_inet_conn_request(struct sock *sk, | ||
821 | struct sk_buff *skb, struct request_sock *req) | ||
822 | { | ||
823 | return 0; | ||
824 | } | ||
825 | |||
826 | static inline void dummy_inet_csk_clone(struct sock *newsk, | ||
827 | const struct request_sock *req) | ||
828 | { | ||
829 | } | ||
830 | |||
831 | static inline void dummy_req_classify_flow(const struct request_sock *req, | ||
832 | struct flowi *fl) | ||
833 | { | ||
834 | } | ||
815 | #endif /* CONFIG_SECURITY_NETWORK */ | 835 | #endif /* CONFIG_SECURITY_NETWORK */ |
816 | 836 | ||
817 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 837 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
@@ -1084,6 +1104,10 @@ void security_fixup_ops (struct security_operations *ops) | |||
1084 | set_to_dummy_if_null(ops, sk_free_security); | 1104 | set_to_dummy_if_null(ops, sk_free_security); |
1085 | set_to_dummy_if_null(ops, sk_clone_security); | 1105 | set_to_dummy_if_null(ops, sk_clone_security); |
1086 | set_to_dummy_if_null(ops, sk_getsecid); | 1106 | set_to_dummy_if_null(ops, sk_getsecid); |
1107 | set_to_dummy_if_null(ops, sock_graft); | ||
1108 | set_to_dummy_if_null(ops, inet_conn_request); | ||
1109 | set_to_dummy_if_null(ops, inet_csk_clone); | ||
1110 | set_to_dummy_if_null(ops, req_classify_flow); | ||
1087 | #endif /* CONFIG_SECURITY_NETWORK */ | 1111 | #endif /* CONFIG_SECURITY_NETWORK */ |
1088 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 1112 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
1089 | set_to_dummy_if_null(ops, xfrm_policy_alloc_security); | 1113 | set_to_dummy_if_null(ops, xfrm_policy_alloc_security); |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4e5989d584ce..1dc935f7b919 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -3328,8 +3328,9 @@ static int selinux_socket_unix_stream_connect(struct socket *sock, | |||
3328 | /* server child socket */ | 3328 | /* server child socket */ |
3329 | ssec = newsk->sk_security; | 3329 | ssec = newsk->sk_security; |
3330 | ssec->peer_sid = isec->sid; | 3330 | ssec->peer_sid = isec->sid; |
3331 | 3331 | err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid); | |
3332 | return 0; | 3332 | |
3333 | return err; | ||
3333 | } | 3334 | } |
3334 | 3335 | ||
3335 | static int selinux_socket_unix_may_send(struct socket *sock, | 3336 | static int selinux_socket_unix_may_send(struct socket *sock, |
@@ -3355,11 +3356,29 @@ static int selinux_socket_unix_may_send(struct socket *sock, | |||
3355 | } | 3356 | } |
3356 | 3357 | ||
3357 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | 3358 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, |
3358 | struct avc_audit_data *ad, u32 sock_sid, u16 sock_class, | 3359 | struct avc_audit_data *ad, u16 family, char *addrp, int len) |
3359 | u16 family, char *addrp, int len) | ||
3360 | { | 3360 | { |
3361 | int err = 0; | 3361 | int err = 0; |
3362 | u32 netif_perm, node_perm, node_sid, if_sid, recv_perm = 0; | 3362 | u32 netif_perm, node_perm, node_sid, if_sid, recv_perm = 0; |
3363 | struct socket *sock; | ||
3364 | u16 sock_class = 0; | ||
3365 | u32 sock_sid = 0; | ||
3366 | |||
3367 | read_lock_bh(&sk->sk_callback_lock); | ||
3368 | sock = sk->sk_socket; | ||
3369 | if (sock) { | ||
3370 | struct inode *inode; | ||
3371 | inode = SOCK_INODE(sock); | ||
3372 | if (inode) { | ||
3373 | struct inode_security_struct *isec; | ||
3374 | isec = inode->i_security; | ||
3375 | sock_sid = isec->sid; | ||
3376 | sock_class = isec->sclass; | ||
3377 | } | ||
3378 | } | ||
3379 | read_unlock_bh(&sk->sk_callback_lock); | ||
3380 | if (!sock_sid) | ||
3381 | goto out; | ||
3363 | 3382 | ||
3364 | if (!skb->dev) | 3383 | if (!skb->dev) |
3365 | goto out; | 3384 | goto out; |
@@ -3419,12 +3438,10 @@ out: | |||
3419 | static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | 3438 | static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) |
3420 | { | 3439 | { |
3421 | u16 family; | 3440 | u16 family; |
3422 | u16 sock_class = 0; | ||
3423 | char *addrp; | 3441 | char *addrp; |
3424 | int len, err = 0; | 3442 | int len, err = 0; |
3425 | u32 sock_sid = 0; | ||
3426 | struct socket *sock; | ||
3427 | struct avc_audit_data ad; | 3443 | struct avc_audit_data ad; |
3444 | struct sk_security_struct *sksec = sk->sk_security; | ||
3428 | 3445 | ||
3429 | family = sk->sk_family; | 3446 | family = sk->sk_family; |
3430 | if (family != PF_INET && family != PF_INET6) | 3447 | if (family != PF_INET && family != PF_INET6) |
@@ -3434,22 +3451,6 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
3434 | if (family == PF_INET6 && skb->protocol == ntohs(ETH_P_IP)) | 3451 | if (family == PF_INET6 && skb->protocol == ntohs(ETH_P_IP)) |
3435 | family = PF_INET; | 3452 | family = PF_INET; |
3436 | 3453 | ||
3437 | read_lock_bh(&sk->sk_callback_lock); | ||
3438 | sock = sk->sk_socket; | ||
3439 | if (sock) { | ||
3440 | struct inode *inode; | ||
3441 | inode = SOCK_INODE(sock); | ||
3442 | if (inode) { | ||
3443 | struct inode_security_struct *isec; | ||
3444 | isec = inode->i_security; | ||
3445 | sock_sid = isec->sid; | ||
3446 | sock_class = isec->sclass; | ||
3447 | } | ||
3448 | } | ||
3449 | read_unlock_bh(&sk->sk_callback_lock); | ||
3450 | if (!sock_sid) | ||
3451 | goto out; | ||
3452 | |||
3453 | AVC_AUDIT_DATA_INIT(&ad, NET); | 3454 | AVC_AUDIT_DATA_INIT(&ad, NET); |
3454 | ad.u.net.netif = skb->dev ? skb->dev->name : "[unknown]"; | 3455 | ad.u.net.netif = skb->dev ? skb->dev->name : "[unknown]"; |
3455 | ad.u.net.family = family; | 3456 | ad.u.net.family = family; |
@@ -3459,16 +3460,15 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
3459 | goto out; | 3460 | goto out; |
3460 | 3461 | ||
3461 | if (selinux_compat_net) | 3462 | if (selinux_compat_net) |
3462 | err = selinux_sock_rcv_skb_compat(sk, skb, &ad, sock_sid, | 3463 | err = selinux_sock_rcv_skb_compat(sk, skb, &ad, family, |
3463 | sock_class, family, | ||
3464 | addrp, len); | 3464 | addrp, len); |
3465 | else | 3465 | else |
3466 | err = avc_has_perm(sock_sid, skb->secmark, SECCLASS_PACKET, | 3466 | err = avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET, |
3467 | PACKET__RECV, &ad); | 3467 | PACKET__RECV, &ad); |
3468 | if (err) | 3468 | if (err) |
3469 | goto out; | 3469 | goto out; |
3470 | 3470 | ||
3471 | err = selinux_xfrm_sock_rcv_skb(sock_sid, skb, &ad); | 3471 | err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad); |
3472 | out: | 3472 | out: |
3473 | return err; | 3473 | return err; |
3474 | } | 3474 | } |
@@ -3572,6 +3572,49 @@ static void selinux_sk_getsecid(struct sock *sk, u32 *secid) | |||
3572 | } | 3572 | } |
3573 | } | 3573 | } |
3574 | 3574 | ||
3575 | void selinux_sock_graft(struct sock* sk, struct socket *parent) | ||
3576 | { | ||
3577 | struct inode_security_struct *isec = SOCK_INODE(parent)->i_security; | ||
3578 | struct sk_security_struct *sksec = sk->sk_security; | ||
3579 | |||
3580 | isec->sid = sksec->sid; | ||
3581 | } | ||
3582 | |||
3583 | int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | ||
3584 | struct request_sock *req) | ||
3585 | { | ||
3586 | struct sk_security_struct *sksec = sk->sk_security; | ||
3587 | int err; | ||
3588 | u32 newsid = 0; | ||
3589 | u32 peersid; | ||
3590 | |||
3591 | err = selinux_xfrm_decode_session(skb, &peersid, 0); | ||
3592 | BUG_ON(err); | ||
3593 | |||
3594 | err = security_sid_mls_copy(sksec->sid, peersid, &newsid); | ||
3595 | if (err) | ||
3596 | return err; | ||
3597 | |||
3598 | req->secid = newsid; | ||
3599 | return 0; | ||
3600 | } | ||
3601 | |||
3602 | void selinux_inet_csk_clone(struct sock *newsk, const struct request_sock *req) | ||
3603 | { | ||
3604 | struct sk_security_struct *newsksec = newsk->sk_security; | ||
3605 | |||
3606 | newsksec->sid = req->secid; | ||
3607 | /* NOTE: Ideally, we should also get the isec->sid for the | ||
3608 | new socket in sync, but we don't have the isec available yet. | ||
3609 | So we will wait until sock_graft to do it, by which | ||
3610 | time it will have been created and available. */ | ||
3611 | } | ||
3612 | |||
3613 | void selinux_req_classify_flow(const struct request_sock *req, struct flowi *fl) | ||
3614 | { | ||
3615 | fl->secid = req->secid; | ||
3616 | } | ||
3617 | |||
3575 | static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) | 3618 | static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) |
3576 | { | 3619 | { |
3577 | int err = 0; | 3620 | int err = 0; |
@@ -3611,12 +3654,24 @@ out: | |||
3611 | #ifdef CONFIG_NETFILTER | 3654 | #ifdef CONFIG_NETFILTER |
3612 | 3655 | ||
3613 | static int selinux_ip_postroute_last_compat(struct sock *sk, struct net_device *dev, | 3656 | static int selinux_ip_postroute_last_compat(struct sock *sk, struct net_device *dev, |
3614 | struct inode_security_struct *isec, | ||
3615 | struct avc_audit_data *ad, | 3657 | struct avc_audit_data *ad, |
3616 | u16 family, char *addrp, int len) | 3658 | u16 family, char *addrp, int len) |
3617 | { | 3659 | { |
3618 | int err; | 3660 | int err = 0; |
3619 | u32 netif_perm, node_perm, node_sid, if_sid, send_perm = 0; | 3661 | u32 netif_perm, node_perm, node_sid, if_sid, send_perm = 0; |
3662 | struct socket *sock; | ||
3663 | struct inode *inode; | ||
3664 | struct inode_security_struct *isec; | ||
3665 | |||
3666 | sock = sk->sk_socket; | ||
3667 | if (!sock) | ||
3668 | goto out; | ||
3669 | |||
3670 | inode = SOCK_INODE(sock); | ||
3671 | if (!inode) | ||
3672 | goto out; | ||
3673 | |||
3674 | isec = inode->i_security; | ||
3620 | 3675 | ||
3621 | err = sel_netif_sids(dev, &if_sid, NULL); | 3676 | err = sel_netif_sids(dev, &if_sid, NULL); |
3622 | if (err) | 3677 | if (err) |
@@ -3681,26 +3736,16 @@ static unsigned int selinux_ip_postroute_last(unsigned int hooknum, | |||
3681 | char *addrp; | 3736 | char *addrp; |
3682 | int len, err = 0; | 3737 | int len, err = 0; |
3683 | struct sock *sk; | 3738 | struct sock *sk; |
3684 | struct socket *sock; | ||
3685 | struct inode *inode; | ||
3686 | struct sk_buff *skb = *pskb; | 3739 | struct sk_buff *skb = *pskb; |
3687 | struct inode_security_struct *isec; | ||
3688 | struct avc_audit_data ad; | 3740 | struct avc_audit_data ad; |
3689 | struct net_device *dev = (struct net_device *)out; | 3741 | struct net_device *dev = (struct net_device *)out; |
3742 | struct sk_security_struct *sksec; | ||
3690 | 3743 | ||
3691 | sk = skb->sk; | 3744 | sk = skb->sk; |
3692 | if (!sk) | 3745 | if (!sk) |
3693 | goto out; | 3746 | goto out; |
3694 | 3747 | ||
3695 | sock = sk->sk_socket; | 3748 | sksec = sk->sk_security; |
3696 | if (!sock) | ||
3697 | goto out; | ||
3698 | |||
3699 | inode = SOCK_INODE(sock); | ||
3700 | if (!inode) | ||
3701 | goto out; | ||
3702 | |||
3703 | isec = inode->i_security; | ||
3704 | 3749 | ||
3705 | AVC_AUDIT_DATA_INIT(&ad, NET); | 3750 | AVC_AUDIT_DATA_INIT(&ad, NET); |
3706 | ad.u.net.netif = dev->name; | 3751 | ad.u.net.netif = dev->name; |
@@ -3711,16 +3756,16 @@ static unsigned int selinux_ip_postroute_last(unsigned int hooknum, | |||
3711 | goto out; | 3756 | goto out; |
3712 | 3757 | ||
3713 | if (selinux_compat_net) | 3758 | if (selinux_compat_net) |
3714 | err = selinux_ip_postroute_last_compat(sk, dev, isec, &ad, | 3759 | err = selinux_ip_postroute_last_compat(sk, dev, &ad, |
3715 | family, addrp, len); | 3760 | family, addrp, len); |
3716 | else | 3761 | else |
3717 | err = avc_has_perm(isec->sid, skb->secmark, SECCLASS_PACKET, | 3762 | err = avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET, |
3718 | PACKET__SEND, &ad); | 3763 | PACKET__SEND, &ad); |
3719 | 3764 | ||
3720 | if (err) | 3765 | if (err) |
3721 | goto out; | 3766 | goto out; |
3722 | 3767 | ||
3723 | err = selinux_xfrm_postroute_last(isec->sid, skb, &ad); | 3768 | err = selinux_xfrm_postroute_last(sksec->sid, skb, &ad); |
3724 | out: | 3769 | out: |
3725 | return err ? NF_DROP : NF_ACCEPT; | 3770 | return err ? NF_DROP : NF_ACCEPT; |
3726 | } | 3771 | } |
@@ -4623,6 +4668,10 @@ static struct security_operations selinux_ops = { | |||
4623 | .sk_free_security = selinux_sk_free_security, | 4668 | .sk_free_security = selinux_sk_free_security, |
4624 | .sk_clone_security = selinux_sk_clone_security, | 4669 | .sk_clone_security = selinux_sk_clone_security, |
4625 | .sk_getsecid = selinux_sk_getsecid, | 4670 | .sk_getsecid = selinux_sk_getsecid, |
4671 | .sock_graft = selinux_sock_graft, | ||
4672 | .inet_conn_request = selinux_inet_conn_request, | ||
4673 | .inet_csk_clone = selinux_inet_csk_clone, | ||
4674 | .req_classify_flow = selinux_req_classify_flow, | ||
4626 | 4675 | ||
4627 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 4676 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
4628 | .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc, | 4677 | .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc, |
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index d3690f985135..3e742b850af6 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c | |||
@@ -271,7 +271,6 @@ not_from_user: | |||
271 | goto out; | 271 | goto out; |
272 | } | 272 | } |
273 | 273 | ||
274 | |||
275 | ctx->ctx_doi = XFRM_SC_DOI_LSM; | 274 | ctx->ctx_doi = XFRM_SC_DOI_LSM; |
276 | ctx->ctx_alg = XFRM_SC_ALG_SELINUX; | 275 | ctx->ctx_alg = XFRM_SC_ALG_SELINUX; |
277 | ctx->ctx_sid = ctx_sid; | 276 | ctx->ctx_sid = ctx_sid; |