Skip to content

Commit a7fed5c

Browse files
KAGA-KOKOsuryasaimadhu
authored andcommitted
x86/nmi: Make register_nmi_handler() more robust
register_nmi_handler() has no sanity check whether a handler has been registered already. Such an unintended double-add leads to list corruption and hard to diagnose problems during the next NMI handling. Init the list head in the static NMI action struct and check it for being empty in register_nmi_handler(). [ bp: Fixups. ] Reported-by: Sean Christopherson <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Borislav Petkov <[email protected]> Link: https://lore.kernel.org/lkml/[email protected]
1 parent 203d891 commit a7fed5c

File tree

2 files changed

+9
-4
lines changed

2 files changed

+9
-4
lines changed

arch/x86/include/asm/nmi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ struct nmiaction {
4747
#define register_nmi_handler(t, fn, fg, n, init...) \
4848
({ \
4949
static struct nmiaction init fn##_na = { \
50+
.list = LIST_HEAD_INIT(fn##_na.list), \
5051
.handler = (fn), \
5152
.name = (n), \
5253
.flags = (fg), \

arch/x86/kernel/nmi.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ int __register_nmi_handler(unsigned int type, struct nmiaction *action)
157157
struct nmi_desc *desc = nmi_to_desc(type);
158158
unsigned long flags;
159159

160-
if (!action->handler)
160+
if (WARN_ON_ONCE(!action->handler || !list_empty(&action->list)))
161161
return -EINVAL;
162162

163163
raw_spin_lock_irqsave(&desc->lock, flags);
@@ -177,7 +177,7 @@ int __register_nmi_handler(unsigned int type, struct nmiaction *action)
177177
list_add_rcu(&action->list, &desc->head);
178178
else
179179
list_add_tail_rcu(&action->list, &desc->head);
180-
180+
181181
raw_spin_unlock_irqrestore(&desc->lock, flags);
182182
return 0;
183183
}
@@ -186,7 +186,7 @@ EXPORT_SYMBOL(__register_nmi_handler);
186186
void unregister_nmi_handler(unsigned int type, const char *name)
187187
{
188188
struct nmi_desc *desc = nmi_to_desc(type);
189-
struct nmiaction *n;
189+
struct nmiaction *n, *found = NULL;
190190
unsigned long flags;
191191

192192
raw_spin_lock_irqsave(&desc->lock, flags);
@@ -200,12 +200,16 @@ void unregister_nmi_handler(unsigned int type, const char *name)
200200
WARN(in_nmi(),
201201
"Trying to free NMI (%s) from NMI context!\n", n->name);
202202
list_del_rcu(&n->list);
203+
found = n;
203204
break;
204205
}
205206
}
206207

207208
raw_spin_unlock_irqrestore(&desc->lock, flags);
208-
synchronize_rcu();
209+
if (found) {
210+
synchronize_rcu();
211+
INIT_LIST_HEAD(&found->list);
212+
}
209213
}
210214
EXPORT_SYMBOL_GPL(unregister_nmi_handler);
211215

0 commit comments

Comments
 (0)