From: Alexei Starovoitov <alexei.starovoitov@gmail.com>
To: Daniel Borkmann <daniel@iogearbox.net>
Cc: Alexei Starovoitov <ast@kernel.org>,
davem@davemloft.net, jakub.kicinski@netronome.com,
netdev@vger.kernel.org, kernel-team@fb.com
Subject: Re: [PATCH bpf-next 1/9] bpf: introduce bpf_spin_lock
Date: Thu, 17 Jan 2019 21:51:29 -0800 [thread overview]
Message-ID: <20190118055127.6esmbegpobostha2@ast-mbp> (raw)
In-Reply-To: <bd1a1d4b-9f95-0438-3419-6c35ff0b5698@iogearbox.net>
On Thu, Jan 17, 2019 at 12:27:55PM +0100, Daniel Borkmann wrote:
>
> Was thinking something like this, in very rough pseudo code:
>
> Prog A (normal spin lock use of mapA):
>
> val = bpf_map_lookup_elem(&mapA, &key);
> if (val) {
> bpf_spin_lock(&val->lock);
> [...]
> bpf_spin_unlock(&val->lock);
> }
>
> Prog B:
>
> if (non_const_condition_A) {
> map_ptr = &mapB; // mapB is normal array map with same
> // properties as mapA, but no BTF and
> // thus no spinlock use.
> } else {
> map_ptr = &mapA;
> }
> val = bpf_map_lookup_elem(&map_ptr, &key);
> map_ptr = 0; // clear map reg to match for
> // both verification paths
> if (val) {
> // turning val into PTR_TO_MAP_VALUE
> if (non_const_condition_B) {
> // write into memory area of spin_lock;
> // first path with mapB is considered
> // safe (since map with no spin_lock so
> // write into this area allowed);
> // now when verifier is checking the
> // non_const_condition_A's else path
> // with mapA, then non_const_condition_B
> // has pruning checkpoint and is going
> // to compare reg with PTR_TO_MAP_VALUE;
> // since id is not considered I /think/
> // verifier would find it (wrongly) safe
> // as well.
> }
> }
>
> Wdyt?
I've implemented it and it was rejected.
regsafe() is doing:
memcmp(rold, rcur, offsetof(struct bpf_reg_state, id));
'map_ptr' is before 'id' in bpf_reg_state.
lookups from different maps will have different register states
as expected.
I still felt that we need to compare id, so I tried
if (random)
val = bpf_map_lookup_elem(&hash_map, &key1);
else
val = bpf_map_lookup_elem(&hash_map, &key2);
to force pruning of two states that point to the same map.
The val->spin_lock addresses will be different and intuitively it
may feel that we need to compare id, but it's unnecessary.
If the rest of the program is valid with val for key1
it's a good thing to prune verification for key2 to avoid
spending more cycles in the verifier.
All map elements have spin_locks. If bpf code is valid
for one element it's valid for all elements.
Then I tried to trick the verifier with the following:
int flag = 0;
if (random) {
val = bpf_map_lookup_elem(&hash_map, &key1);
} else {
flag = 1;
val = bpf_map_lookup_elem(&hash_map, &key2);
}
if (!val)
goto err;
bpf_spin_lock(&val->lock);
bpf_spin_unlock(&val->lock);
if (flag == 1) // access spin_lock with ld/st
the first pass of the verifier will correctly avoid
exploring 'flag == 1' condition (because the verifier is
smart enough to know that the flag is 0 there), but
the second pass with different reg->id for 'val' will not be pruned,
since the register (or stack) where 'flag' is stored
is different and the verifier will proceed and will
catch ld/st into spin_lock field and the prog will be rejected.
So I believe the verifier should not compare 'id' in regsafe()
for PTR_TO_MAP_VALUE to have better pruning.
I'll add a comment there explaining this.
next prev parent reply other threads:[~2019-01-18 5:51 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-01-16 5:08 [PATCH bpf-next 0/9] introduce bpf_spin_lock Alexei Starovoitov
2019-01-16 5:08 ` [PATCH bpf-next 1/9] bpf: " Alexei Starovoitov
2019-01-16 22:48 ` Daniel Borkmann
2019-01-16 23:16 ` Daniel Borkmann
2019-01-16 23:30 ` Alexei Starovoitov
2019-01-17 0:21 ` Daniel Borkmann
2019-01-17 1:16 ` Alexei Starovoitov
2019-01-17 11:27 ` Daniel Borkmann
2019-01-18 5:51 ` Alexei Starovoitov [this message]
2019-01-16 23:23 ` Alexei Starovoitov
2019-01-17 0:16 ` Martin Lau
2019-01-17 1:02 ` Alexei Starovoitov
2019-01-16 5:08 ` [PATCH bpf-next 2/9] bpf: add support for bpf_spin_lock to cgroup local storage Alexei Starovoitov
2019-01-16 5:08 ` [PATCH bpf-next 3/9] tools/bpf: sync include/uapi/linux/bpf.h Alexei Starovoitov
2019-01-16 5:08 ` [PATCH bpf-next 4/9] selftests/bpf: add bpf_spin_lock tests Alexei Starovoitov
2019-01-16 5:08 ` [PATCH bpf-next 5/9] selftests/bpf: add bpf_spin_lock C test Alexei Starovoitov
2019-01-16 5:08 ` [PATCH bpf-next 8/9] libbpf: introduce bpf_map_lookup_elem_flags() Alexei Starovoitov
2019-01-16 6:18 ` Yonghong Song
2019-01-16 6:28 ` Alexei Starovoitov
2019-01-16 5:08 ` [PATCH bpf-next 9/9] selftests/bpf: test for BPF_F_LOCK Alexei Starovoitov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190118055127.6esmbegpobostha2@ast-mbp \
--to=alexei.starovoitov@gmail.com \
--cc=ast@kernel.org \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=jakub.kicinski@netronome.com \
--cc=kernel-team@fb.com \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox