• David Howells's avatar
    rxrpc: Fix send on a connected, but unbound socket · 36febc98
    David Howells authored
    [ Upstream commit e835ada0 ]
    
    If sendmsg() or sendmmsg() is called on a connected socket that hasn't had
    bind() called on it, then an oops will occur when the kernel tries to
    connect the call because no local endpoint has been allocated.
    
    Fix this by implicitly binding the socket if it is in the
    RXRPC_CLIENT_UNBOUND state, just like it does for the RXRPC_UNBOUND state.
    
    Further, the state should be transitioned to RXRPC_CLIENT_BOUND after this
    to prevent further attempts to bind it.
    
    This can be tested with:
    
    	#include <stdio.h>
    	#include <stdlib.h>
    	#include <string.h>
    	#include <sys/socket.h>
    	#include <arpa/inet.h>
    	#include <linux/rxrpc.h>
    	static const unsigned char inet6_addr[16] = {
    		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0xac, 0x14, 0x14, 0xaa
    	};
    	int main(void)
    	{
    		struct sockaddr_rxrpc srx;
    		struct cmsghdr *cm;
    		struct msghdr msg;
    		unsigned char control[16];
    		int fd;
    		memset(&srx, 0, sizeof(srx));
    		srx.srx_family = 0x21;
    		srx.srx_service = 0;
    		srx.transport_type = AF_INET;
    		srx.transport_len = 0x1c;
    		srx.transport.sin6.sin6_family = AF_INET6;
    		srx.transport.sin6.sin6_port = htons(0x4e22);
    		srx.transport.sin6.sin6_flowinfo = htons(0x4e22);
    		srx.transport.sin6.sin6_scope_id = htons(0xaa3b);
    		memcpy(&srx.transport.sin6.sin6_addr, inet6_addr, 16);
    		cm = (struct cmsghdr *)control;
    		cm->cmsg_len	= CMSG_LEN(sizeof(unsigned long));
    		cm->cmsg_level	= SOL_RXRPC;
    		cm->cmsg_type	= RXRPC_USER_CALL_ID;
    		*(unsigned long *)CMSG_DATA(cm) = 0;
    		msg.msg_name = NULL;
    		msg.msg_namelen = 0;
    		msg.msg_iov = NULL;
    		msg.msg_iovlen = 0;
    		msg.msg_control = control;
    		msg.msg_controllen = cm->cmsg_len;
    		msg.msg_flags = 0;
    		fd = socket(AF_RXRPC, SOCK_DGRAM, AF_INET);
    		connect(fd, (struct sockaddr *)&srx, sizeof(srx));
    		sendmsg(fd, &msg, 0);
    		return 0;
    	}
    
    Leading to the following oops:
    
    	BUG: kernel NULL pointer dereference, address: 0000000000000018
    	#PF: supervisor read access in kernel mode
    	#PF: error_code(0x0000) - not-present page
    	...
    	RIP: 0010:rxrpc_connect_call+0x42/0xa01
    	...
    	Call Trace:
    	 ? mark_held_locks+0x47/0x59
    	 ? __local_bh_enable_ip+0xb6/0xba
    	 rxrpc_new_client_call+0x3b1/0x762
    	 ? rxrpc_do_sendmsg+0x3c0/0x92e
    	 rxrpc_do_sendmsg+0x3c0/0x92e
    	 rxrpc_sendmsg+0x16b/0x1b5
    	 sock_sendmsg+0x2d/0x39
    	 ___sys_sendmsg+0x1a4/0x22a
    	 ? release_sock+0x19/0x9e
    	 ? reacquire_held_locks+0x136/0x160
    	 ? release_sock+0x19/0x9e
    	 ? find_held_lock+0x2b/0x6e
    	 ? __lock_acquire+0x268/0xf73
    	 ? rxrpc_connect+0xdd/0xe4
    	 ? __local_bh_enable_ip+0xb6/0xba
    	 __sys_sendmsg+0x5e/0x94
    	 do_syscall_64+0x7d/0x1bf
    	 entry_SYSCALL_64_after_hwframe+0x49/0xbe
    
    Fixes: 2341e077 ("rxrpc: Simplify connect() implementation and simplify sendmsg() op")
    Reported-by: syzbot+7966f2a0b2c7da8939b4@syzkaller.appspotmail.com
    Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
    Reviewed-by: default avatarMarc Dionne <marc.dionne@auristor.com>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    36febc98
af_rxrpc.c 25.3 KB