| From 1b6ba4e33b91f7393468774f30a57ae013adb6c0 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 18 Jun 2021 09:58:05 +0200 |
| Subject: xsk: Fix broken Tx ring validation |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Magnus Karlsson <magnus.karlsson@intel.com> |
| |
| [ Upstream commit f654fae47e83e56b454fbbfd0af0a4f232e356d6 ] |
| |
| Fix broken Tx ring validation for AF_XDP. The commit under the Fixes |
| tag, fixed an off-by-one error in the validation but introduced |
| another error. Descriptors are now let through even if they straddle a |
| chunk boundary which they are not allowed to do in aligned mode. Worse |
| is that they are let through even if they straddle the end of the umem |
| itself, tricking the kernel to read data outside the allowed umem |
| region which might or might not be mapped at all. |
| |
| Fix this by reintroducing the old code, but subtract the length by one |
| to fix the off-by-one error that the original patch was |
| addressing. The test chunk != chunk_end makes sure packets do not |
| straddle chunk boundraries. Note that packets of zero length are |
| allowed in the interface, therefore the test if the length is |
| non-zero. |
| |
| Fixes: ac31565c2193 ("xsk: Fix for xp_aligned_validate_desc() when len == chunk_size") |
| Signed-off-by: Magnus Karlsson <magnus.karlsson@intel.com> |
| Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> |
| Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com> |
| Acked-by: Björn Töpel <bjorn@kernel.org> |
| Link: https://lore.kernel.org/bpf/20210618075805.14412-1-magnus.karlsson@gmail.com |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/xdp/xsk_queue.h | 11 +++++++---- |
| 1 file changed, 7 insertions(+), 4 deletions(-) |
| |
| diff --git a/net/xdp/xsk_queue.h b/net/xdp/xsk_queue.h |
| index be9fd5a72011..3c7ce60fe9a5 100644 |
| --- a/net/xdp/xsk_queue.h |
| +++ b/net/xdp/xsk_queue.h |
| @@ -126,12 +126,15 @@ static inline bool xskq_cons_read_addr_unchecked(struct xsk_queue *q, u64 *addr) |
| static inline bool xp_aligned_validate_desc(struct xsk_buff_pool *pool, |
| struct xdp_desc *desc) |
| { |
| - u64 chunk; |
| - |
| - if (desc->len > pool->chunk_size) |
| - return false; |
| + u64 chunk, chunk_end; |
| |
| chunk = xp_aligned_extract_addr(pool, desc->addr); |
| + if (likely(desc->len)) { |
| + chunk_end = xp_aligned_extract_addr(pool, desc->addr + desc->len - 1); |
| + if (chunk != chunk_end) |
| + return false; |
| + } |
| + |
| if (chunk >= pool->addrs_cnt) |
| return false; |
| |
| -- |
| 2.30.2 |
| |