* Gaah: selinux_socket_unix_stream_connect oops @ 2011-01-05 16:27 Linus Torvalds 2011-01-05 22:25 ` David Miller 0 siblings, 1 reply; 4+ messages in thread From: Linus Torvalds @ 2011-01-05 16:27 UTC (permalink / raw) To: David Miller, Network Development, Jeremy Fitzhardinge, James Morris [-- Attachment #1: Type: text/plain, Size: 2441 bytes --] This was actually a regression entry, but only ever reported once by Jeremy, I think. So it was basically ignored as not being very common and there not being any hints about what causes it. But after doing the 2.6.37 release, and intending to put it on all the machines I have access to, guess what I find on the kids computer? Right. It must be a reasonably rare race condition, because that computer had been up for three weeks or so (since middle of December), but yesterday evening it crashed due to that thing. The code disassembly is 13: 55 push %ebp 14: 89 e5 mov %esp,%ebp 16: 57 push %edi 17: 8d 7d 90 lea -0x70(%ebp),%edi 1a: 56 push %esi 1b: 53 push %ebx 1c: 83 ec 6c sub $0x6c,%esp 1f: 8b 40 14 mov 0x14(%eax),%eax 22: 8b 52 14 mov 0x14(%edx),%edx 25: 8b 98 58 01 00 00 mov 0x158(%eax),%ebx 2b:* 8b 82 58 01 00 00 mov 0x158(%edx),%eax <-- trapping instruction 31: 89 45 8c mov %eax,-0x74(%ebp) 34: 31 c0 xor %eax,%eax 36: 8b b1 58 01 00 00 mov 0x158(%ecx),%esi 3c: 89 7d 88 mov %edi,-0x78(%ebp) which means that it's "other->sk" that is NULL, which I think matches Jeremy's case exactly. The logs have a hint: this seems to have coincided with the console-kit-daemon giving a warning like: WARNING: Couldn't read /proc/13585/environ: Failed to open file '/proc/13585/environ': No such file or directory and then NetworkManager having a bunch of authentication warnings that end up about being Could not get UID of name ':1.3871': no such name (full text in the attachment). So I wonder if there is some subtle race that happens when one end of a unix domain socket attaches just as another end disconnects? Especially as "security_unix_stream_connect()" is called before the whole connect sequence is really final. It's generally "unix_release()" that sets 'sock->sk' to NULL. Btw, why do we pass in "sock" and "other->sk_socket" ("struct socket"), when it appears that what the security code really wants to get "struct sock" (which would be "sk" and "other" in the caller)? The calling convention seems to result in (a) this NULL pointer thing and (b) all these extra dereferences. Comments? Ideas? Linus [-- Attachment #2: kids.txt --] [-- Type: text/plain, Size: 5215 bytes --] Happened with Linux version 2.6.37-rc5-00333-gdaefc3d after perhaps three weeks of uptime. That kernel isn't in git, it has an extra patch (to force-enable AHCI on the mac mini), so it's really v2.6.37-rc5-332-g0fcdcfbbc98f in baseline. --- Jan 4 17:02:50 kids console-kit-daemon[2884]: WARNING: Couldn't read /proc/13585/environ: Failed to open file '/proc/13585/environ': No such file or directory Jan 4 17:02:50 kids NetworkManager[2438]: <warn> error requesting auth for org.freedesktop.NetworkManager.network-control: (6) Remote Exception invoking org.freedesktop.PolicyKit1.Authority.CheckAuthorization() on /org/freede... ...NameHasNoOwner: Could not get UID of name ':1.3871': no such name Jan 4 17:02:50 kids NetworkManager[2438]: <warn> User connections unavailable: (6) Remote Exception invoking org.freedesktop.PolicyKit1.Authority.CheckAuthorization() ... Jan 4 17:02:50 kids NetworkManager[2438]: <warn> error requesting auth for org.freedesktop.NetworkManager.enable-disable-network: (6) Remote Exception invoking org.fre... Jan 4 17:02:50 kids NetworkManager[2438]: <warn> error requesting auth for org.freedesktop.NetworkManager.sleep-wake: (6) Remote Exception invoking org.freedesktop.Pol... Jan 4 17:02:50 kids NetworkManager[2438]: <warn> error requesting auth for org.freedesktop.NetworkManager.enable-disable-wifi: (6) Remote Exception invoking org.freede... Jan 4 17:02:50 kids NetworkManager[2438]: <warn> error requesting auth for org.freedesktop.NetworkManager.enable-disable-wwan: (6) Remote Exception invoking org.freede... Jan 4 17:02:50 kids NetworkManager[2438]: <warn> error requesting auth for org.freedesktop.NetworkManager.use-user-connections: (6) Remote Exception invoking org.freed... Jan 4 17:02:50 kids NetworkManager[2438]: <warn> error requesting auth for org.freedesktop.NetworkManager.network-control: (6) Remote Exception invoking org.freedeskto... Jan 4 17:02:50 kids bonobo-activation-server (celeste-15075): could not associate with desktop session: Failed to connect to socket /tmp/dbus-8AXjzuuw2I: Connection re... ...NameHasNoOwner: Could not get UID of name ':1.3871': no such name Jan 4 17:02:50 kids kernel: [1755465.955480] BUG: unable to handle kernel NULL pointer dereference at 00000158 Jan 4 17:02:50 kids kernel: [1755465.956226] IP: [<c111297e>] selinux_socket_unix_stream_connect+0x18/0x84 Jan 4 17:02:50 kids kernel: [1755465.956226] *pde = 00000000 Jan 4 17:02:50 kids kernel: [1755465.956226] Oops: 0000 [#1] SMP Jan 4 17:02:50 kids kernel: [1755465.956226] last sysfs file: /sys/devices/virtual/sound/timer/uevent Jan 4 17:02:50 kids kernel: [1755465.956226] Modules linked in: [last unloaded: scsi_wait_scan] Jan 4 17:02:50 kids kernel: [1755465.956226] Jan 4 17:02:50 kids kernel: [1755465.956226] Pid: 15075, comm: bonobo-activati Not tainted 2.6.37-rc5-00333-gdaefc3d #13 Mac-F4208EC8/Macmini1,1 Jan 4 17:02:50 kids kernel: [1755465.956226] EIP: 0060:[<c111297e>] EFLAGS: 00210296 CPU: 1 Jan 4 17:02:50 kids kernel: [1755465.956226] EIP is at selinux_socket_unix_stream_connect+0x18/0x84 Jan 4 17:02:50 kids kernel: [1755465.956226] EAX: ee48b200 EBX: f1f983c0 ECX: ee48be00 EDX: 00000000 Jan 4 17:02:50 kids kernel: [1755465.956226] ESI: ee48b200 EDI: f59c5e1c EBP: f59c5e8c ESP: f59c5e14 Jan 4 17:02:50 kids kernel: [1755465.956226] DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 Jan 4 17:02:50 kids kernel: [1755465.956226] Process bonobo-activati (pid: 15075, ti=f59c4000 task=ee45eb50 task.ti=f59c4000) Jan 4 17:02:50 kids kernel: [1755465.956226] Stack: Jan 4 17:02:50 kids kernel: [1755465.956226] 00000000 00000000 00000000 00000000 00000000 00200046 00200046 00000059 Jan 4 17:02:50 kids kernel: [1755465.956226] 00000013 00000000 f59c5e44 c103070e f59c5e5c c1003cc5 f59c5e64 ee432a00 Jan 4 17:02:50 kids kernel: [1755465.956226] ee48b200 ee48be00 f59c5ed4 c1002ce9 ee432a00 f59c5ec0 e1b02900 ee48b200 Jan 4 17:02:50 kids kernel: [1755465.956226] Call Trace: Jan 4 17:02:50 kids kernel: [1755465.956226] [<c103070e>] ? irq_exit+0x39/0x5d Jan 4 17:02:50 kids kernel: [1755465.956226] [<c1003cc5>] ? do_IRQ+0x83/0x97 Jan 4 17:02:50 kids kernel: [1755465.956226] [<c1002ce9>] ? common_interrupt+0x29/0x30 Jan 4 17:02:50 kids kernel: [1755465.956226] [<c111072c>] ? security_unix_stream_connect+0x10/0x13 Jan 4 17:02:50 kids kernel: [1755465.956226] [<c1390029>] ? unix_stream_connect+0x1e3/0x35e Jan 4 17:02:50 kids kernel: [1755465.956226] [<c1316047>] ? sys_connect+0x60/0x7d Jan 4 17:02:50 kids kernel: [1755465.956226] [<c1316b29>] ? sys_socketcall+0x8f/0x1a5 Jan 4 17:02:50 kids kernel: [1755465.956226] [<c100278c>] ? sysenter_do_call+0x12/0x22 Jan 4 17:02:50 kids kernel: [1755465.956226] Code: 56 68 00 00 04 00 e8 ba f2 ff ff 8d 65 f4 5b 5e 5f c9 c3 55 89 e5 57 8d 7d 90 56 53 83 ec 6c 8b 40 14 8b 52 14 8b 98 58 01 00 00 <8b> 82 58 01 00 00 89 45 8c 31 c0 8b b1 58 01 00 00 89 7d 88 b9 Jan 4 17:02:50 kids kernel: [1755465.956226] EIP: [<c111297e>] selinux_socket_unix_stream_connect+0x18/0x84 SS:ESP 0068:f59c5e14 Jan 4 17:02:50 kids kernel: [1755465.956226] CR2: 0000000000000158 Jan 4 17:02:50 kids kernel: [1755466.037178] ---[ end trace 9fd0d9b8feb78e69 ]--- ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Gaah: selinux_socket_unix_stream_connect oops 2011-01-05 16:27 Gaah: selinux_socket_unix_stream_connect oops Linus Torvalds @ 2011-01-05 22:25 ` David Miller 2011-01-05 23:32 ` Linus Torvalds 0 siblings, 1 reply; 4+ messages in thread From: David Miller @ 2011-01-05 22:25 UTC (permalink / raw) To: torvalds; +Cc: netdev, jeremy, jmorris From: Linus Torvalds <torvalds@linux-foundation.org> Date: Wed, 5 Jan 2011 08:27:01 -0800 > So I wonder if there is some subtle race that happens when one end of > a unix domain socket attaches just as another end disconnects? > Especially as "security_unix_stream_connect()" is called before the > whole connect sequence is really final. It's generally > "unix_release()" that sets 'sock->sk' to NULL. > > Btw, why do we pass in "sock" and "other->sk_socket" ("struct > socket"), when it appears that what the security code really wants to > get "struct sock" (which would be "sk" and "other" in the caller)? The > calling convention seems to result in (a) this NULL pointer thing and > (b) all these extra dereferences. > > Comments? Ideas? There is nothing which blocks that unix_release() code which sets socket->sk to NULL, it runs asynchronously to this connect code. The reason it passes in the socket pointer instead of the pointer to struct sock is because that's what SMACK wants to use, as it needs to get at SOCK_INODE(). See, even you think the whole world is SELINUX :-))) More seriously, we can get at the struct socket via sk->sk_socket in the SMACK code. sk->sk_socket, unlike socket->sk, has it's state change to NULL (via sock_orphen()) protected by unix_state_lock(), which we hold for "other" in this unix connect code path. Therefore I propose we fix this like so: -------------------- 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> diff --git a/include/linux/security.h b/include/linux/security.h index fd4d55f..d47a4c2 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) * @unix_stream_connect: * Check permissions before establishing a Unix domain stream connection * between @sock and @other. - * @sock contains the socket structure. - * @other contains the peer socket structure. + * @sock contains the sock structure. + * @other contains the peer sock structure. + * @newsk contains the new sock structure. * Return 0 if permission is granted. * @unix_may_send: * Check permissions before connecting or sending datagrams from @sock to @@ -1568,8 +1569,7 @@ struct security_operations { int (*inode_getsecctx)(struct inode *inode, void **ctx, u32 *ctxlen); #ifdef CONFIG_SECURITY_NETWORK - int (*unix_stream_connect) (struct socket *sock, - struct socket *other, struct sock *newsk); + int (*unix_stream_connect) (struct sock *sock, struct sock *other, struct sock *newsk); int (*unix_may_send) (struct socket *sock, struct socket *other); 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 #ifdef CONFIG_SECURITY_NETWORK -int security_unix_stream_connect(struct socket *sock, struct socket *other, - struct sock *newsk); +int security_unix_stream_connect(struct sock *sock, struct sock *other, struct sock *newsk); int security_unix_may_send(struct socket *sock, struct socket *other); int security_socket_create(int family, int type, int protocol, int kern); int security_socket_post_create(struct socket *sock, int family, @@ -2567,8 +2566,8 @@ void security_tun_dev_post_create(struct sock *sk); int security_tun_dev_attach(struct sock *sk); #else /* CONFIG_SECURITY_NETWORK */ -static inline int security_unix_stream_connect(struct socket *sock, - struct socket *other, +static inline int security_unix_stream_connect(struct sock *sock, + struct sock *other, struct sock *newsk) { return 0; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 417d7a6..dd419d2 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1157,7 +1157,7 @@ restart: goto restart; } - err = security_unix_stream_connect(sock, other->sk_socket, newsk); + err = security_unix_stream_connect(sk, other, newsk); if (err) { unix_state_unlock(sk); goto out_unlock; diff --git a/security/capability.c b/security/capability.c index c773635..2a5df2b 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, } #ifdef CONFIG_SECURITY_NETWORK -static int cap_unix_stream_connect(struct socket *sock, struct socket *other, +static int cap_unix_stream_connect(struct sock *sock, struct sock *other, struct sock *newsk) { return 0; diff --git a/security/security.c b/security/security.c index 1b798d3..e5fb07a 100644 --- a/security/security.c +++ b/security/security.c @@ -977,8 +977,7 @@ EXPORT_SYMBOL(security_inode_getsecctx); #ifdef CONFIG_SECURITY_NETWORK -int security_unix_stream_connect(struct socket *sock, struct socket *other, - struct sock *newsk) +int security_unix_stream_connect(struct sock *sock, struct sock *other, struct sock *newsk) { return security_ops->unix_stream_connect(sock, other, newsk); } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c82538a..6f637d2 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) return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN); } -static int selinux_socket_unix_stream_connect(struct socket *sock, - struct socket *other, +static int selinux_socket_unix_stream_connect(struct sock *sock, + struct sock *other, struct sock *newsk) { - struct sk_security_struct *sksec_sock = sock->sk->sk_security; - struct sk_security_struct *sksec_other = other->sk->sk_security; + struct sk_security_struct *sksec_sock = sock->sk_security; + struct sk_security_struct *sksec_other = other->sk_security; struct sk_security_struct *sksec_new = newsk->sk_security; struct common_audit_data ad; int err; COMMON_AUDIT_DATA_INIT(&ad, NET); - ad.u.net.sk = other->sk; + ad.u.net.sk = other; err = avc_has_perm(sksec_sock->sid, sksec_other->sid, sksec_other->sclass, diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 489a85a..ccb71a0 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, /** * smack_unix_stream_connect - Smack access on UDS - * @sock: one socket - * @other: the other socket + * @sock: one sock + * @other: the other sock * @newsk: unused * * Return 0 if a subject with the smack of sock could access * an object with the smack of other, otherwise an error code */ -static int smack_unix_stream_connect(struct socket *sock, - struct socket *other, struct sock *newsk) +static int smack_unix_stream_connect(struct sock *sock, + struct sock *other, struct sock *newsk) { - struct inode *sp = SOCK_INODE(sock); - struct inode *op = SOCK_INODE(other); + struct inode *sp = SOCK_INODE(sock->sk_socket); + struct inode *op = SOCK_INODE(other->sk_socket); struct smk_audit_info ad; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); - smk_ad_setfield_u_net_sk(&ad, other->sk); + smk_ad_setfield_u_net_sk(&ad, other); return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_READWRITE, &ad); } ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: Gaah: selinux_socket_unix_stream_connect oops 2011-01-05 22:25 ` David Miller @ 2011-01-05 23:32 ` Linus Torvalds 2011-01-05 23:38 ` David Miller 0 siblings, 1 reply; 4+ messages in thread From: Linus Torvalds @ 2011-01-05 23:32 UTC (permalink / raw) To: David Miller; +Cc: netdev, jeremy, jmorris On Wed, Jan 5, 2011 at 2:25 PM, David Miller <davem@davemloft.net> wrote: > > More seriously, we can get at the struct socket via sk->sk_socket in > the SMACK code. sk->sk_socket, unlike socket->sk, has it's state > change to NULL (via sock_orphen()) protected by unix_state_lock(), > which we hold for "other" in this unix connect code path. > > Therefore I propose we fix this like so: Looks fine to me. And no, I don't think that selinux is all the world, but selinux is the _common_ case, and with the cross-pointers, the only difference can be whether you need to dereference the pointer or not - so choosing the "extra dereference" case for the common case seems silly. The fact that this also fixes locking is obviously an even better reason to do it, though ;) Linus ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Gaah: selinux_socket_unix_stream_connect oops 2011-01-05 23:32 ` Linus Torvalds @ 2011-01-05 23:38 ` David Miller 0 siblings, 0 replies; 4+ messages in thread From: David Miller @ 2011-01-05 23:38 UTC (permalink / raw) To: torvalds; +Cc: netdev, jeremy, jmorris From: Linus Torvalds <torvalds@linux-foundation.org> Date: Wed, 5 Jan 2011 15:32:44 -0800 > On Wed, Jan 5, 2011 at 2:25 PM, David Miller <davem@davemloft.net> wrote: >> >> More seriously, we can get at the struct socket via sk->sk_socket in >> the SMACK code. sk->sk_socket, unlike socket->sk, has it's state >> change to NULL (via sock_orphen()) protected by unix_state_lock(), >> which we hold for "other" in this unix connect code path. >> >> Therefore I propose we fix this like so: > > Looks fine to me. > > And no, I don't think that selinux is all the world, but selinux is > the _common_ case, and with the cross-pointers, the only difference > can be whether you need to dereference the pointer or not - so > choosing the "extra dereference" case for the common case seems silly. > > The fact that this also fixes locking is obviously an even better > reason to do it, though ;) Right :) I'll toss this your way during the merge window and queue it up for later -stable submission as well. Thanks. ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2011-01-05 23:41 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2011-01-05 16:27 Gaah: selinux_socket_unix_stream_connect oops Linus Torvalds 2011-01-05 22:25 ` David Miller 2011-01-05 23:32 ` Linus Torvalds 2011-01-05 23:38 ` David Miller
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).