mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 12:43:29 +02:00
rxrpc: Ask the security class how much space to allow in a packet
Ask the security class how much header and trailer space to allow for when allocating a packet, given how much data is remaining. This will allow the rxgk security class to stick both a trailer in as well as a header as appropriate in the future. Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
@@ -234,6 +234,11 @@ struct rxrpc_security {
|
|||||||
int (*init_connection_security)(struct rxrpc_connection *,
|
int (*init_connection_security)(struct rxrpc_connection *,
|
||||||
struct rxrpc_key_token *);
|
struct rxrpc_key_token *);
|
||||||
|
|
||||||
|
/* Work out how much data we can store in a packet, given an estimate
|
||||||
|
* of the amount of data remaining.
|
||||||
|
*/
|
||||||
|
int (*how_much_data)(struct rxrpc_call *, size_t,
|
||||||
|
size_t *, size_t *, size_t *);
|
||||||
|
|
||||||
/* impose security on a packet */
|
/* impose security on a packet */
|
||||||
int (*secure_packet)(struct rxrpc_call *, struct sk_buff *, size_t);
|
int (*secure_packet)(struct rxrpc_call *, struct sk_buff *, size_t);
|
||||||
@@ -467,8 +472,6 @@ struct rxrpc_connection {
|
|||||||
atomic_t serial; /* packet serial number counter */
|
atomic_t serial; /* packet serial number counter */
|
||||||
unsigned int hi_serial; /* highest serial number received */
|
unsigned int hi_serial; /* highest serial number received */
|
||||||
u32 service_id; /* Service ID, possibly upgraded */
|
u32 service_id; /* Service ID, possibly upgraded */
|
||||||
u8 size_align; /* data size alignment (for security) */
|
|
||||||
u8 security_size; /* security header size */
|
|
||||||
u8 security_ix; /* security type */
|
u8 security_ix; /* security type */
|
||||||
u8 out_clientflag; /* RXRPC_CLIENT_INITIATED if we are client */
|
u8 out_clientflag; /* RXRPC_CLIENT_INITIATED if we are client */
|
||||||
u8 bundle_shift; /* Index into bundle->avail_chans */
|
u8 bundle_shift; /* Index into bundle->avail_chans */
|
||||||
|
@@ -49,7 +49,6 @@ struct rxrpc_connection *rxrpc_alloc_connection(gfp_t gfp)
|
|||||||
conn->security = &rxrpc_no_security;
|
conn->security = &rxrpc_no_security;
|
||||||
spin_lock_init(&conn->state_lock);
|
spin_lock_init(&conn->state_lock);
|
||||||
conn->debug_id = atomic_inc_return(&rxrpc_debug_id);
|
conn->debug_id = atomic_inc_return(&rxrpc_debug_id);
|
||||||
conn->size_align = 4;
|
|
||||||
conn->idle_timestamp = jiffies;
|
conn->idle_timestamp = jiffies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -14,6 +14,17 @@ static int none_init_connection_security(struct rxrpc_connection *conn,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Work out how much data we can put in an unsecured packet.
|
||||||
|
*/
|
||||||
|
static int none_how_much_data(struct rxrpc_call *call, size_t remain,
|
||||||
|
size_t *_buf_size, size_t *_data_size, size_t *_offset)
|
||||||
|
{
|
||||||
|
*_buf_size = *_data_size = min_t(size_t, remain, RXRPC_JUMBO_DATALEN);
|
||||||
|
*_offset = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int none_secure_packet(struct rxrpc_call *call, struct sk_buff *skb,
|
static int none_secure_packet(struct rxrpc_call *call, struct sk_buff *skb,
|
||||||
size_t data_size)
|
size_t data_size)
|
||||||
{
|
{
|
||||||
@@ -81,6 +92,7 @@ const struct rxrpc_security rxrpc_no_security = {
|
|||||||
.exit = none_exit,
|
.exit = none_exit,
|
||||||
.init_connection_security = none_init_connection_security,
|
.init_connection_security = none_init_connection_security,
|
||||||
.free_call_crypto = none_free_call_crypto,
|
.free_call_crypto = none_free_call_crypto,
|
||||||
|
.how_much_data = none_how_much_data,
|
||||||
.secure_packet = none_secure_packet,
|
.secure_packet = none_secure_packet,
|
||||||
.verify_packet = none_verify_packet,
|
.verify_packet = none_verify_packet,
|
||||||
.locate_data = none_locate_data,
|
.locate_data = none_locate_data,
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
#define INST_SZ 40 /* size of principal's instance */
|
#define INST_SZ 40 /* size of principal's instance */
|
||||||
#define REALM_SZ 40 /* size of principal's auth domain */
|
#define REALM_SZ 40 /* size of principal's auth domain */
|
||||||
#define SNAME_SZ 40 /* size of service name */
|
#define SNAME_SZ 40 /* size of service name */
|
||||||
|
#define RXKAD_ALIGN 8
|
||||||
|
|
||||||
struct rxkad_level1_hdr {
|
struct rxkad_level1_hdr {
|
||||||
__be32 data_size; /* true data size (excluding padding) */
|
__be32 data_size; /* true data size (excluding padding) */
|
||||||
@@ -80,7 +81,7 @@ static int rxkad_preparse_server_key(struct key_preparsed_payload *prep)
|
|||||||
|
|
||||||
static void rxkad_free_preparse_server_key(struct key_preparsed_payload *prep)
|
static void rxkad_free_preparse_server_key(struct key_preparsed_payload *prep)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (prep->payload.data[0])
|
if (prep->payload.data[0])
|
||||||
crypto_free_skcipher(prep->payload.data[0]);
|
crypto_free_skcipher(prep->payload.data[0]);
|
||||||
}
|
}
|
||||||
@@ -119,14 +120,8 @@ static int rxkad_init_connection_security(struct rxrpc_connection *conn,
|
|||||||
|
|
||||||
switch (conn->params.security_level) {
|
switch (conn->params.security_level) {
|
||||||
case RXRPC_SECURITY_PLAIN:
|
case RXRPC_SECURITY_PLAIN:
|
||||||
break;
|
|
||||||
case RXRPC_SECURITY_AUTH:
|
case RXRPC_SECURITY_AUTH:
|
||||||
conn->size_align = 8;
|
|
||||||
conn->security_size = sizeof(struct rxkad_level1_hdr);
|
|
||||||
break;
|
|
||||||
case RXRPC_SECURITY_ENCRYPT:
|
case RXRPC_SECURITY_ENCRYPT:
|
||||||
conn->size_align = 8;
|
|
||||||
conn->security_size = sizeof(struct rxkad_level2_hdr);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -EKEYREJECTED;
|
ret = -EKEYREJECTED;
|
||||||
@@ -147,6 +142,40 @@ error:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Work out how much data we can put in a packet.
|
||||||
|
*/
|
||||||
|
static int rxkad_how_much_data(struct rxrpc_call *call, size_t remain,
|
||||||
|
size_t *_buf_size, size_t *_data_size, size_t *_offset)
|
||||||
|
{
|
||||||
|
size_t shdr, buf_size, chunk;
|
||||||
|
|
||||||
|
switch (call->conn->params.security_level) {
|
||||||
|
default:
|
||||||
|
buf_size = chunk = min_t(size_t, remain, RXRPC_JUMBO_DATALEN);
|
||||||
|
shdr = 0;
|
||||||
|
goto out;
|
||||||
|
case RXRPC_SECURITY_AUTH:
|
||||||
|
shdr = sizeof(struct rxkad_level1_hdr);
|
||||||
|
break;
|
||||||
|
case RXRPC_SECURITY_ENCRYPT:
|
||||||
|
shdr = sizeof(struct rxkad_level2_hdr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf_size = round_down(RXRPC_JUMBO_DATALEN, RXKAD_ALIGN);
|
||||||
|
|
||||||
|
chunk = buf_size - shdr;
|
||||||
|
if (remain < chunk)
|
||||||
|
buf_size = round_up(shdr + remain, RXKAD_ALIGN);
|
||||||
|
|
||||||
|
out:
|
||||||
|
*_buf_size = buf_size;
|
||||||
|
*_data_size = chunk;
|
||||||
|
*_offset = shdr;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* prime the encryption state with the invariant parts of a connection's
|
* prime the encryption state with the invariant parts of a connection's
|
||||||
* description
|
* description
|
||||||
@@ -237,6 +266,7 @@ static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
|
|||||||
struct rxkad_level1_hdr hdr;
|
struct rxkad_level1_hdr hdr;
|
||||||
struct rxrpc_crypt iv;
|
struct rxrpc_crypt iv;
|
||||||
struct scatterlist sg;
|
struct scatterlist sg;
|
||||||
|
size_t pad;
|
||||||
u16 check;
|
u16 check;
|
||||||
|
|
||||||
_enter("");
|
_enter("");
|
||||||
@@ -247,6 +277,12 @@ static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
|
|||||||
hdr.data_size = htonl(data_size);
|
hdr.data_size = htonl(data_size);
|
||||||
memcpy(skb->head, &hdr, sizeof(hdr));
|
memcpy(skb->head, &hdr, sizeof(hdr));
|
||||||
|
|
||||||
|
pad = sizeof(struct rxkad_level1_hdr) + data_size;
|
||||||
|
pad = RXKAD_ALIGN - pad;
|
||||||
|
pad &= RXKAD_ALIGN - 1;
|
||||||
|
if (pad)
|
||||||
|
skb_put_zero(skb, pad);
|
||||||
|
|
||||||
/* start the encryption afresh */
|
/* start the encryption afresh */
|
||||||
memset(&iv, 0, sizeof(iv));
|
memset(&iv, 0, sizeof(iv));
|
||||||
|
|
||||||
@@ -275,6 +311,7 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
|
|||||||
struct rxrpc_crypt iv;
|
struct rxrpc_crypt iv;
|
||||||
struct scatterlist sg[16];
|
struct scatterlist sg[16];
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
|
size_t pad;
|
||||||
u16 check;
|
u16 check;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@@ -288,6 +325,12 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
|
|||||||
rxkhdr.checksum = 0;
|
rxkhdr.checksum = 0;
|
||||||
memcpy(skb->head, &rxkhdr, sizeof(rxkhdr));
|
memcpy(skb->head, &rxkhdr, sizeof(rxkhdr));
|
||||||
|
|
||||||
|
pad = sizeof(struct rxkad_level2_hdr) + data_size;
|
||||||
|
pad = RXKAD_ALIGN - pad;
|
||||||
|
pad &= RXKAD_ALIGN - 1;
|
||||||
|
if (pad)
|
||||||
|
skb_put_zero(skb, pad);
|
||||||
|
|
||||||
/* encrypt from the session key */
|
/* encrypt from the session key */
|
||||||
token = call->conn->params.key->payload.data[0];
|
token = call->conn->params.key->payload.data[0];
|
||||||
memcpy(&iv, token->kad->session_key, sizeof(iv));
|
memcpy(&iv, token->kad->session_key, sizeof(iv));
|
||||||
@@ -303,8 +346,7 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
|
|||||||
if (skb_shinfo(skb)->nr_frags > 16)
|
if (skb_shinfo(skb)->nr_frags > 16)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
len = data_size + call->conn->size_align - 1;
|
len = round_up(data_size, RXKAD_ALIGN);
|
||||||
len &= ~(call->conn->size_align - 1);
|
|
||||||
|
|
||||||
sg_init_table(sg, ARRAY_SIZE(sg));
|
sg_init_table(sg, ARRAY_SIZE(sg));
|
||||||
err = skb_to_sgvec(skb, sg, 8, len);
|
err = skb_to_sgvec(skb, sg, 8, len);
|
||||||
@@ -1353,6 +1395,7 @@ const struct rxrpc_security rxkad = {
|
|||||||
.free_preparse_server_key = rxkad_free_preparse_server_key,
|
.free_preparse_server_key = rxkad_free_preparse_server_key,
|
||||||
.destroy_server_key = rxkad_destroy_server_key,
|
.destroy_server_key = rxkad_destroy_server_key,
|
||||||
.init_connection_security = rxkad_init_connection_security,
|
.init_connection_security = rxkad_init_connection_security,
|
||||||
|
.how_much_data = rxkad_how_much_data,
|
||||||
.secure_packet = rxkad_secure_packet,
|
.secure_packet = rxkad_secure_packet,
|
||||||
.verify_packet = rxkad_verify_packet,
|
.verify_packet = rxkad_verify_packet,
|
||||||
.free_call_crypto = rxkad_free_call_crypto,
|
.free_call_crypto = rxkad_free_call_crypto,
|
||||||
|
@@ -327,7 +327,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
|
|||||||
rxrpc_send_ack_packet(call, false, NULL);
|
rxrpc_send_ack_packet(call, false, NULL);
|
||||||
|
|
||||||
if (!skb) {
|
if (!skb) {
|
||||||
size_t size, chunk, max, space;
|
size_t remain, bufsize, chunk, offset;
|
||||||
|
|
||||||
_debug("alloc");
|
_debug("alloc");
|
||||||
|
|
||||||
@@ -342,24 +342,21 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
|
|||||||
goto maybe_error;
|
goto maybe_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
max = RXRPC_JUMBO_DATALEN;
|
/* Work out the maximum size of a packet. Assume that
|
||||||
max -= call->conn->security_size;
|
* the security header is going to be in the padded
|
||||||
max &= ~(call->conn->size_align - 1UL);
|
* region (enc blocksize), but the trailer is not.
|
||||||
|
*/
|
||||||
|
remain = more ? INT_MAX : msg_data_left(msg);
|
||||||
|
ret = call->conn->security->how_much_data(call, remain,
|
||||||
|
&bufsize, &chunk, &offset);
|
||||||
|
if (ret < 0)
|
||||||
|
goto maybe_error;
|
||||||
|
|
||||||
chunk = max;
|
_debug("SIZE: %zu/%zu @%zu", chunk, bufsize, offset);
|
||||||
if (chunk > msg_data_left(msg) && !more)
|
|
||||||
chunk = msg_data_left(msg);
|
|
||||||
|
|
||||||
space = chunk + call->conn->size_align;
|
|
||||||
space &= ~(call->conn->size_align - 1UL);
|
|
||||||
|
|
||||||
size = space + call->conn->security_size;
|
|
||||||
|
|
||||||
_debug("SIZE: %zu/%zu/%zu", chunk, space, size);
|
|
||||||
|
|
||||||
/* create a buffer that we can retain until it's ACK'd */
|
/* create a buffer that we can retain until it's ACK'd */
|
||||||
skb = sock_alloc_send_skb(
|
skb = sock_alloc_send_skb(
|
||||||
sk, size, msg->msg_flags & MSG_DONTWAIT, &ret);
|
sk, bufsize, msg->msg_flags & MSG_DONTWAIT, &ret);
|
||||||
if (!skb)
|
if (!skb)
|
||||||
goto maybe_error;
|
goto maybe_error;
|
||||||
|
|
||||||
@@ -371,8 +368,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
|
|||||||
|
|
||||||
ASSERTCMP(skb->mark, ==, 0);
|
ASSERTCMP(skb->mark, ==, 0);
|
||||||
|
|
||||||
_debug("HS: %u", call->conn->security_size);
|
__skb_put(skb, offset);
|
||||||
__skb_put(skb, call->conn->security_size);
|
|
||||||
|
|
||||||
sp->remain = chunk;
|
sp->remain = chunk;
|
||||||
if (sp->remain > skb_tailroom(skb))
|
if (sp->remain > skb_tailroom(skb))
|
||||||
@@ -421,17 +417,6 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
|
|||||||
(msg_data_left(msg) == 0 && !more)) {
|
(msg_data_left(msg) == 0 && !more)) {
|
||||||
struct rxrpc_connection *conn = call->conn;
|
struct rxrpc_connection *conn = call->conn;
|
||||||
uint32_t seq;
|
uint32_t seq;
|
||||||
size_t pad;
|
|
||||||
|
|
||||||
/* pad out if we're using security */
|
|
||||||
if (conn->security_ix) {
|
|
||||||
pad = conn->security_size + skb->mark;
|
|
||||||
pad = conn->size_align - pad;
|
|
||||||
pad &= conn->size_align - 1;
|
|
||||||
_debug("pad %zu", pad);
|
|
||||||
if (pad)
|
|
||||||
skb_put_zero(skb, pad);
|
|
||||||
}
|
|
||||||
|
|
||||||
seq = call->tx_top + 1;
|
seq = call->tx_top + 1;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user