Skip to content

Commit ec832bd

Browse files
committed
rxrpc: Don't retain the server key in the connection
Don't retain a pointer to the server key in the connection, but rather get it on demand when the server has to deal with a response packet. This is necessary to implement RxGK (GSSAPI-mediated transport class), where we can't know which key we'll need until we've challenged the client and got back the response. This also means that we don't need to do a key search in the accept path in softirq mode. Also, whilst we're at it, allow the security class to ask for a kvno and encoding-type variant of a server key as RxGK needs different keys for different encoding types. Keys of this type have an extra bit in the description: "<service-id>:<security-index>:<kvno>:<enctype>" Signed-off-by: David Howells <[email protected]>
1 parent 41057eb commit ec832bd

File tree

7 files changed

+100
-67
lines changed

7 files changed

+100
-67
lines changed

net/rxrpc/ar-internal.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,6 @@ struct rxrpc_connection {
441441
struct list_head link; /* link in master connection list */
442442
struct sk_buff_head rx_queue; /* received conn-level packets */
443443
const struct rxrpc_security *security; /* applied security module */
444-
struct key *server_key; /* security for this service */
445444
struct crypto_sync_skcipher *cipher; /* encryption handle */
446445
struct rxrpc_crypt csum_iv; /* packet checksum base */
447446
unsigned long flags;
@@ -890,8 +889,7 @@ struct rxrpc_connection *rxrpc_find_service_conn_rcu(struct rxrpc_peer *,
890889
struct sk_buff *);
891890
struct rxrpc_connection *rxrpc_prealloc_service_connection(struct rxrpc_net *, gfp_t);
892891
void rxrpc_new_incoming_connection(struct rxrpc_sock *, struct rxrpc_connection *,
893-
const struct rxrpc_security *, struct key *,
894-
struct sk_buff *);
892+
const struct rxrpc_security *, struct sk_buff *);
895893
void rxrpc_unpublish_service_conn(struct rxrpc_connection *);
896894

897895
/*
@@ -1056,9 +1054,10 @@ extern const struct rxrpc_security rxkad;
10561054
int __init rxrpc_init_security(void);
10571055
void rxrpc_exit_security(void);
10581056
int rxrpc_init_client_conn_security(struct rxrpc_connection *);
1059-
bool rxrpc_look_up_server_security(struct rxrpc_local *, struct rxrpc_sock *,
1060-
const struct rxrpc_security **, struct key **,
1061-
struct sk_buff *);
1057+
const struct rxrpc_security *rxrpc_get_incoming_security(struct rxrpc_sock *,
1058+
struct sk_buff *);
1059+
struct key *rxrpc_look_up_server_security(struct rxrpc_connection *,
1060+
struct sk_buff *, u32, u32);
10621061

10631062
/*
10641063
* sendmsg.c

net/rxrpc/call_accept.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,6 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx,
261261
struct rxrpc_peer *peer,
262262
struct rxrpc_connection *conn,
263263
const struct rxrpc_security *sec,
264-
struct key *key,
265264
struct sk_buff *skb)
266265
{
267266
struct rxrpc_backlog *b = rx->backlog;
@@ -309,7 +308,7 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx,
309308
conn->params.local = rxrpc_get_local(local);
310309
conn->params.peer = peer;
311310
rxrpc_see_connection(conn);
312-
rxrpc_new_incoming_connection(rx, conn, sec, key, skb);
311+
rxrpc_new_incoming_connection(rx, conn, sec, skb);
313312
} else {
314313
rxrpc_get_connection(conn);
315314
}
@@ -353,7 +352,6 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
353352
struct rxrpc_connection *conn;
354353
struct rxrpc_peer *peer = NULL;
355354
struct rxrpc_call *call = NULL;
356-
struct key *key = NULL;
357355

358356
_enter("");
359357

@@ -374,11 +372,13 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
374372
*/
375373
conn = rxrpc_find_connection_rcu(local, skb, &peer);
376374

377-
if (!conn && !rxrpc_look_up_server_security(local, rx, &sec, &key, skb))
378-
goto no_call;
375+
if (!conn) {
376+
sec = rxrpc_get_incoming_security(rx, skb);
377+
if (!sec)
378+
goto no_call;
379+
}
379380

380-
call = rxrpc_alloc_incoming_call(rx, local, peer, conn, sec, key, skb);
381-
key_put(key);
381+
call = rxrpc_alloc_incoming_call(rx, local, peer, conn, sec, skb);
382382
if (!call) {
383383
skb->mark = RXRPC_SKB_MARK_REJECT_BUSY;
384384
goto no_call;

net/rxrpc/conn_event.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,6 @@ static void rxrpc_secure_connection(struct rxrpc_connection *conn)
378378
_enter("{%d}", conn->debug_id);
379379

380380
ASSERT(conn->security_ix != 0);
381-
ASSERT(conn->server_key);
382381

383382
if (conn->security->issue_challenge(conn) < 0) {
384383
abort_code = RX_CALL_DEAD;

net/rxrpc/conn_object.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,6 @@ static void rxrpc_destroy_connection(struct rcu_head *rcu)
363363

364364
conn->security->clear(conn);
365365
key_put(conn->params.key);
366-
key_put(conn->server_key);
367366
rxrpc_put_bundle(conn->bundle);
368367
rxrpc_put_peer(conn->params.peer);
369368

net/rxrpc/conn_service.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,6 @@ struct rxrpc_connection *rxrpc_prealloc_service_connection(struct rxrpc_net *rxn
156156
void rxrpc_new_incoming_connection(struct rxrpc_sock *rx,
157157
struct rxrpc_connection *conn,
158158
const struct rxrpc_security *sec,
159-
struct key *key,
160159
struct sk_buff *skb)
161160
{
162161
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
@@ -170,7 +169,6 @@ void rxrpc_new_incoming_connection(struct rxrpc_sock *rx,
170169
conn->security_ix = sp->hdr.securityIndex;
171170
conn->out_clientflag = 0;
172171
conn->security = sec;
173-
conn->server_key = key_get(key);
174172
if (conn->security_ix)
175173
conn->state = RXRPC_CONN_SERVICE_UNSECURED;
176174
else

net/rxrpc/rxkad.c

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -647,11 +647,7 @@ static int rxkad_issue_challenge(struct rxrpc_connection *conn)
647647
u32 serial;
648648
int ret;
649649

650-
_enter("{%d,%x}", conn->debug_id, key_serial(conn->server_key));
651-
652-
ret = key_validate(conn->server_key);
653-
if (ret < 0)
654-
return ret;
650+
_enter("{%d}", conn->debug_id);
655651

656652
get_random_bytes(&conn->security_nonce, sizeof(conn->security_nonce));
657653

@@ -891,6 +887,7 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn,
891887
* decrypt the kerberos IV ticket in the response
892888
*/
893889
static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
890+
struct key *server_key,
894891
struct sk_buff *skb,
895892
void *ticket, size_t ticket_len,
896893
struct rxrpc_crypt *_session_key,
@@ -910,30 +907,17 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
910907
u32 abort_code;
911908
u8 *p, *q, *name, *end;
912909

913-
_enter("{%d},{%x}", conn->debug_id, key_serial(conn->server_key));
910+
_enter("{%d},{%x}", conn->debug_id, key_serial(server_key));
914911

915912
*_expiry = 0;
916913

917-
ret = key_validate(conn->server_key);
918-
if (ret < 0) {
919-
switch (ret) {
920-
case -EKEYEXPIRED:
921-
abort_code = RXKADEXPIRED;
922-
goto other_error;
923-
default:
924-
abort_code = RXKADNOAUTH;
925-
goto other_error;
926-
}
927-
}
928-
929-
ASSERT(conn->server_key->payload.data[0] != NULL);
914+
ASSERT(server_key->payload.data[0] != NULL);
930915
ASSERTCMP((unsigned long) ticket & 7UL, ==, 0);
931916

932-
memcpy(&iv, &conn->server_key->payload.data[2], sizeof(iv));
917+
memcpy(&iv, &server_key->payload.data[2], sizeof(iv));
933918

934919
ret = -ENOMEM;
935-
req = skcipher_request_alloc(conn->server_key->payload.data[0],
936-
GFP_NOFS);
920+
req = skcipher_request_alloc(server_key->payload.data[0], GFP_NOFS);
937921
if (!req)
938922
goto temporary_error;
939923

@@ -1089,14 +1073,35 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
10891073
struct rxkad_response *response;
10901074
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
10911075
struct rxrpc_crypt session_key;
1076+
struct key *server_key;
10921077
const char *eproto;
10931078
time64_t expiry;
10941079
void *ticket;
10951080
u32 abort_code, version, kvno, ticket_len, level;
10961081
__be32 csum;
10971082
int ret, i;
10981083

1099-
_enter("{%d,%x}", conn->debug_id, key_serial(conn->server_key));
1084+
_enter("{%d}", conn->debug_id);
1085+
1086+
server_key = rxrpc_look_up_server_security(conn, skb, 0, 0);
1087+
if (IS_ERR(server_key)) {
1088+
switch (PTR_ERR(server_key)) {
1089+
case -ENOKEY:
1090+
abort_code = RXKADUNKNOWNKEY;
1091+
break;
1092+
case -EKEYEXPIRED:
1093+
abort_code = RXKADEXPIRED;
1094+
break;
1095+
default:
1096+
abort_code = RXKADNOAUTH;
1097+
break;
1098+
}
1099+
trace_rxrpc_abort(0, "SVK",
1100+
sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
1101+
abort_code, PTR_ERR(server_key));
1102+
*_abort_code = abort_code;
1103+
return -EPROTO;
1104+
}
11001105

11011106
ret = -ENOMEM;
11021107
response = kzalloc(sizeof(struct rxkad_response), GFP_NOFS);
@@ -1144,8 +1149,8 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
11441149
ticket, ticket_len) < 0)
11451150
goto protocol_error_free;
11461151

1147-
ret = rxkad_decrypt_ticket(conn, skb, ticket, ticket_len, &session_key,
1148-
&expiry, _abort_code);
1152+
ret = rxkad_decrypt_ticket(conn, server_key, skb, ticket, ticket_len,
1153+
&session_key, &expiry, _abort_code);
11491154
if (ret < 0)
11501155
goto temporary_error_free_ticket;
11511156

@@ -1224,6 +1229,7 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
12241229
protocol_error:
12251230
kfree(response);
12261231
trace_rxrpc_rx_eproto(NULL, sp->hdr.serial, eproto);
1232+
key_put(server_key);
12271233
*_abort_code = abort_code;
12281234
return -EPROTO;
12291235

@@ -1236,6 +1242,7 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
12361242
* ENOMEM. We just want to send the challenge again. Note that we
12371243
* also come out this way if the ticket decryption fails.
12381244
*/
1245+
key_put(server_key);
12391246
return ret;
12401247
}
12411248

net/rxrpc/security.c

Lines changed: 56 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -102,58 +102,89 @@ int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
102102
}
103103

104104
/*
105-
* Find the security key for a server connection.
105+
* Set the ops a server connection.
106106
*/
107-
bool rxrpc_look_up_server_security(struct rxrpc_local *local, struct rxrpc_sock *rx,
108-
const struct rxrpc_security **_sec,
109-
struct key **_key,
110-
struct sk_buff *skb)
107+
const struct rxrpc_security *rxrpc_get_incoming_security(struct rxrpc_sock *rx,
108+
struct sk_buff *skb)
111109
{
112110
const struct rxrpc_security *sec;
113111
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
114-
key_ref_t kref = NULL;
115-
char kdesc[5 + 1 + 3 + 1];
116112

117113
_enter("");
118114

119-
sprintf(kdesc, "%u:%u", sp->hdr.serviceId, sp->hdr.securityIndex);
120-
121115
sec = rxrpc_security_lookup(sp->hdr.securityIndex);
122116
if (!sec) {
123117
trace_rxrpc_abort(0, "SVS",
124118
sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
125119
RX_INVALID_OPERATION, EKEYREJECTED);
126120
skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
127121
skb->priority = RX_INVALID_OPERATION;
128-
return false;
122+
return NULL;
129123
}
130124

131-
if (sp->hdr.securityIndex == RXRPC_SECURITY_NONE)
132-
goto out;
133-
134-
if (!rx->securities) {
125+
if (sp->hdr.securityIndex != RXRPC_SECURITY_NONE &&
126+
!rx->securities) {
135127
trace_rxrpc_abort(0, "SVR",
136128
sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
137129
RX_INVALID_OPERATION, EKEYREJECTED);
138130
skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
139-
skb->priority = RX_INVALID_OPERATION;
140-
return false;
131+
skb->priority = sec->no_key_abort;
132+
return NULL;
141133
}
142134

135+
return sec;
136+
}
137+
138+
/*
139+
* Find the security key for a server connection.
140+
*/
141+
struct key *rxrpc_look_up_server_security(struct rxrpc_connection *conn,
142+
struct sk_buff *skb,
143+
u32 kvno, u32 enctype)
144+
{
145+
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
146+
struct rxrpc_sock *rx;
147+
struct key *key = ERR_PTR(-EKEYREJECTED);
148+
key_ref_t kref = NULL;
149+
char kdesc[5 + 1 + 3 + 1 + 12 + 1 + 12 + 1];
150+
int ret;
151+
152+
_enter("");
153+
154+
if (enctype)
155+
sprintf(kdesc, "%u:%u:%u:%u",
156+
sp->hdr.serviceId, sp->hdr.securityIndex, kvno, enctype);
157+
else if (kvno)
158+
sprintf(kdesc, "%u:%u:%u",
159+
sp->hdr.serviceId, sp->hdr.securityIndex, kvno);
160+
else
161+
sprintf(kdesc, "%u:%u",
162+
sp->hdr.serviceId, sp->hdr.securityIndex);
163+
164+
rcu_read_lock();
165+
166+
rx = rcu_dereference(conn->params.local->service);
167+
if (!rx)
168+
goto out;
169+
143170
/* look through the service's keyring */
144171
kref = keyring_search(make_key_ref(rx->securities, 1UL),
145172
&key_type_rxrpc_s, kdesc, true);
146173
if (IS_ERR(kref)) {
147-
trace_rxrpc_abort(0, "SVK",
148-
sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
149-
sec->no_key_abort, EKEYREJECTED);
150-
skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
151-
skb->priority = sec->no_key_abort;
152-
return false;
174+
key = ERR_CAST(kref);
175+
goto out;
176+
}
177+
178+
key = key_ref_to_ptr(kref);
179+
180+
ret = key_validate(key);
181+
if (ret < 0) {
182+
key_put(key);
183+
key = ERR_PTR(ret);
184+
goto out;
153185
}
154186

155187
out:
156-
*_sec = sec;
157-
*_key = key_ref_to_ptr(kref);
158-
return true;
188+
rcu_read_unlock();
189+
return key;
159190
}

0 commit comments

Comments
 (0)