aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-01-05 18:38:53 -0500
committerDavid S. Miller <davem@davemloft.net>2011-01-05 18:38:53 -0500
commit3610cda53f247e176bcbb7a7cca64bc53b12acdb (patch)
treed780bc1e405116e75a194b2f4693a6f9bbe9f58f
parent44b8288308ac9da27eab7d7bdbf1375a568805c3 (diff)
af_unix: Avoid socket->sk NULL OOPS in stream connect security hooks.
unix_release() can asynchornously set socket->sk to NULL, and it does so without holding the unix_state_lock() on "other" during stream connects. However, the reverse mapping, sk->sk_socket, is only transitioned to NULL under the unix_state_lock(). Therefore make the security hooks follow the reverse mapping instead of the forward mapping. Reported-by: Jeremy Fitzhardinge <jeremy@goop.org> Reported-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/security.h15
-rw-r--r--net/unix/af_unix.c2
-rw-r--r--security/capability.c2
-rw-r--r--security/security.c3
-rw-r--r--security/selinux/hooks.c10
-rw-r--r--security/smack/smack_lsm.c14
6 files changed, 22 insertions, 24 deletions
diff --git a/include/linux/security.h b/include/linux/security.h
index fd4d55fb8845..d47a4c24b3e4 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -796,8 +796,9 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
796 * @unix_stream_connect: 796 * @unix_stream_connect:
797 * Check permissions before establishing a Unix domain stream connection 797 * Check permissions before establishing a Unix domain stream connection
798 * between @sock and @other. 798 * between @sock and @other.
799 * @sock contains the socket structure. 799 * @sock contains the sock structure.
800 * @other contains the peer socket structure. 800 * @other contains the peer sock structure.
801 * @newsk contains the new sock structure.
801 * Return 0 if permission is granted. 802 * Return 0 if permission is granted.
802 * @unix_may_send: 803 * @unix_may_send:
803 * Check permissions before connecting or sending datagrams from @sock to 804 * Check permissions before connecting or sending datagrams from @sock to
@@ -1568,8 +1569,7 @@ struct security_operations {
1568 int (*inode_getsecctx)(struct inode *inode, void **ctx, u32 *ctxlen); 1569 int (*inode_getsecctx)(struct inode *inode, void **ctx, u32 *ctxlen);
1569 1570
1570#ifdef CONFIG_SECURITY_NETWORK 1571#ifdef CONFIG_SECURITY_NETWORK
1571 int (*unix_stream_connect) (struct socket *sock, 1572 int (*unix_stream_connect) (struct sock *sock, struct sock *other, struct sock *newsk);
1572 struct socket *other, struct sock *newsk);
1573 int (*unix_may_send) (struct socket *sock, struct socket *other); 1573 int (*unix_may_send) (struct socket *sock, struct socket *other);
1574 1574
1575 int (*socket_create) (int family, int type, int protocol, int kern); 1575 int (*socket_create) (int family, int type, int protocol, int kern);
@@ -2525,8 +2525,7 @@ static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32
2525 2525
2526#ifdef CONFIG_SECURITY_NETWORK 2526#ifdef CONFIG_SECURITY_NETWORK
2527 2527
2528int security_unix_stream_connect(struct socket *sock, struct socket *other, 2528int security_unix_stream_connect(struct sock *sock, struct sock *other, struct sock *newsk);
2529 struct sock *newsk);
2530int security_unix_may_send(struct socket *sock, struct socket *other); 2529int security_unix_may_send(struct socket *sock, struct socket *other);
2531int security_socket_create(int family, int type, int protocol, int kern); 2530int security_socket_create(int family, int type, int protocol, int kern);
2532int security_socket_post_create(struct socket *sock, int family, 2531int security_socket_post_create(struct socket *sock, int family,
@@ -2567,8 +2566,8 @@ void security_tun_dev_post_create(struct sock *sk);
2567int security_tun_dev_attach(struct sock *sk); 2566int security_tun_dev_attach(struct sock *sk);
2568 2567
2569#else /* CONFIG_SECURITY_NETWORK */ 2568#else /* CONFIG_SECURITY_NETWORK */
2570static inline int security_unix_stream_connect(struct socket *sock, 2569static inline int security_unix_stream_connect(struct sock *sock,
2571 struct socket *other, 2570 struct sock *other,
2572 struct sock *newsk) 2571 struct sock *newsk)
2573{ 2572{
2574 return 0; 2573 return 0;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 417d7a6c36cf..dd419d286204 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1157,7 +1157,7 @@ restart:
1157 goto restart; 1157 goto restart;
1158 } 1158 }
1159 1159
1160 err = security_unix_stream_connect(sock, other->sk_socket, newsk); 1160 err = security_unix_stream_connect(sk, other, newsk);
1161 if (err) { 1161 if (err) {
1162 unix_state_unlock(sk); 1162 unix_state_unlock(sk);
1163 goto out_unlock; 1163 goto out_unlock;
diff --git a/security/capability.c b/security/capability.c
index c773635ca3a0..2a5df2b7da83 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -548,7 +548,7 @@ static int cap_sem_semop(struct sem_array *sma, struct sembuf *sops,
548} 548}
549 549
550#ifdef CONFIG_SECURITY_NETWORK 550#ifdef CONFIG_SECURITY_NETWORK
551static int cap_unix_stream_connect(struct socket *sock, struct socket *other, 551static int cap_unix_stream_connect(struct sock *sock, struct sock *other,
552 struct sock *newsk) 552 struct sock *newsk)
553{ 553{
554 return 0; 554 return 0;
diff --git a/security/security.c b/security/security.c
index 1b798d3df710..e5fb07a3052d 100644
--- a/security/security.c
+++ b/security/security.c
@@ -977,8 +977,7 @@ EXPORT_SYMBOL(security_inode_getsecctx);
977 977
978#ifdef CONFIG_SECURITY_NETWORK 978#ifdef CONFIG_SECURITY_NETWORK
979 979
980int security_unix_stream_connect(struct socket *sock, struct socket *other, 980int security_unix_stream_connect(struct sock *sock, struct sock *other, struct sock *newsk)
981 struct sock *newsk)
982{ 981{
983 return security_ops->unix_stream_connect(sock, other, newsk); 982 return security_ops->unix_stream_connect(sock, other, newsk);
984} 983}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index c82538a4b1a4..6f637d2678ac 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3921,18 +3921,18 @@ static int selinux_socket_shutdown(struct socket *sock, int how)
3921 return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN); 3921 return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN);
3922} 3922}
3923 3923
3924static int selinux_socket_unix_stream_connect(struct socket *sock, 3924static int selinux_socket_unix_stream_connect(struct sock *sock,
3925 struct socket *other, 3925 struct sock *other,
3926 struct sock *newsk) 3926 struct sock *newsk)
3927{ 3927{
3928 struct sk_security_struct *sksec_sock = sock->sk->sk_security; 3928 struct sk_security_struct *sksec_sock = sock->sk_security;
3929 struct sk_security_struct *sksec_other = other->sk->sk_security; 3929 struct sk_security_struct *sksec_other = other->sk_security;
3930 struct sk_security_struct *sksec_new = newsk->sk_security; 3930 struct sk_security_struct *sksec_new = newsk->sk_security;
3931 struct common_audit_data ad; 3931 struct common_audit_data ad;
3932 int err; 3932 int err;
3933 3933
3934 COMMON_AUDIT_DATA_INIT(&ad, NET); 3934 COMMON_AUDIT_DATA_INIT(&ad, NET);
3935 ad.u.net.sk = other->sk; 3935 ad.u.net.sk = other;
3936 3936
3937 err = avc_has_perm(sksec_sock->sid, sksec_other->sid, 3937 err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
3938 sksec_other->sclass, 3938 sksec_other->sclass,
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 489a85afa477..ccb71a044a1a 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2408,22 +2408,22 @@ static int smack_setprocattr(struct task_struct *p, char *name,
2408 2408
2409/** 2409/**
2410 * smack_unix_stream_connect - Smack access on UDS 2410 * smack_unix_stream_connect - Smack access on UDS
2411 * @sock: one socket 2411 * @sock: one sock
2412 * @other: the other socket 2412 * @other: the other sock
2413 * @newsk: unused 2413 * @newsk: unused
2414 * 2414 *
2415 * Return 0 if a subject with the smack of sock could access 2415 * Return 0 if a subject with the smack of sock could access
2416 * an object with the smack of other, otherwise an error code 2416 * an object with the smack of other, otherwise an error code
2417 */ 2417 */
2418static int smack_unix_stream_connect(struct socket *sock, 2418static int smack_unix_stream_connect(struct sock *sock,
2419 struct socket *other, struct sock *newsk) 2419 struct sock *other, struct sock *newsk)
2420{ 2420{
2421 struct inode *sp = SOCK_INODE(sock); 2421 struct inode *sp = SOCK_INODE(sock->sk_socket);
2422 struct inode *op = SOCK_INODE(other); 2422 struct inode *op = SOCK_INODE(other->sk_socket);
2423 struct smk_audit_info ad; 2423 struct smk_audit_info ad;
2424 2424
2425 smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); 2425 smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET);
2426 smk_ad_setfield_u_net_sk(&ad, other->sk); 2426 smk_ad_setfield_u_net_sk(&ad, other);
2427 return smk_access(smk_of_inode(sp), smk_of_inode(op), 2427 return smk_access(smk_of_inode(sp), smk_of_inode(op),
2428 MAY_READWRITE, &ad); 2428 MAY_READWRITE, &ad);
2429} 2429}