Skip to content

Commit a34a9f1

Browse files
tohojoAlexei Starovoitov
authored andcommitted
bpf: Avoid deadlock when using queue and stack maps from NMI
Sysbot discovered that the queue and stack maps can deadlock if they are being used from a BPF program that can be called from NMI context (such as one that is attached to a perf HW counter event). To fix this, add an in_nmi() check and use raw_spin_trylock() in NMI context, erroring out if grabbing the lock fails. Fixes: f1a2e44 ("bpf: add queue and stack maps") Reported-by: Hsin-Wei Hung <hsinweih@uci.edu> Tested-by: Hsin-Wei Hung <hsinweih@uci.edu> Co-developed-by: Hsin-Wei Hung <hsinweih@uci.edu> Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com> Link: https://lore.kernel.org/r/20230911132815.717240-1-toke@redhat.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent b772b70 commit a34a9f1

1 file changed

Lines changed: 18 additions & 3 deletions

File tree

kernel/bpf/queue_stack_maps.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,12 @@ static long __queue_map_get(struct bpf_map *map, void *value, bool delete)
9898
int err = 0;
9999
void *ptr;
100100

101-
raw_spin_lock_irqsave(&qs->lock, flags);
101+
if (in_nmi()) {
102+
if (!raw_spin_trylock_irqsave(&qs->lock, flags))
103+
return -EBUSY;
104+
} else {
105+
raw_spin_lock_irqsave(&qs->lock, flags);
106+
}
102107

103108
if (queue_stack_map_is_empty(qs)) {
104109
memset(value, 0, qs->map.value_size);
@@ -128,7 +133,12 @@ static long __stack_map_get(struct bpf_map *map, void *value, bool delete)
128133
void *ptr;
129134
u32 index;
130135

131-
raw_spin_lock_irqsave(&qs->lock, flags);
136+
if (in_nmi()) {
137+
if (!raw_spin_trylock_irqsave(&qs->lock, flags))
138+
return -EBUSY;
139+
} else {
140+
raw_spin_lock_irqsave(&qs->lock, flags);
141+
}
132142

133143
if (queue_stack_map_is_empty(qs)) {
134144
memset(value, 0, qs->map.value_size);
@@ -193,7 +203,12 @@ static long queue_stack_map_push_elem(struct bpf_map *map, void *value,
193203
if (flags & BPF_NOEXIST || flags > BPF_EXIST)
194204
return -EINVAL;
195205

196-
raw_spin_lock_irqsave(&qs->lock, irq_flags);
206+
if (in_nmi()) {
207+
if (!raw_spin_trylock_irqsave(&qs->lock, irq_flags))
208+
return -EBUSY;
209+
} else {
210+
raw_spin_lock_irqsave(&qs->lock, irq_flags);
211+
}
197212

198213
if (queue_stack_map_is_full(qs)) {
199214
if (!replace) {

0 commit comments

Comments
 (0)