Messages in this thread Patch in this message | | | From | Levi Yun <> | Subject | [PATCH] fs/exec.c: Avoid a race in formats | Date | Thu, 24 Feb 2022 08:17:52 +0900 |
| |
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@gmail.com> --- 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
| |