Commit d65e6c80 authored by Alexei Starovoitov's avatar Alexei Starovoitov

Merge branch 'bpf_msg_pull_data-fixes'

Daniel Borkmann says:

====================
This set contains three more fixes for the bpf_msg_pull_data()
mainly for correcting scatterlist ring wrap-arounds as well as
fixing up data pointers. For details please see individual patches.
Thanks!
====================
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents 5b24109b a8cf76a9
...@@ -2282,6 +2282,13 @@ static const struct bpf_func_proto bpf_msg_cork_bytes_proto = { ...@@ -2282,6 +2282,13 @@ static const struct bpf_func_proto bpf_msg_cork_bytes_proto = {
.arg2_type = ARG_ANYTHING, .arg2_type = ARG_ANYTHING,
}; };
#define sk_msg_iter_var(var) \
do { \
var++; \
if (var == MAX_SKB_FRAGS) \
var = 0; \
} while (0)
BPF_CALL_4(bpf_msg_pull_data, BPF_CALL_4(bpf_msg_pull_data,
struct sk_msg_buff *, msg, u32, start, u32, end, u64, flags) struct sk_msg_buff *, msg, u32, start, u32, end, u64, flags)
{ {
...@@ -2302,14 +2309,13 @@ BPF_CALL_4(bpf_msg_pull_data, ...@@ -2302,14 +2309,13 @@ BPF_CALL_4(bpf_msg_pull_data,
if (start < offset + len) if (start < offset + len)
break; break;
offset += len; offset += len;
i++; sk_msg_iter_var(i);
if (i == MAX_SKB_FRAGS)
i = 0;
} while (i != msg->sg_end); } while (i != msg->sg_end);
if (unlikely(start >= offset + len)) if (unlikely(start >= offset + len))
return -EINVAL; return -EINVAL;
first_sg = i;
/* The start may point into the sg element so we need to also /* The start may point into the sg element so we need to also
* account for the headroom. * account for the headroom.
*/ */
...@@ -2317,8 +2323,6 @@ BPF_CALL_4(bpf_msg_pull_data, ...@@ -2317,8 +2323,6 @@ BPF_CALL_4(bpf_msg_pull_data,
if (!msg->sg_copy[i] && bytes_sg_total <= len) if (!msg->sg_copy[i] && bytes_sg_total <= len)
goto out; goto out;
first_sg = i;
/* At this point we need to linearize multiple scatterlist /* At this point we need to linearize multiple scatterlist
* elements or a single shared page. Either way we need to * elements or a single shared page. Either way we need to
* copy into a linear buffer exclusively owned by BPF. Then * copy into a linear buffer exclusively owned by BPF. Then
...@@ -2331,9 +2335,7 @@ BPF_CALL_4(bpf_msg_pull_data, ...@@ -2331,9 +2335,7 @@ BPF_CALL_4(bpf_msg_pull_data,
*/ */
do { do {
copy += sg[i].length; copy += sg[i].length;
i++; sk_msg_iter_var(i);
if (i == MAX_SKB_FRAGS)
i = 0;
if (bytes_sg_total <= copy) if (bytes_sg_total <= copy)
break; break;
} while (i != msg->sg_end); } while (i != msg->sg_end);
...@@ -2359,9 +2361,7 @@ BPF_CALL_4(bpf_msg_pull_data, ...@@ -2359,9 +2361,7 @@ BPF_CALL_4(bpf_msg_pull_data,
sg[i].length = 0; sg[i].length = 0;
put_page(sg_page(&sg[i])); put_page(sg_page(&sg[i]));
i++; sk_msg_iter_var(i);
if (i == MAX_SKB_FRAGS)
i = 0;
} while (i != last_sg); } while (i != last_sg);
sg[first_sg].length = copy; sg[first_sg].length = copy;
...@@ -2371,11 +2371,15 @@ BPF_CALL_4(bpf_msg_pull_data, ...@@ -2371,11 +2371,15 @@ BPF_CALL_4(bpf_msg_pull_data,
* had a single entry though we can just replace it and * had a single entry though we can just replace it and
* be done. Otherwise walk the ring and shift the entries. * be done. Otherwise walk the ring and shift the entries.
*/ */
shift = last_sg - first_sg - 1; WARN_ON_ONCE(last_sg == first_sg);
shift = last_sg > first_sg ?
last_sg - first_sg - 1 :
MAX_SKB_FRAGS - first_sg + last_sg - 1;
if (!shift) if (!shift)
goto out; goto out;
i = first_sg + 1; i = first_sg;
sk_msg_iter_var(i);
do { do {
int move_from; int move_from;
...@@ -2392,15 +2396,13 @@ BPF_CALL_4(bpf_msg_pull_data, ...@@ -2392,15 +2396,13 @@ BPF_CALL_4(bpf_msg_pull_data,
sg[move_from].page_link = 0; sg[move_from].page_link = 0;
sg[move_from].offset = 0; sg[move_from].offset = 0;
i++; sk_msg_iter_var(i);
if (i == MAX_SKB_FRAGS)
i = 0;
} while (1); } while (1);
msg->sg_end -= shift; msg->sg_end -= shift;
if (msg->sg_end < 0) if (msg->sg_end < 0)
msg->sg_end += MAX_SKB_FRAGS; msg->sg_end += MAX_SKB_FRAGS;
out: out:
msg->data = sg_virt(&sg[i]) + start - offset; msg->data = sg_virt(&sg[first_sg]) + start - offset;
msg->data_end = msg->data + bytes; msg->data_end = msg->data + bytes;
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment