Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ef68622d authored by David Howells's avatar David Howells
Browse files

rxrpc: Handle temporary errors better in rxkad security

In the rxkad security module, when we encounter a temporary error (such as
ENOMEM) from which we could conceivably recover, don't abort the
connection, but rather permit retransmission of the relevant packets to
induce a retry.

Note that I'm leaving some places that could be merged together to insert
tracing in the next patch.

Signed-off-by; David Howells <dhowells@redhat.com>
parent 84a4c09c
Loading
Loading
Loading
Loading
+40 −38
Original line number Original line Diff line number Diff line
@@ -759,16 +759,14 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn,


	_enter("{%d,%x}", conn->debug_id, key_serial(conn->params.key));
	_enter("{%d,%x}", conn->debug_id, key_serial(conn->params.key));


	if (!conn->params.key) {
	abort_code = RX_PROTOCOL_ERROR;
		_leave(" = -EPROTO [no key]");
	if (!conn->params.key)
		return -EPROTO;
		goto protocol_error;
	}


	abort_code = RXKADEXPIRED;
	ret = key_validate(conn->params.key);
	ret = key_validate(conn->params.key);
	if (ret < 0) {
	if (ret < 0)
		*_abort_code = RXKADEXPIRED;
		goto other_error;
		return ret;
	}


	abort_code = RXKADPACKETSHORT;
	abort_code = RXKADPACKETSHORT;
	if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
	if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
@@ -787,8 +785,9 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn,
		goto protocol_error;
		goto protocol_error;


	abort_code = RXKADLEVELFAIL;
	abort_code = RXKADLEVELFAIL;
	ret = -EACCES;
	if (conn->params.security_level < min_level)
	if (conn->params.security_level < min_level)
		goto protocol_error;
		goto other_error;


	token = conn->params.key->payload.data[0];
	token = conn->params.key->payload.data[0];


@@ -815,9 +814,10 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn,
	return rxkad_send_response(conn, &sp->hdr, &resp, token->kad);
	return rxkad_send_response(conn, &sp->hdr, &resp, token->kad);


protocol_error:
protocol_error:
	ret = -EPROTO;
other_error:
	*_abort_code = abort_code;
	*_abort_code = abort_code;
	_leave(" = -EPROTO [%d]", abort_code);
	return ret;
	return -EPROTO;
}
}


/*
/*
@@ -848,10 +848,10 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
		switch (ret) {
		switch (ret) {
		case -EKEYEXPIRED:
		case -EKEYEXPIRED:
			*_abort_code = RXKADEXPIRED;
			*_abort_code = RXKADEXPIRED;
			goto error;
			goto other_error;
		default:
		default:
			*_abort_code = RXKADNOAUTH;
			*_abort_code = RXKADNOAUTH;
			goto error;
			goto other_error;
		}
		}
	}
	}


@@ -860,13 +860,11 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,


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


	ret = -ENOMEM;
	req = skcipher_request_alloc(conn->server_key->payload.data[0],
	req = skcipher_request_alloc(conn->server_key->payload.data[0],
				     GFP_NOFS);
				     GFP_NOFS);
	if (!req) {
	if (!req)
		*_abort_code = RXKADNOAUTH;
		goto temporary_error;
		ret = -ENOMEM;
		goto error;
	}


	sg_init_one(&sg[0], ticket, ticket_len);
	sg_init_one(&sg[0], ticket, ticket_len);
	skcipher_request_set_callback(req, 0, NULL, NULL);
	skcipher_request_set_callback(req, 0, NULL, NULL);
@@ -943,13 +941,13 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
	if (issue > now) {
	if (issue > now) {
		*_abort_code = RXKADNOAUTH;
		*_abort_code = RXKADNOAUTH;
		ret = -EKEYREJECTED;
		ret = -EKEYREJECTED;
		goto error;
		goto other_error;
	}
	}


	if (issue < now - life) {
	if (issue < now - life) {
		*_abort_code = RXKADEXPIRED;
		*_abort_code = RXKADEXPIRED;
		ret = -EKEYEXPIRED;
		ret = -EKEYEXPIRED;
		goto error;
		goto other_error;
	}
	}


	*_expiry = issue + life;
	*_expiry = issue + life;
@@ -961,16 +959,15 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
	/* get the service instance name */
	/* get the service instance name */
	name = Z(INST_SZ);
	name = Z(INST_SZ);
	_debug("KIV SINST: %s", name);
	_debug("KIV SINST: %s", name);

	return 0;
	ret = 0;
error:
	_leave(" = %d", ret);
	return ret;


bad_ticket:
bad_ticket:
	*_abort_code = RXKADBADTICKET;
	*_abort_code = RXKADBADTICKET;
	ret = -EBADMSG;
	ret = -EPROTO;
	goto error;
other_error:
	return ret;
temporary_error:
	return ret;
}
}


/*
/*
@@ -1054,9 +1051,10 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
		goto protocol_error;
		goto protocol_error;


	/* extract the kerberos ticket and decrypt and decode it */
	/* extract the kerberos ticket and decrypt and decode it */
	ret = -ENOMEM;
	ticket = kmalloc(ticket_len, GFP_NOFS);
	ticket = kmalloc(ticket_len, GFP_NOFS);
	if (!ticket)
	if (!ticket)
		return -ENOMEM;
		goto temporary_error;


	abort_code = RXKADPACKETSHORT;
	abort_code = RXKADPACKETSHORT;
	if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
	if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
@@ -1064,12 +1062,9 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
		goto protocol_error_free;
		goto protocol_error_free;


	ret = rxkad_decrypt_ticket(conn, ticket, ticket_len, &session_key,
	ret = rxkad_decrypt_ticket(conn, ticket, ticket_len, &session_key,
				   &expiry, &abort_code);
				   &expiry, _abort_code);
	if (ret < 0) {
	if (ret < 0)
		*_abort_code = abort_code;
		goto temporary_error_free;
		kfree(ticket);
		return ret;
	}


	/* use the session key from inside the ticket to decrypt the
	/* use the session key from inside the ticket to decrypt the
	 * response */
	 * response */
@@ -1123,10 +1118,8 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
	 * this the connection security can be handled in exactly the same way
	 * this the connection security can be handled in exactly the same way
	 * as for a client connection */
	 * as for a client connection */
	ret = rxrpc_get_server_data_key(conn, &session_key, expiry, kvno);
	ret = rxrpc_get_server_data_key(conn, &session_key, expiry, kvno);
	if (ret < 0) {
	if (ret < 0)
		kfree(ticket);
		goto temporary_error_free;
		return ret;
	}


	kfree(ticket);
	kfree(ticket);
	_leave(" = 0");
	_leave(" = 0");
@@ -1140,6 +1133,15 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
	*_abort_code = abort_code;
	*_abort_code = abort_code;
	_leave(" = -EPROTO [%d]", abort_code);
	_leave(" = -EPROTO [%d]", abort_code);
	return -EPROTO;
	return -EPROTO;

temporary_error_free:
	kfree(ticket);
temporary_error:
	/* Ignore the response packet if we got a temporary error such as
	 * ENOMEM.  We just want to send the challenge again.  Note that we
	 * also come out this way if the ticket decryption fails.
	 */
	return ret;
}
}


/*
/*