KEYS: RxRPC: Use key preparsing
Make use of key preparsing in the RxRPC protocol so that quota size determination can take place prior to keyring locking when a key is being added. Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: Steve Dickson <steved@redhat.com>
This commit is contained in:
parent
d46d494214
commit
8a7a3eb4dd
|
@ -26,8 +26,10 @@
|
||||||
#include "ar-internal.h"
|
#include "ar-internal.h"
|
||||||
|
|
||||||
static int rxrpc_vet_description_s(const char *);
|
static int rxrpc_vet_description_s(const char *);
|
||||||
static int rxrpc_instantiate(struct key *, struct key_preparsed_payload *);
|
static int rxrpc_preparse(struct key_preparsed_payload *);
|
||||||
static int rxrpc_instantiate_s(struct key *, struct key_preparsed_payload *);
|
static int rxrpc_preparse_s(struct key_preparsed_payload *);
|
||||||
|
static void rxrpc_free_preparse(struct key_preparsed_payload *);
|
||||||
|
static void rxrpc_free_preparse_s(struct key_preparsed_payload *);
|
||||||
static void rxrpc_destroy(struct key *);
|
static void rxrpc_destroy(struct key *);
|
||||||
static void rxrpc_destroy_s(struct key *);
|
static void rxrpc_destroy_s(struct key *);
|
||||||
static void rxrpc_describe(const struct key *, struct seq_file *);
|
static void rxrpc_describe(const struct key *, struct seq_file *);
|
||||||
|
@ -39,7 +41,9 @@ static long rxrpc_read(const struct key *, char __user *, size_t);
|
||||||
*/
|
*/
|
||||||
struct key_type key_type_rxrpc = {
|
struct key_type key_type_rxrpc = {
|
||||||
.name = "rxrpc",
|
.name = "rxrpc",
|
||||||
.instantiate = rxrpc_instantiate,
|
.preparse = rxrpc_preparse,
|
||||||
|
.free_preparse = rxrpc_free_preparse,
|
||||||
|
.instantiate = generic_key_instantiate,
|
||||||
.match = user_match,
|
.match = user_match,
|
||||||
.destroy = rxrpc_destroy,
|
.destroy = rxrpc_destroy,
|
||||||
.describe = rxrpc_describe,
|
.describe = rxrpc_describe,
|
||||||
|
@ -54,7 +58,9 @@ EXPORT_SYMBOL(key_type_rxrpc);
|
||||||
struct key_type key_type_rxrpc_s = {
|
struct key_type key_type_rxrpc_s = {
|
||||||
.name = "rxrpc_s",
|
.name = "rxrpc_s",
|
||||||
.vet_description = rxrpc_vet_description_s,
|
.vet_description = rxrpc_vet_description_s,
|
||||||
.instantiate = rxrpc_instantiate_s,
|
.preparse = rxrpc_preparse_s,
|
||||||
|
.free_preparse = rxrpc_free_preparse_s,
|
||||||
|
.instantiate = generic_key_instantiate,
|
||||||
.match = user_match,
|
.match = user_match,
|
||||||
.destroy = rxrpc_destroy_s,
|
.destroy = rxrpc_destroy_s,
|
||||||
.describe = rxrpc_describe,
|
.describe = rxrpc_describe,
|
||||||
|
@ -81,13 +87,13 @@ static int rxrpc_vet_description_s(const char *desc)
|
||||||
* parse an RxKAD type XDR format token
|
* parse an RxKAD type XDR format token
|
||||||
* - the caller guarantees we have at least 4 words
|
* - the caller guarantees we have at least 4 words
|
||||||
*/
|
*/
|
||||||
static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr,
|
static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep,
|
||||||
unsigned int toklen)
|
size_t datalen,
|
||||||
|
const __be32 *xdr, unsigned int toklen)
|
||||||
{
|
{
|
||||||
struct rxrpc_key_token *token, **pptoken;
|
struct rxrpc_key_token *token, **pptoken;
|
||||||
size_t plen;
|
size_t plen;
|
||||||
u32 tktlen;
|
u32 tktlen;
|
||||||
int ret;
|
|
||||||
|
|
||||||
_enter(",{%x,%x,%x,%x},%u",
|
_enter(",{%x,%x,%x,%x},%u",
|
||||||
ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
|
ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
|
||||||
|
@ -103,9 +109,7 @@ static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr,
|
||||||
return -EKEYREJECTED;
|
return -EKEYREJECTED;
|
||||||
|
|
||||||
plen = sizeof(*token) + sizeof(*token->kad) + tktlen;
|
plen = sizeof(*token) + sizeof(*token->kad) + tktlen;
|
||||||
ret = key_payload_reserve(key, key->datalen + plen);
|
prep->quotalen = datalen + plen;
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
plen -= sizeof(*token);
|
plen -= sizeof(*token);
|
||||||
token = kzalloc(sizeof(*token), GFP_KERNEL);
|
token = kzalloc(sizeof(*token), GFP_KERNEL);
|
||||||
|
@ -146,16 +150,16 @@ static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr,
|
||||||
token->kad->ticket[6], token->kad->ticket[7]);
|
token->kad->ticket[6], token->kad->ticket[7]);
|
||||||
|
|
||||||
/* count the number of tokens attached */
|
/* count the number of tokens attached */
|
||||||
key->type_data.x[0]++;
|
prep->type_data[0] = (void *)((unsigned long)prep->type_data[0] + 1);
|
||||||
|
|
||||||
/* attach the data */
|
/* attach the data */
|
||||||
for (pptoken = (struct rxrpc_key_token **)&key->payload.data;
|
for (pptoken = (struct rxrpc_key_token **)&prep->payload[0];
|
||||||
*pptoken;
|
*pptoken;
|
||||||
pptoken = &(*pptoken)->next)
|
pptoken = &(*pptoken)->next)
|
||||||
continue;
|
continue;
|
||||||
*pptoken = token;
|
*pptoken = token;
|
||||||
if (token->kad->expiry < key->expiry)
|
if (token->kad->expiry < prep->expiry)
|
||||||
key->expiry = token->kad->expiry;
|
prep->expiry = token->kad->expiry;
|
||||||
|
|
||||||
_leave(" = 0");
|
_leave(" = 0");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -418,8 +422,9 @@ static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen,
|
||||||
* parse an RxK5 type XDR format token
|
* parse an RxK5 type XDR format token
|
||||||
* - the caller guarantees we have at least 4 words
|
* - the caller guarantees we have at least 4 words
|
||||||
*/
|
*/
|
||||||
static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr,
|
static int rxrpc_preparse_xdr_rxk5(struct key_preparsed_payload *prep,
|
||||||
unsigned int toklen)
|
size_t datalen,
|
||||||
|
const __be32 *xdr, unsigned int toklen)
|
||||||
{
|
{
|
||||||
struct rxrpc_key_token *token, **pptoken;
|
struct rxrpc_key_token *token, **pptoken;
|
||||||
struct rxk5_key *rxk5;
|
struct rxk5_key *rxk5;
|
||||||
|
@ -432,9 +437,7 @@ static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr,
|
||||||
|
|
||||||
/* reserve some payload space for this subkey - the length of the token
|
/* reserve some payload space for this subkey - the length of the token
|
||||||
* is a reasonable approximation */
|
* is a reasonable approximation */
|
||||||
ret = key_payload_reserve(key, key->datalen + toklen);
|
prep->quotalen = datalen + toklen;
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
token = kzalloc(sizeof(*token), GFP_KERNEL);
|
token = kzalloc(sizeof(*token), GFP_KERNEL);
|
||||||
if (!token)
|
if (!token)
|
||||||
|
@ -520,14 +523,14 @@ static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr,
|
||||||
if (toklen != 0)
|
if (toklen != 0)
|
||||||
goto inval;
|
goto inval;
|
||||||
|
|
||||||
/* attach the payload to the key */
|
/* attach the payload */
|
||||||
for (pptoken = (struct rxrpc_key_token **)&key->payload.data;
|
for (pptoken = (struct rxrpc_key_token **)&prep->payload[0];
|
||||||
*pptoken;
|
*pptoken;
|
||||||
pptoken = &(*pptoken)->next)
|
pptoken = &(*pptoken)->next)
|
||||||
continue;
|
continue;
|
||||||
*pptoken = token;
|
*pptoken = token;
|
||||||
if (token->kad->expiry < key->expiry)
|
if (token->kad->expiry < prep->expiry)
|
||||||
key->expiry = token->kad->expiry;
|
prep->expiry = token->kad->expiry;
|
||||||
|
|
||||||
_leave(" = 0");
|
_leave(" = 0");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -545,16 +548,17 @@ error:
|
||||||
* attempt to parse the data as the XDR format
|
* attempt to parse the data as the XDR format
|
||||||
* - the caller guarantees we have more than 7 words
|
* - the caller guarantees we have more than 7 words
|
||||||
*/
|
*/
|
||||||
static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datalen)
|
static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep)
|
||||||
{
|
{
|
||||||
const __be32 *xdr = data, *token;
|
const __be32 *xdr = prep->data, *token;
|
||||||
const char *cp;
|
const char *cp;
|
||||||
unsigned int len, tmp, loop, ntoken, toklen, sec_ix;
|
unsigned int len, tmp, loop, ntoken, toklen, sec_ix;
|
||||||
|
size_t datalen = prep->datalen;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
_enter(",{%x,%x,%x,%x},%zu",
|
_enter(",{%x,%x,%x,%x},%zu",
|
||||||
ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
|
ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
|
||||||
datalen);
|
prep->datalen);
|
||||||
|
|
||||||
if (datalen > AFSTOKEN_LENGTH_MAX)
|
if (datalen > AFSTOKEN_LENGTH_MAX)
|
||||||
goto not_xdr;
|
goto not_xdr;
|
||||||
|
@ -635,13 +639,13 @@ static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datal
|
||||||
|
|
||||||
switch (sec_ix) {
|
switch (sec_ix) {
|
||||||
case RXRPC_SECURITY_RXKAD:
|
case RXRPC_SECURITY_RXKAD:
|
||||||
ret = rxrpc_instantiate_xdr_rxkad(key, xdr, toklen);
|
ret = rxrpc_preparse_xdr_rxkad(prep, datalen, xdr, toklen);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
goto error;
|
goto error;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RXRPC_SECURITY_RXK5:
|
case RXRPC_SECURITY_RXK5:
|
||||||
ret = rxrpc_instantiate_xdr_rxk5(key, xdr, toklen);
|
ret = rxrpc_preparse_xdr_rxk5(prep, datalen, xdr, toklen);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
goto error;
|
goto error;
|
||||||
break;
|
break;
|
||||||
|
@ -665,8 +669,9 @@ error:
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* instantiate an rxrpc defined key
|
* Preparse an rxrpc defined key.
|
||||||
* data should be of the form:
|
*
|
||||||
|
* Data should be of the form:
|
||||||
* OFFSET LEN CONTENT
|
* OFFSET LEN CONTENT
|
||||||
* 0 4 key interface version number
|
* 0 4 key interface version number
|
||||||
* 4 2 security index (type)
|
* 4 2 security index (type)
|
||||||
|
@ -678,7 +683,7 @@ error:
|
||||||
*
|
*
|
||||||
* if no data is provided, then a no-security key is made
|
* if no data is provided, then a no-security key is made
|
||||||
*/
|
*/
|
||||||
static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep)
|
static int rxrpc_preparse(struct key_preparsed_payload *prep)
|
||||||
{
|
{
|
||||||
const struct rxrpc_key_data_v1 *v1;
|
const struct rxrpc_key_data_v1 *v1;
|
||||||
struct rxrpc_key_token *token, **pp;
|
struct rxrpc_key_token *token, **pp;
|
||||||
|
@ -686,7 +691,7 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep
|
||||||
u32 kver;
|
u32 kver;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
_enter("{%x},,%zu", key_serial(key), prep->datalen);
|
_enter("%zu", prep->datalen);
|
||||||
|
|
||||||
/* handle a no-security key */
|
/* handle a no-security key */
|
||||||
if (!prep->data && prep->datalen == 0)
|
if (!prep->data && prep->datalen == 0)
|
||||||
|
@ -694,7 +699,7 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep
|
||||||
|
|
||||||
/* determine if the XDR payload format is being used */
|
/* determine if the XDR payload format is being used */
|
||||||
if (prep->datalen > 7 * 4) {
|
if (prep->datalen > 7 * 4) {
|
||||||
ret = rxrpc_instantiate_xdr(key, prep->data, prep->datalen);
|
ret = rxrpc_preparse_xdr(prep);
|
||||||
if (ret != -EPROTO)
|
if (ret != -EPROTO)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -743,9 +748,7 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
plen = sizeof(*token->kad) + v1->ticket_length;
|
plen = sizeof(*token->kad) + v1->ticket_length;
|
||||||
ret = key_payload_reserve(key, plen + sizeof(*token));
|
prep->quotalen = plen + sizeof(*token);
|
||||||
if (ret < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
token = kzalloc(sizeof(*token), GFP_KERNEL);
|
token = kzalloc(sizeof(*token), GFP_KERNEL);
|
||||||
|
@ -762,15 +765,16 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep
|
||||||
memcpy(&token->kad->session_key, &v1->session_key, 8);
|
memcpy(&token->kad->session_key, &v1->session_key, 8);
|
||||||
memcpy(&token->kad->ticket, v1->ticket, v1->ticket_length);
|
memcpy(&token->kad->ticket, v1->ticket, v1->ticket_length);
|
||||||
|
|
||||||
/* attach the data */
|
/* count the number of tokens attached */
|
||||||
key->type_data.x[0]++;
|
prep->type_data[0] = (void *)((unsigned long)prep->type_data[0] + 1);
|
||||||
|
|
||||||
pp = (struct rxrpc_key_token **)&key->payload.data;
|
/* attach the data */
|
||||||
|
pp = (struct rxrpc_key_token **)&prep->payload[0];
|
||||||
while (*pp)
|
while (*pp)
|
||||||
pp = &(*pp)->next;
|
pp = &(*pp)->next;
|
||||||
*pp = token;
|
*pp = token;
|
||||||
if (token->kad->expiry < key->expiry)
|
if (token->kad->expiry < prep->expiry)
|
||||||
key->expiry = token->kad->expiry;
|
prep->expiry = token->kad->expiry;
|
||||||
token = NULL;
|
token = NULL;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
|
@ -781,44 +785,14 @@ error:
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* instantiate a server secret key
|
* Free token list.
|
||||||
* data should be a pointer to the 8-byte secret key
|
|
||||||
*/
|
*/
|
||||||
static int rxrpc_instantiate_s(struct key *key,
|
static void rxrpc_free_token_list(struct rxrpc_key_token *token)
|
||||||
struct key_preparsed_payload *prep)
|
|
||||||
{
|
{
|
||||||
struct crypto_blkcipher *ci;
|
struct rxrpc_key_token *next;
|
||||||
|
|
||||||
_enter("{%x},,%zu", key_serial(key), prep->datalen);
|
for (; token; token = next) {
|
||||||
|
next = token->next;
|
||||||
if (prep->datalen != 8)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
memcpy(&key->type_data, prep->data, 8);
|
|
||||||
|
|
||||||
ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC);
|
|
||||||
if (IS_ERR(ci)) {
|
|
||||||
_leave(" = %ld", PTR_ERR(ci));
|
|
||||||
return PTR_ERR(ci);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0)
|
|
||||||
BUG();
|
|
||||||
|
|
||||||
key->payload.data = ci;
|
|
||||||
_leave(" = 0");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* dispose of the data dangling from the corpse of a rxrpc key
|
|
||||||
*/
|
|
||||||
static void rxrpc_destroy(struct key *key)
|
|
||||||
{
|
|
||||||
struct rxrpc_key_token *token;
|
|
||||||
|
|
||||||
while ((token = key->payload.data)) {
|
|
||||||
key->payload.data = token->next;
|
|
||||||
switch (token->security_index) {
|
switch (token->security_index) {
|
||||||
case RXRPC_SECURITY_RXKAD:
|
case RXRPC_SECURITY_RXKAD:
|
||||||
kfree(token->kad);
|
kfree(token->kad);
|
||||||
|
@ -837,6 +811,61 @@ static void rxrpc_destroy(struct key *key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clean up preparse data.
|
||||||
|
*/
|
||||||
|
static void rxrpc_free_preparse(struct key_preparsed_payload *prep)
|
||||||
|
{
|
||||||
|
rxrpc_free_token_list(prep->payload[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Preparse a server secret key.
|
||||||
|
*
|
||||||
|
* The data should be the 8-byte secret key.
|
||||||
|
*/
|
||||||
|
static int rxrpc_preparse_s(struct key_preparsed_payload *prep)
|
||||||
|
{
|
||||||
|
struct crypto_blkcipher *ci;
|
||||||
|
|
||||||
|
_enter("%zu", prep->datalen);
|
||||||
|
|
||||||
|
if (prep->datalen != 8)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
memcpy(&prep->type_data, prep->data, 8);
|
||||||
|
|
||||||
|
ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC);
|
||||||
|
if (IS_ERR(ci)) {
|
||||||
|
_leave(" = %ld", PTR_ERR(ci));
|
||||||
|
return PTR_ERR(ci);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0)
|
||||||
|
BUG();
|
||||||
|
|
||||||
|
prep->payload[0] = ci;
|
||||||
|
_leave(" = 0");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clean up preparse data.
|
||||||
|
*/
|
||||||
|
static void rxrpc_free_preparse_s(struct key_preparsed_payload *prep)
|
||||||
|
{
|
||||||
|
if (prep->payload[0])
|
||||||
|
crypto_free_blkcipher(prep->payload[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dispose of the data dangling from the corpse of a rxrpc key
|
||||||
|
*/
|
||||||
|
static void rxrpc_destroy(struct key *key)
|
||||||
|
{
|
||||||
|
rxrpc_free_token_list(key->payload.data);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* dispose of the data dangling from the corpse of a rxrpc key
|
* dispose of the data dangling from the corpse of a rxrpc key
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue