Handle encrypt of arbitarily fragmented mbuf chains: previously
we bailed if we couldn't collect the 16-bytes of data required for an aes block cipher in 2 mbufs; now we deal with it. While here make space accounting signed so a sanity check does the right thing for malformed mbuf chains. Approved by: re (scottl)
This commit is contained in:
parent
e1d30f6c56
commit
097175bde2
@ -401,11 +401,10 @@ ccmp_encrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
|
||||
struct ccmp_ctx *ctx = key->wk_private;
|
||||
struct ieee80211_frame *wh;
|
||||
struct mbuf *m = m0;
|
||||
int data_len, i;
|
||||
int data_len, i, space;
|
||||
uint8_t aad[2 * AES_BLOCK_LEN], b0[AES_BLOCK_LEN], b[AES_BLOCK_LEN],
|
||||
e[AES_BLOCK_LEN], s0[AES_BLOCK_LEN];
|
||||
uint8_t *pos;
|
||||
u_int space;
|
||||
|
||||
ctx->cc_ic->ic_stats.is_crypto_ccmp++;
|
||||
|
||||
@ -444,27 +443,75 @@ ccmp_encrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
|
||||
}
|
||||
if (space != 0) {
|
||||
uint8_t *pos_next;
|
||||
u_int space_next;
|
||||
u_int len;
|
||||
int space_next;
|
||||
int len, dl, sp;
|
||||
struct mbuf *n;
|
||||
|
||||
/*
|
||||
* Block straddles buffers, split references. We
|
||||
* do not handle splits that require >2 buffers.
|
||||
* Block straddles one or more mbufs, gather data
|
||||
* into the block buffer b, apply the cipher, then
|
||||
* scatter the results back into the mbuf chain.
|
||||
* The buffer will automatically get space bytes
|
||||
* of data at offset 0 copied in+out by the
|
||||
* CCMP_ENCRYPT request so we must take care of
|
||||
* the remaining data.
|
||||
*/
|
||||
pos_next = mtod(m, uint8_t *);
|
||||
len = min(data_len, AES_BLOCK_LEN);
|
||||
space_next = len > space ? len - space : 0;
|
||||
KASSERT(m->m_len >= space_next,
|
||||
("not enough data in following buffer, "
|
||||
"m_len %u need %u\n", m->m_len, space_next));
|
||||
n = m;
|
||||
dl = data_len;
|
||||
sp = space;
|
||||
for (;;) {
|
||||
pos_next = mtod(n, uint8_t *);
|
||||
len = min(dl, AES_BLOCK_LEN);
|
||||
space_next = len > sp ? len - sp : 0;
|
||||
if (n->m_len >= space_next) {
|
||||
/*
|
||||
* This mbuf has enough data; just grab
|
||||
* what we need and stop.
|
||||
*/
|
||||
xor_block(b+sp, pos_next, space_next);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* This mbuf's contents are insufficient,
|
||||
* take 'em all and prepare to advance to
|
||||
* the next mbuf.
|
||||
*/
|
||||
xor_block(b+sp, pos_next, n->m_len);
|
||||
sp += n->m_len, dl -= n->m_len;
|
||||
n = n->m_next;
|
||||
if (n == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
xor_block(b+space, pos_next, space_next);
|
||||
CCMP_ENCRYPT(i, b, b0, pos, e, space);
|
||||
xor_block(pos_next, e+space, space_next);
|
||||
data_len -= len;
|
||||
/* XXX could check for data_len <= 0 */
|
||||
i++;
|
||||
|
||||
/* NB: just like above, but scatter data to mbufs */
|
||||
dl = data_len;
|
||||
sp = space;
|
||||
for (;;) {
|
||||
pos_next = mtod(m, uint8_t *);
|
||||
len = min(dl, AES_BLOCK_LEN);
|
||||
space_next = len > sp ? len - sp : 0;
|
||||
if (m->m_len >= space_next) {
|
||||
xor_block(pos_next, e+sp, space_next);
|
||||
break;
|
||||
}
|
||||
xor_block(pos_next, e+sp, m->m_len);
|
||||
sp += m->m_len, dl -= m->m_len;
|
||||
m = m->m_next;
|
||||
if (m == NULL)
|
||||
goto done;
|
||||
}
|
||||
/*
|
||||
* Do bookkeeping. m now points to the last mbuf
|
||||
* we grabbed data from. We know we consumed a
|
||||
* full block of data as otherwise we'd have hit
|
||||
* the end of the mbuf chain, so deduct from data_len.
|
||||
* Otherwise advance the block number (i) and setup
|
||||
* pos+space to reflect contents of the new mbuf.
|
||||
*/
|
||||
data_len -= AES_BLOCK_LEN;
|
||||
i++;
|
||||
pos = pos_next + space_next;
|
||||
space = m->m_len - space_next;
|
||||
} else {
|
||||
@ -475,6 +522,7 @@ ccmp_encrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
|
||||
space = m->m_len;
|
||||
}
|
||||
}
|
||||
done:
|
||||
/* tack on MIC */
|
||||
xor_block(b, s0, ccmp.ic_trailer);
|
||||
return m_append(m0, ccmp.ic_trailer, b);
|
||||
@ -540,7 +588,9 @@ ccmp_decrypt(struct ieee80211_key *key, u_int64_t pn, struct mbuf *m, int hdrlen
|
||||
|
||||
/*
|
||||
* Block straddles buffers, split references. We
|
||||
* do not handle splits that require >2 buffers.
|
||||
* do not handle splits that require >2 buffers
|
||||
* since rx'd frames are never badly fragmented
|
||||
* because drivers typically recv in clusters.
|
||||
*/
|
||||
pos_next = mtod(m, uint8_t *);
|
||||
len = min(data_len, AES_BLOCK_LEN);
|
||||
|
Loading…
Reference in New Issue
Block a user