Skip to content

Commit

Permalink
tls: cap the output scatter list to something reasonable
Browse files Browse the repository at this point in the history
TLS recvmsg() passes user pages as destination for decrypt.
The decrypt operation is repeated record by record, each
record being 16kB, max. TLS allocates an sg_table and uses
iov_iter_get_pages() to populate it with enough pages to
fit the decrypted record.

Even though we decrypt a single message at a time we size
the sg_table based on the entire length of the iovec.
This leads to unnecessarily large allocations, risking
triggering OOM conditions.

Use iov_iter_truncate() / iov_iter_reexpand() to construct
a "capped" version of iov_iter_npages(). Alternatively we
could parametrize iov_iter_npages() to take the size as
arg instead of using i->count, or do something else..

Signed-off-by: Jakub Kicinski <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
kuba-moo authored and davem330 committed Feb 4, 2022
1 parent 6ff6064 commit b93235e
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 1 deletion.
17 changes: 17 additions & 0 deletions include/linux/uio.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,23 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)
i->count = count;
}

static inline int
iov_iter_npages_cap(struct iov_iter *i, int maxpages, size_t max_bytes)
{
size_t shorted = 0;
int npages;

if (iov_iter_count(i) > max_bytes) {
shorted = iov_iter_count(i) - max_bytes;
iov_iter_truncate(i, max_bytes);
}
npages = iov_iter_npages(i, INT_MAX);
if (shorted)
iov_iter_reexpand(i, iov_iter_count(i) + shorted);

return npages;
}

struct csum_state {
__wsum csum;
size_t off;
Expand Down
3 changes: 2 additions & 1 deletion net/tls/tls_sw.c
Original file line number Diff line number Diff line change
Expand Up @@ -1433,7 +1433,8 @@ static int decrypt_internal(struct sock *sk, struct sk_buff *skb,

if (*zc && (out_iov || out_sg)) {
if (out_iov)
n_sgout = iov_iter_npages(out_iov, INT_MAX) + 1;
n_sgout = 1 +
iov_iter_npages_cap(out_iov, INT_MAX, data_len);
else
n_sgout = sg_nents(out_sg);
n_sgin = skb_nsg(skb, rxm->offset + prot->prepend_size,
Expand Down

0 comments on commit b93235e

Please sign in to comment.