--- a/sys/kern/kern_syscalls.c +++ b/sys/kern/kern_syscalls.c @@ -72,9 +72,19 @@ int syscall_deregister(int *offset, struct sysent *old_sysent) { - if (*offset) - sysent[*offset] = *old_sysent; - return 0; + /* + * *offset and *old_sysent are only meaningful after a successful + * syscall_register(). MOD_UNLOAD can nevertheless reach us with + * never-initialized values (MOD_LOAD rollback via + * module_register_init() -> module_unload(), kern_module.c:110-116), + * so the index MUST be re-validated before writing the shared + * dispatch table. Note NO_SYSCALL is -1, which the old + * "if (*offset)" test happily passed. + */ + if (*offset <= 0 || *offset >= SYS_MAXSYSCALL) + return EINVAL; + sysent[*offset] = *old_sysent; + return 0; } int @@ -90,10 +100,16 @@ &data->old_sysent); if (error) return error; + data->registered = 1; ms.intval = *data->offset; module_setspecific(mod, &ms); if (data->chainevh) error = data->chainevh(mod, what, data->chainarg); + if (error == 0) + return 0; + /* init failed: roll our registration back before failing */ + syscall_deregister(data->offset, &data->old_sysent); + data->registered = 0; return error; case MOD_UNLOAD : @@ -102,7 +118,11 @@ if (error) return error; } - error = syscall_deregister(data->offset, &data->old_sysent); + if (data->registered) { + error = syscall_deregister(data->offset, + &data->old_sysent); + data->registered = 0; + } return error; } --- a/sys/sys/sysent.h +++ b/sys/sys/sysent.h @@ -87,15 +87,16 @@ struct syscall_module_data { int (*chainevh)(struct module *, int, void *); /* next handler */ - void *chainarg; /* arg for next event handler */ + void *chainarg; /* arg for next event */ int *offset; /* offset into sysent */ struct sysent *new_sysent; /* new sysent */ struct sysent old_sysent; /* old sysent */ + int registered; /* syscall_register() succeeded */ }; #define SYSCALL_MODULE(name, offset, new_sysent, evh, arg) \ static struct syscall_module_data name##_syscall_mod = { \ - evh, arg, offset, new_sysent, { 0, NULL } \ + evh, arg, offset, new_sysent, { 0, 0, NULL, NULL }, 0 \ }; \ \ static moduledata_t name##_mod = { \