Suppose a module registers its own binfmt (custom) and formats is like: +---------+ +----------+ +---------+ | custom | -> | format1 | -> | format2 | +---------+ +----------+ +---------+ and try to call unregister_binfmt with custom NOT in __exit stage. In that situation, below race scenario can happen. CPU 0 CPU1 search_binary_handler ... read_lock unregister_binfmt(custom) list_for_each_entry < wait > (get custom binfmt) ... read_unlock ... ... list_del custom binfmt return -ENOEXEC get next fmt entry (LIST_POISON1) Because CPU1 set the fmt->lh.next as LIST_POISON1, CPU 0 get next binfmt as LIST_POISON1. In that situation, CPU0 try to dereference LIST_POISON1 address and makes PANIC. To avoid this situation, check the fmt is valid. And if it isn't valid, return -EAGAIN. Signed-off-by: Levi Yun <ppbuk5246@xxxxxxxxx> --- fs/exec.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/exec.c b/fs/exec.c index 79f2c9483302..2042a1232656 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1720,6 +1720,12 @@ static int search_binary_handler(struct linux_binprm *bprm) retry: read_lock(&binfmt_lock); list_for_each_entry(fmt, &formats, lh) { + if (fmt == LIST_POISON1) { + read_unlock(&binfmt_lock); + retval = -EAGAIN; + break; + } + if (!try_module_get(fmt->module)) continue; read_unlock(&binfmt_lock); -- 2.34.1