Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ptr_ring: add barriers

Users of ptr_ring expect that it's safe to give the
data structure a pointer and have it be available
to consumers, but that actually requires an smb_wmb
or a stronger barrier.

In absence of such barriers and on architectures that reorder writes,
consumer might read an un=initialized value from an skb pointer stored
in the skb array. This was observed causing crashes.

To fix, add memory barriers. The barrier we use is a wmb, the
assumption being that producers do not need to read the value so we do
not need to order these reads.

Reported-by: George Cherian <george.cherian@cavium.com>
Suggested-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Michael S. Tsirkin and committed by
David S. Miller
a8ceb5db f0f1d016

+9
+9
include/linux/ptr_ring.h
··· 101 101 102 102 /* Note: callers invoking this in a loop must use a compiler barrier, 103 103 * for example cpu_relax(). Callers must hold producer_lock. 104 + * Callers are responsible for making sure pointer that is being queued 105 + * points to a valid data. 104 106 */ 105 107 static inline int __ptr_ring_produce(struct ptr_ring *r, void *ptr) 106 108 { 107 109 if (unlikely(!r->size) || r->queue[r->producer]) 108 110 return -ENOSPC; 111 + 112 + /* Make sure the pointer we are storing points to a valid data. */ 113 + /* Pairs with smp_read_barrier_depends in __ptr_ring_consume. */ 114 + smp_wmb(); 109 115 110 116 r->queue[r->producer++] = ptr; 111 117 if (unlikely(r->producer >= r->size)) ··· 281 275 if (ptr) 282 276 __ptr_ring_discard_one(r); 283 277 278 + /* Make sure anyone accessing data through the pointer is up to date. */ 279 + /* Pairs with smp_wmb in __ptr_ring_produce. */ 280 + smp_read_barrier_depends(); 284 281 return ptr; 285 282 } 286 283