mirror of
https://github.com/torvalds/linux.git
synced 2026-06-02 03:24:19 +02:00
Merge branch 'rxrpc-miscellaneous-fixes'
David Howells says: ==================== rxrpc: Miscellaneous fixes Here are some fixes for rxrpc: (1) Fix the calling of IP routing code with IRQs disabled. (2) Fix a recvmsg/recvmsg race when the first completes a call. (3) Fix a race between notification, recvmsg and sendmsg releasing a call. (4) Fix abort of abort. (5) Fix call-level aborts that should be connection-level aborts. ==================== Link: https://patch.msgid.link/20250717074350.3767366-1-dhowells@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
32247444dd
|
|
@ -322,20 +322,24 @@
|
|||
EM(rxrpc_call_put_kernel, "PUT kernel ") \
|
||||
EM(rxrpc_call_put_poke, "PUT poke ") \
|
||||
EM(rxrpc_call_put_recvmsg, "PUT recvmsg ") \
|
||||
EM(rxrpc_call_put_release_recvmsg_q, "PUT rls-rcmq") \
|
||||
EM(rxrpc_call_put_release_sock, "PUT rls-sock") \
|
||||
EM(rxrpc_call_put_release_sock_tba, "PUT rls-sk-a") \
|
||||
EM(rxrpc_call_put_sendmsg, "PUT sendmsg ") \
|
||||
EM(rxrpc_call_put_unnotify, "PUT unnotify") \
|
||||
EM(rxrpc_call_put_userid_exists, "PUT u-exists") \
|
||||
EM(rxrpc_call_put_userid, "PUT user-id ") \
|
||||
EM(rxrpc_call_see_accept, "SEE accept ") \
|
||||
EM(rxrpc_call_see_activate_client, "SEE act-clnt") \
|
||||
EM(rxrpc_call_see_already_released, "SEE alrdy-rl") \
|
||||
EM(rxrpc_call_see_connect_failed, "SEE con-fail") \
|
||||
EM(rxrpc_call_see_connected, "SEE connect ") \
|
||||
EM(rxrpc_call_see_conn_abort, "SEE conn-abt") \
|
||||
EM(rxrpc_call_see_discard, "SEE discard ") \
|
||||
EM(rxrpc_call_see_disconnected, "SEE disconn ") \
|
||||
EM(rxrpc_call_see_distribute_error, "SEE dist-err") \
|
||||
EM(rxrpc_call_see_input, "SEE input ") \
|
||||
EM(rxrpc_call_see_notify_released, "SEE nfy-rlsd") \
|
||||
EM(rxrpc_call_see_recvmsg, "SEE recvmsg ") \
|
||||
EM(rxrpc_call_see_release, "SEE release ") \
|
||||
EM(rxrpc_call_see_userid_exists, "SEE u-exists") \
|
||||
EM(rxrpc_call_see_waiting_call, "SEE q-conn ") \
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ enum rxrpc_skb_mark {
|
|||
RXRPC_SKB_MARK_SERVICE_CONN_SECURED, /* Service connection response has been verified */
|
||||
RXRPC_SKB_MARK_REJECT_BUSY, /* Reject with BUSY */
|
||||
RXRPC_SKB_MARK_REJECT_ABORT, /* Reject with ABORT (code in skb->priority) */
|
||||
RXRPC_SKB_MARK_REJECT_CONN_ABORT, /* Reject with connection ABORT (code in skb->priority) */
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -1253,6 +1254,8 @@ int rxrpc_encap_rcv(struct sock *, struct sk_buff *);
|
|||
void rxrpc_error_report(struct sock *);
|
||||
bool rxrpc_direct_abort(struct sk_buff *skb, enum rxrpc_abort_reason why,
|
||||
s32 abort_code, int err);
|
||||
bool rxrpc_direct_conn_abort(struct sk_buff *skb, enum rxrpc_abort_reason why,
|
||||
s32 abort_code, int err);
|
||||
int rxrpc_io_thread(void *data);
|
||||
void rxrpc_post_response(struct rxrpc_connection *conn, struct sk_buff *skb);
|
||||
static inline void rxrpc_wake_up_io_thread(struct rxrpc_local *local)
|
||||
|
|
@ -1383,6 +1386,7 @@ struct rxrpc_peer *rxrpc_lookup_peer_rcu(struct rxrpc_local *,
|
|||
const struct sockaddr_rxrpc *);
|
||||
struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local,
|
||||
struct sockaddr_rxrpc *srx, gfp_t gfp);
|
||||
void rxrpc_assess_MTU_size(struct rxrpc_local *local, struct rxrpc_peer *peer);
|
||||
struct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *, gfp_t,
|
||||
enum rxrpc_peer_trace);
|
||||
void rxrpc_new_incoming_peer(struct rxrpc_local *local, struct rxrpc_peer *peer);
|
||||
|
|
|
|||
|
|
@ -219,6 +219,7 @@ void rxrpc_discard_prealloc(struct rxrpc_sock *rx)
|
|||
tail = b->call_backlog_tail;
|
||||
while (CIRC_CNT(head, tail, size) > 0) {
|
||||
struct rxrpc_call *call = b->call_backlog[tail];
|
||||
rxrpc_see_call(call, rxrpc_call_see_discard);
|
||||
rcu_assign_pointer(call->socket, rx);
|
||||
if (rx->app_ops &&
|
||||
rx->app_ops->discard_new_call) {
|
||||
|
|
@ -373,8 +374,8 @@ bool rxrpc_new_incoming_call(struct rxrpc_local *local,
|
|||
spin_lock(&rx->incoming_lock);
|
||||
if (rx->sk.sk_state == RXRPC_SERVER_LISTEN_DISABLED ||
|
||||
rx->sk.sk_state == RXRPC_CLOSE) {
|
||||
rxrpc_direct_abort(skb, rxrpc_abort_shut_down,
|
||||
RX_INVALID_OPERATION, -ESHUTDOWN);
|
||||
rxrpc_direct_conn_abort(skb, rxrpc_abort_shut_down,
|
||||
RX_INVALID_OPERATION, -ESHUTDOWN);
|
||||
goto no_call;
|
||||
}
|
||||
|
||||
|
|
@ -406,6 +407,7 @@ bool rxrpc_new_incoming_call(struct rxrpc_local *local,
|
|||
|
||||
spin_unlock(&rx->incoming_lock);
|
||||
read_unlock_irq(&local->services_lock);
|
||||
rxrpc_assess_MTU_size(local, call->peer);
|
||||
|
||||
if (hlist_unhashed(&call->error_link)) {
|
||||
spin_lock_irq(&call->peer->lock);
|
||||
|
|
@ -420,12 +422,12 @@ bool rxrpc_new_incoming_call(struct rxrpc_local *local,
|
|||
|
||||
unsupported_service:
|
||||
read_unlock_irq(&local->services_lock);
|
||||
return rxrpc_direct_abort(skb, rxrpc_abort_service_not_offered,
|
||||
RX_INVALID_OPERATION, -EOPNOTSUPP);
|
||||
return rxrpc_direct_conn_abort(skb, rxrpc_abort_service_not_offered,
|
||||
RX_INVALID_OPERATION, -EOPNOTSUPP);
|
||||
unsupported_security:
|
||||
read_unlock_irq(&local->services_lock);
|
||||
return rxrpc_direct_abort(skb, rxrpc_abort_service_not_offered,
|
||||
RX_INVALID_OPERATION, -EKEYREJECTED);
|
||||
return rxrpc_direct_conn_abort(skb, rxrpc_abort_service_not_offered,
|
||||
RX_INVALID_OPERATION, -EKEYREJECTED);
|
||||
no_call:
|
||||
spin_unlock(&rx->incoming_lock);
|
||||
read_unlock_irq(&local->services_lock);
|
||||
|
|
|
|||
|
|
@ -561,7 +561,7 @@ static void rxrpc_cleanup_rx_buffers(struct rxrpc_call *call)
|
|||
void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)
|
||||
{
|
||||
struct rxrpc_connection *conn = call->conn;
|
||||
bool put = false, putu = false;
|
||||
bool putu = false;
|
||||
|
||||
_enter("{%d,%d}", call->debug_id, refcount_read(&call->ref));
|
||||
|
||||
|
|
@ -573,23 +573,13 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)
|
|||
|
||||
rxrpc_put_call_slot(call);
|
||||
|
||||
/* Make sure we don't get any more notifications */
|
||||
/* Note that at this point, the call may still be on or may have been
|
||||
* added back on to the socket receive queue. recvmsg() must discard
|
||||
* released calls. The CALL_RELEASED flag should prevent further
|
||||
* notifications.
|
||||
*/
|
||||
spin_lock_irq(&rx->recvmsg_lock);
|
||||
|
||||
if (!list_empty(&call->recvmsg_link)) {
|
||||
_debug("unlinking once-pending call %p { e=%lx f=%lx }",
|
||||
call, call->events, call->flags);
|
||||
list_del(&call->recvmsg_link);
|
||||
put = true;
|
||||
}
|
||||
|
||||
/* list_empty() must return false in rxrpc_notify_socket() */
|
||||
call->recvmsg_link.next = NULL;
|
||||
call->recvmsg_link.prev = NULL;
|
||||
|
||||
spin_unlock_irq(&rx->recvmsg_lock);
|
||||
if (put)
|
||||
rxrpc_put_call(call, rxrpc_call_put_unnotify);
|
||||
|
||||
write_lock(&rx->call_lock);
|
||||
|
||||
|
|
@ -638,6 +628,12 @@ void rxrpc_release_calls_on_socket(struct rxrpc_sock *rx)
|
|||
rxrpc_put_call(call, rxrpc_call_put_release_sock);
|
||||
}
|
||||
|
||||
while ((call = list_first_entry_or_null(&rx->recvmsg_q,
|
||||
struct rxrpc_call, recvmsg_link))) {
|
||||
list_del_init(&call->recvmsg_link);
|
||||
rxrpc_put_call(call, rxrpc_call_put_release_recvmsg_q);
|
||||
}
|
||||
|
||||
_leave("");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,6 +97,20 @@ bool rxrpc_direct_abort(struct sk_buff *skb, enum rxrpc_abort_reason why,
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Directly produce a connection abort from a packet.
|
||||
*/
|
||||
bool rxrpc_direct_conn_abort(struct sk_buff *skb, enum rxrpc_abort_reason why,
|
||||
s32 abort_code, int err)
|
||||
{
|
||||
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
|
||||
|
||||
trace_rxrpc_abort(0, why, sp->hdr.cid, 0, sp->hdr.seq, abort_code, err);
|
||||
skb->mark = RXRPC_SKB_MARK_REJECT_CONN_ABORT;
|
||||
skb->priority = abort_code;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool rxrpc_bad_message(struct sk_buff *skb, enum rxrpc_abort_reason why)
|
||||
{
|
||||
return rxrpc_direct_abort(skb, why, RX_PROTOCOL_ERROR, -EBADMSG);
|
||||
|
|
|
|||
|
|
@ -814,6 +814,9 @@ void rxrpc_reject_packet(struct rxrpc_local *local, struct sk_buff *skb)
|
|||
__be32 code;
|
||||
int ret, ioc;
|
||||
|
||||
if (sp->hdr.type == RXRPC_PACKET_TYPE_ABORT)
|
||||
return; /* Never abort an abort. */
|
||||
|
||||
rxrpc_see_skb(skb, rxrpc_skb_see_reject);
|
||||
|
||||
iov[0].iov_base = &whdr;
|
||||
|
|
@ -826,7 +829,13 @@ void rxrpc_reject_packet(struct rxrpc_local *local, struct sk_buff *skb)
|
|||
msg.msg_controllen = 0;
|
||||
msg.msg_flags = 0;
|
||||
|
||||
memset(&whdr, 0, sizeof(whdr));
|
||||
whdr = (struct rxrpc_wire_header) {
|
||||
.epoch = htonl(sp->hdr.epoch),
|
||||
.cid = htonl(sp->hdr.cid),
|
||||
.callNumber = htonl(sp->hdr.callNumber),
|
||||
.serviceId = htons(sp->hdr.serviceId),
|
||||
.flags = ~sp->hdr.flags & RXRPC_CLIENT_INITIATED,
|
||||
};
|
||||
|
||||
switch (skb->mark) {
|
||||
case RXRPC_SKB_MARK_REJECT_BUSY:
|
||||
|
|
@ -834,6 +843,9 @@ void rxrpc_reject_packet(struct rxrpc_local *local, struct sk_buff *skb)
|
|||
size = sizeof(whdr);
|
||||
ioc = 1;
|
||||
break;
|
||||
case RXRPC_SKB_MARK_REJECT_CONN_ABORT:
|
||||
whdr.callNumber = 0;
|
||||
fallthrough;
|
||||
case RXRPC_SKB_MARK_REJECT_ABORT:
|
||||
whdr.type = RXRPC_PACKET_TYPE_ABORT;
|
||||
code = htonl(skb->priority);
|
||||
|
|
@ -847,14 +859,6 @@ void rxrpc_reject_packet(struct rxrpc_local *local, struct sk_buff *skb)
|
|||
if (rxrpc_extract_addr_from_skb(&srx, skb) == 0) {
|
||||
msg.msg_namelen = srx.transport_len;
|
||||
|
||||
whdr.epoch = htonl(sp->hdr.epoch);
|
||||
whdr.cid = htonl(sp->hdr.cid);
|
||||
whdr.callNumber = htonl(sp->hdr.callNumber);
|
||||
whdr.serviceId = htons(sp->hdr.serviceId);
|
||||
whdr.flags = sp->hdr.flags;
|
||||
whdr.flags ^= RXRPC_CLIENT_INITIATED;
|
||||
whdr.flags &= RXRPC_CLIENT_INITIATED;
|
||||
|
||||
iov_iter_kvec(&msg.msg_iter, WRITE, iov, ioc, size);
|
||||
ret = do_udp_sendmsg(local->socket, &msg, size);
|
||||
if (ret < 0)
|
||||
|
|
|
|||
|
|
@ -149,8 +149,7 @@ struct rxrpc_peer *rxrpc_lookup_peer_rcu(struct rxrpc_local *local,
|
|||
* assess the MTU size for the network interface through which this peer is
|
||||
* reached
|
||||
*/
|
||||
static void rxrpc_assess_MTU_size(struct rxrpc_local *local,
|
||||
struct rxrpc_peer *peer)
|
||||
void rxrpc_assess_MTU_size(struct rxrpc_local *local, struct rxrpc_peer *peer)
|
||||
{
|
||||
struct net *net = local->net;
|
||||
struct dst_entry *dst;
|
||||
|
|
@ -277,8 +276,6 @@ static void rxrpc_init_peer(struct rxrpc_local *local, struct rxrpc_peer *peer,
|
|||
|
||||
peer->hdrsize += sizeof(struct rxrpc_wire_header);
|
||||
peer->max_data = peer->if_mtu - peer->hdrsize;
|
||||
|
||||
rxrpc_assess_MTU_size(local, peer);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -297,6 +294,7 @@ static struct rxrpc_peer *rxrpc_create_peer(struct rxrpc_local *local,
|
|||
if (peer) {
|
||||
memcpy(&peer->srx, srx, sizeof(*srx));
|
||||
rxrpc_init_peer(local, peer, hash_key);
|
||||
rxrpc_assess_MTU_size(local, peer);
|
||||
}
|
||||
|
||||
_leave(" = %p", peer);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@ void rxrpc_notify_socket(struct rxrpc_call *call)
|
|||
|
||||
if (!list_empty(&call->recvmsg_link))
|
||||
return;
|
||||
if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) {
|
||||
rxrpc_see_call(call, rxrpc_call_see_notify_released);
|
||||
return;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
|
|
@ -447,6 +451,16 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
|
|||
goto try_again;
|
||||
}
|
||||
|
||||
rxrpc_see_call(call, rxrpc_call_see_recvmsg);
|
||||
if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) {
|
||||
rxrpc_see_call(call, rxrpc_call_see_already_released);
|
||||
list_del_init(&call->recvmsg_link);
|
||||
spin_unlock_irq(&rx->recvmsg_lock);
|
||||
release_sock(&rx->sk);
|
||||
trace_rxrpc_recvmsg(call->debug_id, rxrpc_recvmsg_unqueue, 0);
|
||||
rxrpc_put_call(call, rxrpc_call_put_recvmsg);
|
||||
goto try_again;
|
||||
}
|
||||
if (!(flags & MSG_PEEK))
|
||||
list_del_init(&call->recvmsg_link);
|
||||
else
|
||||
|
|
@ -470,8 +484,13 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
|
|||
|
||||
release_sock(&rx->sk);
|
||||
|
||||
if (test_bit(RXRPC_CALL_RELEASED, &call->flags))
|
||||
BUG();
|
||||
if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) {
|
||||
rxrpc_see_call(call, rxrpc_call_see_already_released);
|
||||
mutex_unlock(&call->user_mutex);
|
||||
if (!(flags & MSG_PEEK))
|
||||
rxrpc_put_call(call, rxrpc_call_put_recvmsg);
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
ret = rxrpc_recvmsg_user_id(call, msg, flags);
|
||||
if (ret < 0)
|
||||
|
|
|
|||
|
|
@ -140,15 +140,15 @@ const struct rxrpc_security *rxrpc_get_incoming_security(struct rxrpc_sock *rx,
|
|||
|
||||
sec = rxrpc_security_lookup(sp->hdr.securityIndex);
|
||||
if (!sec) {
|
||||
rxrpc_direct_abort(skb, rxrpc_abort_unsupported_security,
|
||||
RX_INVALID_OPERATION, -EKEYREJECTED);
|
||||
rxrpc_direct_conn_abort(skb, rxrpc_abort_unsupported_security,
|
||||
RX_INVALID_OPERATION, -EKEYREJECTED);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sp->hdr.securityIndex != RXRPC_SECURITY_NONE &&
|
||||
!rx->securities) {
|
||||
rxrpc_direct_abort(skb, rxrpc_abort_no_service_key,
|
||||
sec->no_key_abort, -EKEYREJECTED);
|
||||
rxrpc_direct_conn_abort(skb, rxrpc_abort_no_service_key,
|
||||
sec->no_key_abort, -EKEYREJECTED);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user