Skip to content

Commit f196220

Browse files
committed
module: fix init_module_from_file() error handling
Vegard Nossum pointed out two different problems with the error handling in init_module_from_file(): (a) the idempotent loading code didn't clean up properly in some error cases, leaving the on-stack 'struct idempotent' element still in the hash table (b) failure to read the module file would nonsensically update the 'invalid_kread_bytes' stat counter with the error value The first error is quite nasty, in that it can then cause subsequent idempotent loads of that same file to access stale stack contents of the previous failure. The case may not happen in any normal situation (explaining all the "Tested-by's on the original change), and requires admin privileges, but syzkaller triggers random bad behavior as a result: BUG: soft lockup in sys_finit_module BUG: unable to handle kernel paging request in init_module_from_file general protection fault in init_module_from_file INFO: task hung in init_module_from_file KASAN: out-of-bounds Read in init_module_from_file KASAN: slab-out-of-bounds Read in init_module_from_file ... The second error is fairly benign and just leads to nonsensical stats (and has been around since the debug stats were added). Vegard also provided a patch for the idempotent loading issue, but I'd rather re-organize the code and make it more legible using another level of helper functions than add the usual "goto out" error handling. Link: https://lore.kernel.org/lkml/20230704100852.23452-1-vegard.nossum@oracle.com/ Fixes: 9b9879f ("modules: catch concurrent module loads, treat them as idempotent") Reported-by: Vegard Nossum <vegard.nossum@oracle.com> Reported-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com> Reported-by: syzbot+9c2bdc9d24e4a7abe741@syzkaller.appspotmail.com Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent b5641a5 commit f196220

1 file changed

Lines changed: 23 additions & 16 deletions

File tree

kernel/module/main.c

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3092,7 +3092,7 @@ static bool idempotent(struct idempotent *u, const void *cookie)
30923092
* remove everybody - which includes ourselves - fill in the return
30933093
* value, and then complete the operation.
30943094
*/
3095-
static void idempotent_complete(struct idempotent *u, int ret)
3095+
static int idempotent_complete(struct idempotent *u, int ret)
30963096
{
30973097
const void *cookie = u->cookie;
30983098
int hash = hash_ptr(cookie, IDEM_HASH_BITS);
@@ -3109,27 +3109,18 @@ static void idempotent_complete(struct idempotent *u, int ret)
31093109
complete(&pos->complete);
31103110
}
31113111
spin_unlock(&idem_lock);
3112+
return ret;
31123113
}
31133114

31143115
static int init_module_from_file(struct file *f, const char __user * uargs, int flags)
31153116
{
3116-
struct idempotent idem;
31173117
struct load_info info = { };
31183118
void *buf = NULL;
3119-
int len, ret;
3120-
3121-
if (!f || !(f->f_mode & FMODE_READ))
3122-
return -EBADF;
3123-
3124-
if (idempotent(&idem, file_inode(f))) {
3125-
wait_for_completion(&idem.complete);
3126-
return idem.ret;
3127-
}
3119+
int len;
31283120

31293121
len = kernel_read_file(f, 0, &buf, INT_MAX, NULL, READING_MODULE);
31303122
if (len < 0) {
31313123
mod_stat_inc(&failed_kreads);
3132-
mod_stat_add_long(len, &invalid_kread_bytes);
31333124
return len;
31343125
}
31353126

@@ -3146,9 +3137,25 @@ static int init_module_from_file(struct file *f, const char __user * uargs, int
31463137
info.len = len;
31473138
}
31483139

3149-
ret = load_module(&info, uargs, flags);
3150-
idempotent_complete(&idem, ret);
3151-
return ret;
3140+
return load_module(&info, uargs, flags);
3141+
}
3142+
3143+
static int idempotent_init_module(struct file *f, const char __user * uargs, int flags)
3144+
{
3145+
struct idempotent idem;
3146+
3147+
if (!f || !(f->f_mode & FMODE_READ))
3148+
return -EBADF;
3149+
3150+
/* See if somebody else is doing the operation? */
3151+
if (idempotent(&idem, file_inode(f))) {
3152+
wait_for_completion(&idem.complete);
3153+
return idem.ret;
3154+
}
3155+
3156+
/* Otherwise, we'll do it and complete others */
3157+
return idempotent_complete(&idem,
3158+
init_module_from_file(f, uargs, flags));
31523159
}
31533160

31543161
SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)
@@ -3168,7 +3175,7 @@ SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)
31683175
return -EINVAL;
31693176

31703177
f = fdget(fd);
3171-
err = init_module_from_file(f.file, uargs, flags);
3178+
err = idempotent_init_module(f.file, uargs, flags);
31723179
fdput(f);
31733180
return err;
31743181
}

0 commit comments

Comments
 (0)