Commit ff43ae4b authored by David S. Miller's avatar David S. Miller

Merge tag 'rxrpc-fixes-20191220' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs

David Howells says:

====================
rxrpc: Fixes

Here are a couple of bugfixes plus a patch that makes one of the bugfixes
easier:

 (1) Move the ping and mutex unlock on a new call from rxrpc_input_packet()
     into rxrpc_new_incoming_call(), which it calls.  This means the
     lock-unlock section is entirely within the latter function.  This
     simplifies patch (2).

 (2) Don't take the call->user_mutex at all in the softirq path.  Mutexes
     aren't allowed to be taken or released there and a patch was merged
     that caused a warning to be emitted every time this happened.  Looking
     at the code again, it looks like that taking the mutex isn't actually
     necessary, as the value of call->state will block access to the call.

 (3) Fix the incoming call path to check incoming calls earlier to reject
     calls to RPC services for which we don't have a security key of the
     appropriate class.  This avoids an assertion failure if YFS tries
     making a secure call to the kafs cache manager RPC service.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 7c3125f0 063c60d3
...@@ -209,6 +209,7 @@ struct rxrpc_skb_priv { ...@@ -209,6 +209,7 @@ struct rxrpc_skb_priv {
struct rxrpc_security { struct rxrpc_security {
const char *name; /* name of this service */ const char *name; /* name of this service */
u8 security_index; /* security type provided */ u8 security_index; /* security type provided */
u32 no_key_abort; /* Abort code indicating no key */
/* Initialise a security service */ /* Initialise a security service */
int (*init)(void); int (*init)(void);
...@@ -977,8 +978,9 @@ static inline void rxrpc_reduce_conn_timer(struct rxrpc_connection *conn, ...@@ -977,8 +978,9 @@ static inline void rxrpc_reduce_conn_timer(struct rxrpc_connection *conn,
struct rxrpc_connection *rxrpc_find_service_conn_rcu(struct rxrpc_peer *, struct rxrpc_connection *rxrpc_find_service_conn_rcu(struct rxrpc_peer *,
struct sk_buff *); struct sk_buff *);
struct rxrpc_connection *rxrpc_prealloc_service_connection(struct rxrpc_net *, gfp_t); struct rxrpc_connection *rxrpc_prealloc_service_connection(struct rxrpc_net *, gfp_t);
void rxrpc_new_incoming_connection(struct rxrpc_sock *, void rxrpc_new_incoming_connection(struct rxrpc_sock *, struct rxrpc_connection *,
struct rxrpc_connection *, struct sk_buff *); const struct rxrpc_security *, struct key *,
struct sk_buff *);
void rxrpc_unpublish_service_conn(struct rxrpc_connection *); void rxrpc_unpublish_service_conn(struct rxrpc_connection *);
/* /*
...@@ -1103,7 +1105,9 @@ extern const struct rxrpc_security rxkad; ...@@ -1103,7 +1105,9 @@ extern const struct rxrpc_security rxkad;
int __init rxrpc_init_security(void); int __init rxrpc_init_security(void);
void rxrpc_exit_security(void); void rxrpc_exit_security(void);
int rxrpc_init_client_conn_security(struct rxrpc_connection *); int rxrpc_init_client_conn_security(struct rxrpc_connection *);
int rxrpc_init_server_conn_security(struct rxrpc_connection *); bool rxrpc_look_up_server_security(struct rxrpc_local *, struct rxrpc_sock *,
const struct rxrpc_security **, struct key **,
struct sk_buff *);
/* /*
* sendmsg.c * sendmsg.c
......
...@@ -239,6 +239,22 @@ void rxrpc_discard_prealloc(struct rxrpc_sock *rx) ...@@ -239,6 +239,22 @@ void rxrpc_discard_prealloc(struct rxrpc_sock *rx)
kfree(b); kfree(b);
} }
/*
* Ping the other end to fill our RTT cache and to retrieve the rwind
* and MTU parameters.
*/
static void rxrpc_send_ping(struct rxrpc_call *call, struct sk_buff *skb)
{
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
ktime_t now = skb->tstamp;
if (call->peer->rtt_usage < 3 ||
ktime_before(ktime_add_ms(call->peer->rtt_last_req, 1000), now))
rxrpc_propose_ACK(call, RXRPC_ACK_PING, sp->hdr.serial,
true, true,
rxrpc_propose_ack_ping_for_params);
}
/* /*
* Allocate a new incoming call from the prealloc pool, along with a connection * Allocate a new incoming call from the prealloc pool, along with a connection
* and a peer as necessary. * and a peer as necessary.
...@@ -247,6 +263,8 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx, ...@@ -247,6 +263,8 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx,
struct rxrpc_local *local, struct rxrpc_local *local,
struct rxrpc_peer *peer, struct rxrpc_peer *peer,
struct rxrpc_connection *conn, struct rxrpc_connection *conn,
const struct rxrpc_security *sec,
struct key *key,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct rxrpc_backlog *b = rx->backlog; struct rxrpc_backlog *b = rx->backlog;
...@@ -294,7 +312,7 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx, ...@@ -294,7 +312,7 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx,
conn->params.local = rxrpc_get_local(local); conn->params.local = rxrpc_get_local(local);
conn->params.peer = peer; conn->params.peer = peer;
rxrpc_see_connection(conn); rxrpc_see_connection(conn);
rxrpc_new_incoming_connection(rx, conn, skb); rxrpc_new_incoming_connection(rx, conn, sec, key, skb);
} else { } else {
rxrpc_get_connection(conn); rxrpc_get_connection(conn);
} }
...@@ -333,9 +351,11 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local, ...@@ -333,9 +351,11 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
const struct rxrpc_security *sec = NULL;
struct rxrpc_connection *conn; struct rxrpc_connection *conn;
struct rxrpc_peer *peer = NULL; struct rxrpc_peer *peer = NULL;
struct rxrpc_call *call; struct rxrpc_call *call = NULL;
struct key *key = NULL;
_enter(""); _enter("");
...@@ -346,9 +366,7 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local, ...@@ -346,9 +366,7 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
sp->hdr.seq, RX_INVALID_OPERATION, ESHUTDOWN); sp->hdr.seq, RX_INVALID_OPERATION, ESHUTDOWN);
skb->mark = RXRPC_SKB_MARK_REJECT_ABORT; skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
skb->priority = RX_INVALID_OPERATION; skb->priority = RX_INVALID_OPERATION;
_leave(" = NULL [close]"); goto no_call;
call = NULL;
goto out;
} }
/* The peer, connection and call may all have sprung into existence due /* The peer, connection and call may all have sprung into existence due
...@@ -358,29 +376,19 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local, ...@@ -358,29 +376,19 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
*/ */
conn = rxrpc_find_connection_rcu(local, skb, &peer); conn = rxrpc_find_connection_rcu(local, skb, &peer);
call = rxrpc_alloc_incoming_call(rx, local, peer, conn, skb); if (!conn && !rxrpc_look_up_server_security(local, rx, &sec, &key, skb))
goto no_call;
call = rxrpc_alloc_incoming_call(rx, local, peer, conn, sec, key, skb);
key_put(key);
if (!call) { if (!call) {
skb->mark = RXRPC_SKB_MARK_REJECT_BUSY; skb->mark = RXRPC_SKB_MARK_REJECT_BUSY;
_leave(" = NULL [busy]"); goto no_call;
call = NULL;
goto out;
} }
trace_rxrpc_receive(call, rxrpc_receive_incoming, trace_rxrpc_receive(call, rxrpc_receive_incoming,
sp->hdr.serial, sp->hdr.seq); sp->hdr.serial, sp->hdr.seq);
/* Lock the call to prevent rxrpc_kernel_send/recv_data() and
* sendmsg()/recvmsg() inconveniently stealing the mutex once the
* notification is generated.
*
* The BUG should never happen because the kernel should be well
* behaved enough not to access the call before the first notification
* event and userspace is prevented from doing so until the state is
* appropriate.
*/
if (!mutex_trylock(&call->user_mutex))
BUG();
/* Make the call live. */ /* Make the call live. */
rxrpc_incoming_call(rx, call, skb); rxrpc_incoming_call(rx, call, skb);
conn = call->conn; conn = call->conn;
...@@ -421,6 +429,9 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local, ...@@ -421,6 +429,9 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
BUG(); BUG();
} }
spin_unlock(&conn->state_lock); spin_unlock(&conn->state_lock);
spin_unlock(&rx->incoming_lock);
rxrpc_send_ping(call, skb);
if (call->state == RXRPC_CALL_SERVER_ACCEPTING) if (call->state == RXRPC_CALL_SERVER_ACCEPTING)
rxrpc_notify_socket(call); rxrpc_notify_socket(call);
...@@ -433,9 +444,12 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local, ...@@ -433,9 +444,12 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
rxrpc_put_call(call, rxrpc_call_put); rxrpc_put_call(call, rxrpc_call_put);
_leave(" = %p{%d}", call, call->debug_id); _leave(" = %p{%d}", call, call->debug_id);
out:
spin_unlock(&rx->incoming_lock);
return call; return call;
no_call:
spin_unlock(&rx->incoming_lock);
_leave(" = NULL [%u]", skb->mark);
return NULL;
} }
/* /*
......
...@@ -376,21 +376,7 @@ static void rxrpc_secure_connection(struct rxrpc_connection *conn) ...@@ -376,21 +376,7 @@ static void rxrpc_secure_connection(struct rxrpc_connection *conn)
_enter("{%d}", conn->debug_id); _enter("{%d}", conn->debug_id);
ASSERT(conn->security_ix != 0); ASSERT(conn->security_ix != 0);
ASSERT(conn->server_key);
if (!conn->params.key) {
_debug("set up security");
ret = rxrpc_init_server_conn_security(conn);
switch (ret) {
case 0:
break;
case -ENOENT:
abort_code = RX_CALL_DEAD;
goto abort;
default:
abort_code = RXKADNOAUTH;
goto abort;
}
}
if (conn->security->issue_challenge(conn) < 0) { if (conn->security->issue_challenge(conn) < 0) {
abort_code = RX_CALL_DEAD; abort_code = RX_CALL_DEAD;
......
...@@ -148,6 +148,8 @@ struct rxrpc_connection *rxrpc_prealloc_service_connection(struct rxrpc_net *rxn ...@@ -148,6 +148,8 @@ struct rxrpc_connection *rxrpc_prealloc_service_connection(struct rxrpc_net *rxn
*/ */
void rxrpc_new_incoming_connection(struct rxrpc_sock *rx, void rxrpc_new_incoming_connection(struct rxrpc_sock *rx,
struct rxrpc_connection *conn, struct rxrpc_connection *conn,
const struct rxrpc_security *sec,
struct key *key,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
...@@ -160,6 +162,8 @@ void rxrpc_new_incoming_connection(struct rxrpc_sock *rx, ...@@ -160,6 +162,8 @@ void rxrpc_new_incoming_connection(struct rxrpc_sock *rx,
conn->service_id = sp->hdr.serviceId; conn->service_id = sp->hdr.serviceId;
conn->security_ix = sp->hdr.securityIndex; conn->security_ix = sp->hdr.securityIndex;
conn->out_clientflag = 0; conn->out_clientflag = 0;
conn->security = sec;
conn->server_key = key_get(key);
if (conn->security_ix) if (conn->security_ix)
conn->state = RXRPC_CONN_SERVICE_UNSECURED; conn->state = RXRPC_CONN_SERVICE_UNSECURED;
else else
......
...@@ -192,22 +192,6 @@ static void rxrpc_congestion_management(struct rxrpc_call *call, ...@@ -192,22 +192,6 @@ static void rxrpc_congestion_management(struct rxrpc_call *call,
goto out_no_clear_ca; goto out_no_clear_ca;
} }
/*
* Ping the other end to fill our RTT cache and to retrieve the rwind
* and MTU parameters.
*/
static void rxrpc_send_ping(struct rxrpc_call *call, struct sk_buff *skb)
{
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
ktime_t now = skb->tstamp;
if (call->peer->rtt_usage < 3 ||
ktime_before(ktime_add_ms(call->peer->rtt_last_req, 1000), now))
rxrpc_propose_ACK(call, RXRPC_ACK_PING, sp->hdr.serial,
true, true,
rxrpc_propose_ack_ping_for_params);
}
/* /*
* Apply a hard ACK by advancing the Tx window. * Apply a hard ACK by advancing the Tx window.
*/ */
...@@ -1396,8 +1380,6 @@ int rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb) ...@@ -1396,8 +1380,6 @@ int rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb)
call = rxrpc_new_incoming_call(local, rx, skb); call = rxrpc_new_incoming_call(local, rx, skb);
if (!call) if (!call)
goto reject_packet; goto reject_packet;
rxrpc_send_ping(call, skb);
mutex_unlock(&call->user_mutex);
} }
/* Process a call packet; this either discards or passes on the ref /* Process a call packet; this either discards or passes on the ref
......
...@@ -648,9 +648,9 @@ static int rxkad_issue_challenge(struct rxrpc_connection *conn) ...@@ -648,9 +648,9 @@ static int rxkad_issue_challenge(struct rxrpc_connection *conn)
u32 serial; u32 serial;
int ret; int ret;
_enter("{%d,%x}", conn->debug_id, key_serial(conn->params.key)); _enter("{%d,%x}", conn->debug_id, key_serial(conn->server_key));
ret = key_validate(conn->params.key); ret = key_validate(conn->server_key);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -1293,6 +1293,7 @@ static void rxkad_exit(void) ...@@ -1293,6 +1293,7 @@ static void rxkad_exit(void)
const struct rxrpc_security rxkad = { const struct rxrpc_security rxkad = {
.name = "rxkad", .name = "rxkad",
.security_index = RXRPC_SECURITY_RXKAD, .security_index = RXRPC_SECURITY_RXKAD,
.no_key_abort = RXKADUNKNOWNKEY,
.init = rxkad_init, .init = rxkad_init,
.exit = rxkad_exit, .exit = rxkad_exit,
.init_connection_security = rxkad_init_connection_security, .init_connection_security = rxkad_init_connection_security,
......
...@@ -101,62 +101,58 @@ int rxrpc_init_client_conn_security(struct rxrpc_connection *conn) ...@@ -101,62 +101,58 @@ int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
} }
/* /*
* initialise the security on a server connection * Find the security key for a server connection.
*/ */
int rxrpc_init_server_conn_security(struct rxrpc_connection *conn) bool rxrpc_look_up_server_security(struct rxrpc_local *local, struct rxrpc_sock *rx,
const struct rxrpc_security **_sec,
struct key **_key,
struct sk_buff *skb)
{ {
const struct rxrpc_security *sec; const struct rxrpc_security *sec;
struct rxrpc_local *local = conn->params.local; struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
struct rxrpc_sock *rx; key_ref_t kref = NULL;
struct key *key;
key_ref_t kref;
char kdesc[5 + 1 + 3 + 1]; char kdesc[5 + 1 + 3 + 1];
_enter(""); _enter("");
sprintf(kdesc, "%u:%u", conn->service_id, conn->security_ix); sprintf(kdesc, "%u:%u", sp->hdr.serviceId, sp->hdr.securityIndex);
sec = rxrpc_security_lookup(conn->security_ix); sec = rxrpc_security_lookup(sp->hdr.securityIndex);
if (!sec) { if (!sec) {
_leave(" = -ENOKEY [lookup]"); trace_rxrpc_abort(0, "SVS",
return -ENOKEY; sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
RX_INVALID_OPERATION, EKEYREJECTED);
skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
skb->priority = RX_INVALID_OPERATION;
return false;
} }
/* find the service */ if (sp->hdr.securityIndex == RXRPC_SECURITY_NONE)
read_lock(&local->services_lock); goto out;
rx = rcu_dereference_protected(local->service,
lockdep_is_held(&local->services_lock));
if (rx && (rx->srx.srx_service == conn->service_id ||
rx->second_service == conn->service_id))
goto found_service;
/* the service appears to have died */
read_unlock(&local->services_lock);
_leave(" = -ENOENT");
return -ENOENT;
found_service:
if (!rx->securities) { if (!rx->securities) {
read_unlock(&local->services_lock); trace_rxrpc_abort(0, "SVR",
_leave(" = -ENOKEY"); sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
return -ENOKEY; RX_INVALID_OPERATION, EKEYREJECTED);
skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
skb->priority = RX_INVALID_OPERATION;
return false;
} }
/* look through the service's keyring */ /* look through the service's keyring */
kref = keyring_search(make_key_ref(rx->securities, 1UL), kref = keyring_search(make_key_ref(rx->securities, 1UL),
&key_type_rxrpc_s, kdesc, true); &key_type_rxrpc_s, kdesc, true);
if (IS_ERR(kref)) { if (IS_ERR(kref)) {
read_unlock(&local->services_lock); trace_rxrpc_abort(0, "SVK",
_leave(" = %ld [search]", PTR_ERR(kref)); sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
return PTR_ERR(kref); sec->no_key_abort, EKEYREJECTED);
skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
skb->priority = sec->no_key_abort;
return false;
} }
key = key_ref_to_ptr(kref); out:
read_unlock(&local->services_lock); *_sec = sec;
*_key = key_ref_to_ptr(kref);
conn->server_key = key; return true;
conn->security = sec;
_leave(" = 0");
return 0;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment