Module Name: src Committed By: hannken Date: Wed Jan 17 10:18:41 UTC 2024
Modified Files: src/sys/kern: init_main.c kern_hook.c Log Message: Protect kernel hooks exechook, exithook and forkhook with rwlock. Lock as writer on establish/disestablish and as reader on list traverse. For exechook ride "exec_lock" as it is already take as reader when traversing the list. Add local locks for exithook and forkhook. Move exec_init before signal_init as signal_init calls exechook_establish() that needs "exec_lock". PR kern/39913 "exec, fork, exit hooks need locking" To generate a diff of this commit: cvs rdiff -u -r1.546 -r1.547 src/sys/kern/init_main.c cvs rdiff -u -r1.14 -r1.15 src/sys/kern/kern_hook.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/init_main.c diff -u src/sys/kern/init_main.c:1.546 src/sys/kern/init_main.c:1.547 --- src/sys/kern/init_main.c:1.546 Sat Sep 23 18:21:11 2023 +++ src/sys/kern/init_main.c Wed Jan 17 10:18:41 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: init_main.c,v 1.546 2023/09/23 18:21:11 ad Exp $ */ +/* $NetBSD: init_main.c,v 1.547 2024/01/17 10:18:41 hannken Exp $ */ /*- * Copyright (c) 2008, 2009, 2019, 2023 The NetBSD Foundation, Inc. @@ -97,7 +97,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.546 2023/09/23 18:21:11 ad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.547 2024/01/17 10:18:41 hannken Exp $"); #include "opt_cnmagic.h" #include "opt_ddb.h" @@ -407,6 +407,9 @@ main(void) /* Must be called after lwpinit (lwpinit_specificdata) */ psref_init(); + /* Initialize exec structures */ + exec_init(1); /* signal_init calls exechook_establish() */ + /* Initialize signal-related data structures. */ signal_init(); @@ -579,9 +582,6 @@ main(void) vmem_rehash_start(); /* must be before exec_init */ - /* Initialize exec structures */ - exec_init(1); /* seminit calls exithook_establish() */ - #if NVERIEXEC > 0 /* * Initialise the Veriexec subsystem. Index: src/sys/kern/kern_hook.c diff -u src/sys/kern/kern_hook.c:1.14 src/sys/kern/kern_hook.c:1.15 --- src/sys/kern/kern_hook.c:1.14 Wed Oct 26 23:21:06 2022 +++ src/sys/kern/kern_hook.c Wed Jan 17 10:18:41 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: kern_hook.c,v 1.14 2022/10/26 23:21:06 riastradh Exp $ */ +/* $NetBSD: kern_hook.c,v 1.15 2024/01/17 10:18:41 hannken Exp $ */ /*- * Copyright (c) 1997, 1998, 1999, 2002, 2007, 2008 The NetBSD Foundation, Inc. @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_hook.c,v 1.14 2022/10/26 23:21:06 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_hook.c,v 1.15 2024/01/17 10:18:41 hannken Exp $"); #include <sys/param.h> @@ -42,6 +42,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_hook.c, #include <sys/hook.h> #include <sys/kmem.h> #include <sys/malloc.h> +#include <sys/once.h> #include <sys/rwlock.h> #include <sys/systm.h> @@ -74,25 +75,48 @@ struct khook_list { int powerhook_debug = 0; +static ONCE_DECL(hook_control); +static krwlock_t exithook_lock; +static krwlock_t forkhook_lock; + +static int +hook_init(void) +{ + + rw_init(&exithook_lock); + rw_init(&forkhook_lock); + + return 0; +} + static void * -hook_establish(hook_list_t *list, void (*fn)(void *), void *arg) +hook_establish(hook_list_t *list, krwlock_t *lock, + void (*fn)(void *), void *arg) { struct hook_desc *hd; - hd = malloc(sizeof(*hd), M_DEVBUF, M_NOWAIT); - if (hd == NULL) - return (NULL); + RUN_ONCE(&hook_control, hook_init); - hd->hk_fn = fn; - hd->hk_arg = arg; - LIST_INSERT_HEAD(list, hd, hk_list); + hd = malloc(sizeof(*hd), M_DEVBUF, M_NOWAIT); + if (hd != NULL) { + if (lock) + rw_enter(lock, RW_WRITER); + hd->hk_fn = fn; + hd->hk_arg = arg; + LIST_INSERT_HEAD(list, hd, hk_list); + if (lock) + rw_exit(lock); + } return (hd); } static void -hook_disestablish(hook_list_t *list, void *vhook) +hook_disestablish(hook_list_t *list, krwlock_t *lock, void *vhook) { + + if (lock) + rw_enter(lock, RW_WRITER); #ifdef DIAGNOSTIC struct hook_desc *hd; @@ -106,6 +130,8 @@ hook_disestablish(hook_list_t *list, voi #endif LIST_REMOVE((struct hook_desc *)vhook, hk_list); free(vhook, M_DEVBUF); + if (lock) + rw_exit(lock); } static void @@ -120,14 +146,20 @@ hook_destroy(hook_list_t *list) } static void -hook_proc_run(hook_list_t *list, struct proc *p) +hook_proc_run(hook_list_t *list, krwlock_t *lock, struct proc *p) { struct hook_desc *hd; + RUN_ONCE(&hook_control, hook_init); + + if (lock) + rw_enter(lock, RW_READER); LIST_FOREACH(hd, list, hk_list) { __FPTRCAST(void (*)(struct proc *, void *), *hd->hk_fn)(p, hd->hk_arg); } + if (lock) + rw_exit(lock); } /* @@ -146,13 +178,13 @@ static hook_list_t shutdownhook_list = L void * shutdownhook_establish(void (*fn)(void *), void *arg) { - return hook_establish(&shutdownhook_list, fn, arg); + return hook_establish(&shutdownhook_list, NULL, fn, arg); } void shutdownhook_disestablish(void *vhook) { - hook_disestablish(&shutdownhook_list, vhook); + hook_disestablish(&shutdownhook_list, NULL, vhook); } /* @@ -193,14 +225,14 @@ static hook_list_t mountroothook_list=LI void * mountroothook_establish(void (*fn)(device_t), device_t dev) { - return hook_establish(&mountroothook_list, __FPTRCAST(void (*), fn), - dev); + return hook_establish(&mountroothook_list, NULL, + __FPTRCAST(void (*), fn), dev); } void mountroothook_disestablish(void *vhook) { - hook_disestablish(&mountroothook_list, vhook); + hook_disestablish(&mountroothook_list, NULL, vhook); } void @@ -227,14 +259,14 @@ static hook_list_t exechook_list = LIST_ void * exechook_establish(void (*fn)(struct proc *, void *), void *arg) { - return hook_establish(&exechook_list, __FPTRCAST(void (*)(void *), fn), - arg); + return hook_establish(&exechook_list, &exec_lock, + __FPTRCAST(void (*)(void *), fn), arg); } void exechook_disestablish(void *vhook) { - hook_disestablish(&exechook_list, vhook); + hook_disestablish(&exechook_list, &exec_lock, vhook); } /* @@ -243,7 +275,9 @@ exechook_disestablish(void *vhook) void doexechooks(struct proc *p) { - hook_proc_run(&exechook_list, p); + KASSERT(rw_lock_held(&exec_lock)); + + hook_proc_run(&exechook_list, NULL, p); } static hook_list_t exithook_list = LIST_HEAD_INITIALIZER(exithook_list); @@ -251,22 +285,16 @@ static hook_list_t exithook_list = LIST_ void * exithook_establish(void (*fn)(struct proc *, void *), void *arg) { - void *rv; - rw_enter(&exec_lock, RW_WRITER); - rv = hook_establish(&exithook_list, __FPTRCAST(void (*)(void *), fn), - arg); - rw_exit(&exec_lock); - return rv; + return hook_establish(&exithook_list, &exithook_lock, + __FPTRCAST(void (*)(void *), fn), arg); } void exithook_disestablish(void *vhook) { - rw_enter(&exec_lock, RW_WRITER); - hook_disestablish(&exithook_list, vhook); - rw_exit(&exec_lock); + hook_disestablish(&exithook_list, &exithook_lock, vhook); } /* @@ -275,7 +303,7 @@ exithook_disestablish(void *vhook) void doexithooks(struct proc *p) { - hook_proc_run(&exithook_list, p); + hook_proc_run(&exithook_list, &exithook_lock, p); } static hook_list_t forkhook_list = LIST_HEAD_INITIALIZER(forkhook_list); @@ -283,14 +311,14 @@ static hook_list_t forkhook_list = LIST_ void * forkhook_establish(void (*fn)(struct proc *, struct proc *)) { - return hook_establish(&forkhook_list, __FPTRCAST(void (*)(void *), fn), - NULL); + return hook_establish(&forkhook_list, &forkhook_lock, + __FPTRCAST(void (*)(void *), fn), NULL); } void forkhook_disestablish(void *vhook) { - hook_disestablish(&forkhook_list, vhook); + hook_disestablish(&forkhook_list, &forkhook_lock, vhook); } /* @@ -301,10 +329,14 @@ doforkhooks(struct proc *p2, struct proc { struct hook_desc *hd; + RUN_ONCE(&hook_control, hook_init); + + rw_enter(&forkhook_lock, RW_READER); LIST_FOREACH(hd, &forkhook_list, hk_list) { __FPTRCAST(void (*)(struct proc *, struct proc *), *hd->hk_fn) (p2, p1); } + rw_exit(&forkhook_lock); } static hook_list_t critpollhook_list = LIST_HEAD_INITIALIZER(critpollhook_list); @@ -312,13 +344,13 @@ static hook_list_t critpollhook_list = L void * critpollhook_establish(void (*fn)(void *), void *arg) { - return hook_establish(&critpollhook_list, fn, arg); + return hook_establish(&critpollhook_list, NULL, fn, arg); } void critpollhook_disestablish(void *vhook) { - hook_disestablish(&critpollhook_list, vhook); + hook_disestablish(&critpollhook_list, NULL, vhook); } /*