Commit db099c62 authored by David Howells's avatar David Howells Committed by David S. Miller
Browse files

rxrpc: Fix timeout of a call that hasn't yet been granted a channel



afs_make_call() calls rxrpc_kernel_begin_call() to begin a call (which may
get stalled in the background waiting for a connection to become
available); it then calls rxrpc_kernel_set_max_life() to set the timeouts -
but that starts the call timer so the call timer might then expire before
we get a connection assigned - leading to the following oops if the call
stalled:

	BUG: kernel NULL pointer dereference, address: 0000000000000000
	...
	CPU: 1 PID: 5111 Comm: krxrpcio/0 Not tainted 6.3.0-rc7-build3+ #701
	RIP: 0010:rxrpc_alloc_txbuf+0xc0/0x157
	...
	Call Trace:
	 <TASK>
	 rxrpc_send_ACK+0x50/0x13b
	 rxrpc_input_call_event+0x16a/0x67d
	 rxrpc_io_thread+0x1b6/0x45f
	 ? _raw_spin_unlock_irqrestore+0x1f/0x35
	 ? rxrpc_input_packet+0x519/0x519
	 kthread+0xe7/0xef
	 ? kthread_complete_and_exit+0x1b/0x1b
	 ret_from_fork+0x22/0x30

Fix this by noting the timeouts in struct rxrpc_call when the call is
created.  The timer will be started when the first packet is transmitted.

It shouldn't be possible to trigger this directly from userspace through
AF_RXRPC as sendmsg() will return EBUSY if the call is in the
waiting-for-conn state if it dropped out of the wait due to a signal.

Fixes: 9d35d880 ("rxrpc: Move client call connection to the I/O thread")
Reported-by: default avatarMarc Dionne <marc.dionne@auristor.com>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Eric Dumazet <edumazet@google.com>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: linux-afs@lists.infradead.org
cc: netdev@vger.kernel.org
cc: linux-kernel@vger.kernel.org
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0eb362d2
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -19,8 +19,8 @@
#define AFSPATHMAX		1024	/* Maximum length of a pathname plus NUL */
#define AFSOPAQUEMAX		1024	/* Maximum length of an opaque field */

#define AFS_VL_MAX_LIFESPAN	(120 * HZ)
#define AFS_PROBE_MAX_LIFESPAN	(30 * HZ)
#define AFS_VL_MAX_LIFESPAN	120
#define AFS_PROBE_MAX_LIFESPAN	30

typedef u64			afs_volid_t;
typedef u64			afs_vnodeid_t;
+1 −1
Original line number Diff line number Diff line
@@ -128,7 +128,7 @@ struct afs_call {
	spinlock_t		state_lock;
	int			error;		/* error code */
	u32			abort_code;	/* Remote abort ID or 0 */
	unsigned int		max_lifespan;	/* Maximum lifespan to set if not 0 */
	unsigned int		max_lifespan;	/* Maximum lifespan in secs to set if not 0 */
	unsigned		request_size;	/* size of request data */
	unsigned		reply_max;	/* maximum size of reply */
	unsigned		count2;		/* count used in unmarshalling */
+3 −5
Original line number Diff line number Diff line
@@ -335,7 +335,9 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
	/* create a call */
	rxcall = rxrpc_kernel_begin_call(call->net->socket, srx, call->key,
					 (unsigned long)call,
					 tx_total_len, gfp,
					 tx_total_len,
					 call->max_lifespan,
					 gfp,
					 (call->async ?
					  afs_wake_up_async_call :
					  afs_wake_up_call_waiter),
@@ -350,10 +352,6 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
	}

	call->rxcall = rxcall;

	if (call->max_lifespan)
		rxrpc_kernel_set_max_life(call->net->socket, rxcall,
					  call->max_lifespan);
	call->issue_time = ktime_get_real();

	/* send the request */
+11 −10
Original line number Diff line number Diff line
@@ -40,16 +40,17 @@ typedef void (*rxrpc_user_attach_call_t)(struct rxrpc_call *, unsigned long);
void rxrpc_kernel_new_call_notification(struct socket *,
					rxrpc_notify_new_call_t,
					rxrpc_discard_new_call_t);
struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *,
					   struct sockaddr_rxrpc *,
					   struct key *,
					   unsigned long,
					   s64,
					   gfp_t,
					   rxrpc_notify_rx_t,
					   bool,
					   enum rxrpc_interruptibility,
					   unsigned int);
struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
					   struct sockaddr_rxrpc *srx,
					   struct key *key,
					   unsigned long user_call_ID,
					   s64 tx_total_len,
					   u32 hard_timeout,
					   gfp_t gfp,
					   rxrpc_notify_rx_t notify_rx,
					   bool upgrade,
					   enum rxrpc_interruptibility interruptibility,
					   unsigned int debug_id);
int rxrpc_kernel_send_data(struct socket *, struct rxrpc_call *,
			   struct msghdr *, size_t,
			   rxrpc_notify_end_tx_t);
+3 −0
Original line number Diff line number Diff line
@@ -265,6 +265,7 @@ static int rxrpc_listen(struct socket *sock, int backlog)
 * @key: The security context to use (defaults to socket setting)
 * @user_call_ID: The ID to use
 * @tx_total_len: Total length of data to transmit during the call (or -1)
 * @hard_timeout: The maximum lifespan of the call in sec
 * @gfp: The allocation constraints
 * @notify_rx: Where to send notifications instead of socket queue
 * @upgrade: Request service upgrade for call
@@ -283,6 +284,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
					   struct key *key,
					   unsigned long user_call_ID,
					   s64 tx_total_len,
					   u32 hard_timeout,
					   gfp_t gfp,
					   rxrpc_notify_rx_t notify_rx,
					   bool upgrade,
@@ -313,6 +315,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
	p.tx_total_len		= tx_total_len;
	p.interruptibility	= interruptibility;
	p.kernel		= true;
	p.timeouts.hard		= hard_timeout;

	memset(&cp, 0, sizeof(cp));
	cp.local		= rx->local;
Loading