diff options
author | Jesper Dangaard Brouer <brouer@redhat.com> | 2018-04-17 16:46:43 +0200 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-04-17 16:50:30 +0200 |
commit | 6dfb970d3dbd6bf274c4bf003ca8ab4a51dc66c7 (patch) | |
tree | 1f162a8267f6647ca930ef202dfc9ad0b0245fae /net | |
parent | xdp: transition into using xdp_frame for ndo_xdp_xmit (diff) | |
download | linux-6dfb970d3dbd6bf274c4bf003ca8ab4a51dc66c7.tar.xz linux-6dfb970d3dbd6bf274c4bf003ca8ab4a51dc66c7.zip |
xdp: avoid leaking info stored in frame data on page reuse
The bpf infrastructure and verifier goes to great length to avoid
bpf progs leaking kernel (pointer) info.
For queueing an xdp_buff via XDP_REDIRECT, xdp_frame info stores
kernel info (incl pointers) in top part of frame data (xdp->data_hard_start).
Checks are in place to assure enough headroom is available for this.
This info is not cleared, and if the frame is reused, then a
malicious user could use bpf_xdp_adjust_head helper to move
xdp->data into this area. Thus, making this area readable.
This is not super critical as XDP progs requires root or
CAP_SYS_ADMIN, which are privileged enough for such info. An
effort (is underway) towards moving networking bpf hooks to the
lesser privileged mode CAP_NET_ADMIN, where leaking such info
should be avoided. Thus, this patch to clear the info when
needed.
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/filter.c | 8 |
1 files changed, 8 insertions, 0 deletions
diff --git a/net/core/filter.c b/net/core/filter.c index 3bb0cb98a9be..a374b8560bc4 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -2692,6 +2692,7 @@ static unsigned long xdp_get_metalen(const struct xdp_buff *xdp) BPF_CALL_2(bpf_xdp_adjust_head, struct xdp_buff *, xdp, int, offset) { + void *xdp_frame_end = xdp->data_hard_start + sizeof(struct xdp_frame); unsigned long metalen = xdp_get_metalen(xdp); void *data_start = xdp->data_hard_start + metalen; void *data = xdp->data + offset; @@ -2700,6 +2701,13 @@ BPF_CALL_2(bpf_xdp_adjust_head, struct xdp_buff *, xdp, int, offset) data > xdp->data_end - ETH_HLEN)) return -EINVAL; + /* Avoid info leak, when reusing area prev used by xdp_frame */ + if (data < xdp_frame_end) { + unsigned long clearlen = xdp_frame_end - data; + + memset(data, 0, clearlen); + } + if (metalen) memmove(xdp->data_meta + offset, xdp->data_meta, metalen); |