diff options
author | Venkat Yekkirala <vyekkirala@TrustedCS.com> | 2006-08-05 02:08:56 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-22 17:53:22 -0400 |
commit | 892c141e62982272b9c738b5520ad0e5e1ad7b42 (patch) | |
tree | c8e0c9b3e55106d2cb085a5047b9d02dbbb28653 | |
parent | 08554d6b33e60aa8ee40bbef94505941c0eefef2 (diff) |
[MLSXFRM]: Add security sid to sock
This adds security for IP sockets at the sock level. Security at the
sock level is needed to enforce the SELinux security policy for
security associations even when a sock is orphaned (such as in the TCP
LAST_ACK state).
This will also be used to enforce SELinux controls over data arriving
at or leaving a child socket while it's still waiting to be accepted.
Signed-off-by: Venkat Yekkirala <vyekkirala@TrustedCS.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/security.h | 12 | ||||
-rw-r--r-- | include/net/sock.h | 13 | ||||
-rw-r--r-- | net/core/sock.c | 2 | ||||
-rw-r--r-- | security/dummy.c | 5 | ||||
-rw-r--r-- | security/selinux/hooks.c | 38 | ||||
-rw-r--r-- | security/selinux/include/objsec.h | 1 |
6 files changed, 53 insertions, 18 deletions
diff --git a/include/linux/security.h b/include/linux/security.h index 6bc2aad494ff..4d7fb59996b0 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -812,6 +812,8 @@ struct swap_info_struct; | |||
812 | * which is used to copy security attributes between local stream sockets. | 812 | * which is used to copy security attributes between local stream sockets. |
813 | * @sk_free_security: | 813 | * @sk_free_security: |
814 | * Deallocate security structure. | 814 | * Deallocate security structure. |
815 | * @sk_clone_security: | ||
816 | * Clone/copy security structure. | ||
815 | * @sk_getsid: | 817 | * @sk_getsid: |
816 | * Retrieve the LSM-specific sid for the sock to enable caching of network | 818 | * Retrieve the LSM-specific sid for the sock to enable caching of network |
817 | * authorizations. | 819 | * authorizations. |
@@ -1332,6 +1334,7 @@ struct security_operations { | |||
1332 | int (*socket_getpeersec_dgram) (struct socket *sock, struct sk_buff *skb, u32 *secid); | 1334 | int (*socket_getpeersec_dgram) (struct socket *sock, struct sk_buff *skb, u32 *secid); |
1333 | int (*sk_alloc_security) (struct sock *sk, int family, gfp_t priority); | 1335 | int (*sk_alloc_security) (struct sock *sk, int family, gfp_t priority); |
1334 | void (*sk_free_security) (struct sock *sk); | 1336 | void (*sk_free_security) (struct sock *sk); |
1337 | void (*sk_clone_security) (const struct sock *sk, struct sock *newsk); | ||
1335 | unsigned int (*sk_getsid) (struct sock *sk, struct flowi *fl, u8 dir); | 1338 | unsigned int (*sk_getsid) (struct sock *sk, struct flowi *fl, u8 dir); |
1336 | #endif /* CONFIG_SECURITY_NETWORK */ | 1339 | #endif /* CONFIG_SECURITY_NETWORK */ |
1337 | 1340 | ||
@@ -2885,6 +2888,11 @@ static inline void security_sk_free(struct sock *sk) | |||
2885 | return security_ops->sk_free_security(sk); | 2888 | return security_ops->sk_free_security(sk); |
2886 | } | 2889 | } |
2887 | 2890 | ||
2891 | static inline void security_sk_clone(const struct sock *sk, struct sock *newsk) | ||
2892 | { | ||
2893 | return security_ops->sk_clone_security(sk, newsk); | ||
2894 | } | ||
2895 | |||
2888 | static inline unsigned int security_sk_sid(struct sock *sk, struct flowi *fl, u8 dir) | 2896 | static inline unsigned int security_sk_sid(struct sock *sk, struct flowi *fl, u8 dir) |
2889 | { | 2897 | { |
2890 | return security_ops->sk_getsid(sk, fl, dir); | 2898 | return security_ops->sk_getsid(sk, fl, dir); |
@@ -3011,6 +3019,10 @@ static inline void security_sk_free(struct sock *sk) | |||
3011 | { | 3019 | { |
3012 | } | 3020 | } |
3013 | 3021 | ||
3022 | static inline void security_sk_clone(const struct sock *sk, struct sock *newsk) | ||
3023 | { | ||
3024 | } | ||
3025 | |||
3014 | static inline unsigned int security_sk_sid(struct sock *sk, struct flowi *fl, u8 dir) | 3026 | static inline unsigned int security_sk_sid(struct sock *sk, struct flowi *fl, u8 dir) |
3015 | { | 3027 | { |
3016 | return 0; | 3028 | return 0; |
diff --git a/include/net/sock.h b/include/net/sock.h index 324b3ea233d6..91cdceb3c028 100644 --- a/include/net/sock.h +++ b/include/net/sock.h | |||
@@ -972,6 +972,19 @@ static inline void sock_graft(struct sock *sk, struct socket *parent) | |||
972 | write_unlock_bh(&sk->sk_callback_lock); | 972 | write_unlock_bh(&sk->sk_callback_lock); |
973 | } | 973 | } |
974 | 974 | ||
975 | static inline void sock_copy(struct sock *nsk, const struct sock *osk) | ||
976 | { | ||
977 | #ifdef CONFIG_SECURITY_NETWORK | ||
978 | void *sptr = nsk->sk_security; | ||
979 | #endif | ||
980 | |||
981 | memcpy(nsk, osk, osk->sk_prot->obj_size); | ||
982 | #ifdef CONFIG_SECURITY_NETWORK | ||
983 | nsk->sk_security = sptr; | ||
984 | security_sk_clone(osk, nsk); | ||
985 | #endif | ||
986 | } | ||
987 | |||
975 | extern int sock_i_uid(struct sock *sk); | 988 | extern int sock_i_uid(struct sock *sk); |
976 | extern unsigned long sock_i_ino(struct sock *sk); | 989 | extern unsigned long sock_i_ino(struct sock *sk); |
977 | 990 | ||
diff --git a/net/core/sock.c b/net/core/sock.c index 51fcfbc041a7..b67d868649cd 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
@@ -911,7 +911,7 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority) | |||
911 | if (newsk != NULL) { | 911 | if (newsk != NULL) { |
912 | struct sk_filter *filter; | 912 | struct sk_filter *filter; |
913 | 913 | ||
914 | memcpy(newsk, sk, sk->sk_prot->obj_size); | 914 | sock_copy(newsk, sk); |
915 | 915 | ||
916 | /* SANITY */ | 916 | /* SANITY */ |
917 | sk_node_init(&newsk->sk_node); | 917 | sk_node_init(&newsk->sk_node); |
diff --git a/security/dummy.c b/security/dummy.c index 58c6d399c844..bd3bc5faa9a8 100644 --- a/security/dummy.c +++ b/security/dummy.c | |||
@@ -805,6 +805,10 @@ static inline void dummy_sk_free_security (struct sock *sk) | |||
805 | { | 805 | { |
806 | } | 806 | } |
807 | 807 | ||
808 | static inline void dummy_sk_clone_security (const struct sock *sk, struct sock *newsk) | ||
809 | { | ||
810 | } | ||
811 | |||
808 | static unsigned int dummy_sk_getsid(struct sock *sk, struct flowi *fl, u8 dir) | 812 | static unsigned int dummy_sk_getsid(struct sock *sk, struct flowi *fl, u8 dir) |
809 | { | 813 | { |
810 | return 0; | 814 | return 0; |
@@ -1060,6 +1064,7 @@ void security_fixup_ops (struct security_operations *ops) | |||
1060 | set_to_dummy_if_null(ops, socket_getpeersec_dgram); | 1064 | set_to_dummy_if_null(ops, socket_getpeersec_dgram); |
1061 | set_to_dummy_if_null(ops, sk_alloc_security); | 1065 | set_to_dummy_if_null(ops, sk_alloc_security); |
1062 | set_to_dummy_if_null(ops, sk_free_security); | 1066 | set_to_dummy_if_null(ops, sk_free_security); |
1067 | set_to_dummy_if_null(ops, sk_clone_security); | ||
1063 | set_to_dummy_if_null(ops, sk_getsid); | 1068 | set_to_dummy_if_null(ops, sk_getsid); |
1064 | #endif /* CONFIG_SECURITY_NETWORK */ | 1069 | #endif /* CONFIG_SECURITY_NETWORK */ |
1065 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 1070 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 5d1b8c733199..d67abf77584a 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -269,15 +269,13 @@ static int sk_alloc_security(struct sock *sk, int family, gfp_t priority) | |||
269 | { | 269 | { |
270 | struct sk_security_struct *ssec; | 270 | struct sk_security_struct *ssec; |
271 | 271 | ||
272 | if (family != PF_UNIX) | ||
273 | return 0; | ||
274 | |||
275 | ssec = kzalloc(sizeof(*ssec), priority); | 272 | ssec = kzalloc(sizeof(*ssec), priority); |
276 | if (!ssec) | 273 | if (!ssec) |
277 | return -ENOMEM; | 274 | return -ENOMEM; |
278 | 275 | ||
279 | ssec->sk = sk; | 276 | ssec->sk = sk; |
280 | ssec->peer_sid = SECINITSID_UNLABELED; | 277 | ssec->peer_sid = SECINITSID_UNLABELED; |
278 | ssec->sid = SECINITSID_UNLABELED; | ||
281 | sk->sk_security = ssec; | 279 | sk->sk_security = ssec; |
282 | 280 | ||
283 | return 0; | 281 | return 0; |
@@ -287,9 +285,6 @@ static void sk_free_security(struct sock *sk) | |||
287 | { | 285 | { |
288 | struct sk_security_struct *ssec = sk->sk_security; | 286 | struct sk_security_struct *ssec = sk->sk_security; |
289 | 287 | ||
290 | if (sk->sk_family != PF_UNIX) | ||
291 | return; | ||
292 | |||
293 | sk->sk_security = NULL; | 288 | sk->sk_security = NULL; |
294 | kfree(ssec); | 289 | kfree(ssec); |
295 | } | 290 | } |
@@ -3068,6 +3063,7 @@ static void selinux_socket_post_create(struct socket *sock, int family, | |||
3068 | { | 3063 | { |
3069 | struct inode_security_struct *isec; | 3064 | struct inode_security_struct *isec; |
3070 | struct task_security_struct *tsec; | 3065 | struct task_security_struct *tsec; |
3066 | struct sk_security_struct *sksec; | ||
3071 | u32 newsid; | 3067 | u32 newsid; |
3072 | 3068 | ||
3073 | isec = SOCK_INODE(sock)->i_security; | 3069 | isec = SOCK_INODE(sock)->i_security; |
@@ -3078,6 +3074,11 @@ static void selinux_socket_post_create(struct socket *sock, int family, | |||
3078 | isec->sid = kern ? SECINITSID_KERNEL : newsid; | 3074 | isec->sid = kern ? SECINITSID_KERNEL : newsid; |
3079 | isec->initialized = 1; | 3075 | isec->initialized = 1; |
3080 | 3076 | ||
3077 | if (sock->sk) { | ||
3078 | sksec = sock->sk->sk_security; | ||
3079 | sksec->sid = isec->sid; | ||
3080 | } | ||
3081 | |||
3081 | return; | 3082 | return; |
3082 | } | 3083 | } |
3083 | 3084 | ||
@@ -3551,22 +3552,24 @@ static void selinux_sk_free_security(struct sock *sk) | |||
3551 | sk_free_security(sk); | 3552 | sk_free_security(sk); |
3552 | } | 3553 | } |
3553 | 3554 | ||
3554 | static unsigned int selinux_sk_getsid_security(struct sock *sk, struct flowi *fl, u8 dir) | 3555 | static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk) |
3555 | { | 3556 | { |
3556 | struct inode_security_struct *isec; | 3557 | struct sk_security_struct *ssec = sk->sk_security; |
3557 | u32 sock_sid = SECINITSID_ANY_SOCKET; | 3558 | struct sk_security_struct *newssec = newsk->sk_security; |
3558 | 3559 | ||
3560 | newssec->sid = ssec->sid; | ||
3561 | newssec->peer_sid = ssec->peer_sid; | ||
3562 | } | ||
3563 | |||
3564 | static unsigned int selinux_sk_getsid_security(struct sock *sk, struct flowi *fl, u8 dir) | ||
3565 | { | ||
3559 | if (!sk) | 3566 | if (!sk) |
3560 | return selinux_no_sk_sid(fl); | 3567 | return selinux_no_sk_sid(fl); |
3568 | else { | ||
3569 | struct sk_security_struct *sksec = sk->sk_security; | ||
3561 | 3570 | ||
3562 | read_lock_bh(&sk->sk_callback_lock); | 3571 | return sksec->sid; |
3563 | isec = get_sock_isec(sk); | 3572 | } |
3564 | |||
3565 | if (isec) | ||
3566 | sock_sid = isec->sid; | ||
3567 | |||
3568 | read_unlock_bh(&sk->sk_callback_lock); | ||
3569 | return sock_sid; | ||
3570 | } | 3573 | } |
3571 | 3574 | ||
3572 | static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) | 3575 | static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) |
@@ -4618,6 +4621,7 @@ static struct security_operations selinux_ops = { | |||
4618 | .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram, | 4621 | .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram, |
4619 | .sk_alloc_security = selinux_sk_alloc_security, | 4622 | .sk_alloc_security = selinux_sk_alloc_security, |
4620 | .sk_free_security = selinux_sk_free_security, | 4623 | .sk_free_security = selinux_sk_free_security, |
4624 | .sk_clone_security = selinux_sk_clone_security, | ||
4621 | .sk_getsid = selinux_sk_getsid_security, | 4625 | .sk_getsid = selinux_sk_getsid_security, |
4622 | 4626 | ||
4623 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 4627 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 940178865fc7..79b9e0af19a0 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
@@ -99,6 +99,7 @@ struct netif_security_struct { | |||
99 | 99 | ||
100 | struct sk_security_struct { | 100 | struct sk_security_struct { |
101 | struct sock *sk; /* back pointer to sk object */ | 101 | struct sock *sk; /* back pointer to sk object */ |
102 | u32 sid; /* SID of this object */ | ||
102 | u32 peer_sid; /* SID of peer */ | 103 | u32 peer_sid; /* SID of peer */ |
103 | }; | 104 | }; |
104 | 105 | ||