You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Reading the len field of the event header needs to be atomic to match
the release memory barrier from
https://github.com/torvalds/linux/blob/eb26cbb1a754ccde5d4d74527dad5ba051808fad/kernel/bpf/ringbuf.c#L487
We also don't care about the PgOff field which is only used by ringbuf
internals.
[ Additional context by Lorenz ]
Based on a suggestion by Daniel Borkmann I wrote a litmus test against
the Linux Kernel Memory Model:
C ringbuf
{}
P0(int *hdr_len, int *prod_pos, int *data) // Producer
{
// __bpf_ringbuf_reserve
*hdr_len = 1; // BUSY
smp_store_release(prod_pos, 1);
// store some data.
*data = 1;
// bpf_ringbuf_commit
int r0 = xchg(hdr_len, 2); // COMMIT
}
P1(int *hdr_len, int *prod_pos, int *data) // Consumer
{
int p = smp_load_acquire(prod_pos);
if (p > 0) {
int l = *hdr_len;
if (l == 2) {
int d = *data;
}
}
}
exists (prod_pos=1 /\ 1:l=2 /\ 1:d=0)
Note that hdr_len is read via a plain read. Executing the litmus test
shows that we can indeed observe a COMMIT (l=2) before data is visible:
$ herd7 -conf linux-kernel.cfg litmus-tests/ringbuf.litmus
Test ringbuf Allowed
States 4
1:d=0; 1:l=0; [prod_pos]=1;
1:d=0; 1:l=1; [prod_pos]=1;
1:d=0; 1:l=2; [prod_pos]=1;
1:d=1; 1:l=2; [prod_pos]=1;
Ok
Witnesses
Positive: 1 Negative: 3
Flag data-race
Condition exists ([prod_pos]=1 /\ 1:l=2 /\ 1:d=0)
Observation ringbuf Sometimes 1 3
Time ringbuf 0.01
Hash=7aed947102aa203443a5b9b5884f956f
This is fixed by using an smp_load_acquire or equivalent to read hdr_len.
Signed-off-by: Paul Cacheux <[email protected]>
Co-developed-by: Lorenz Bauer <[email protected]>
0 commit comments