FreeBSD Bugzilla – Attachment 205503 Details for
Bug 238971
patch(1) modifies the wrong file
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
patch that adds a new Makefile
0001-Save-the-last-callout-function-executed-on-each-CPU.patch (text/plain), 7.06 KB, created by
Eric van Gyzen
on 2019-07-03 19:12:47 UTC
(
hide
)
Description:
patch that adds a new Makefile
Filename:
MIME Type:
Creator:
Eric van Gyzen
Created:
2019-07-03 19:12:47 UTC
Size:
7.06 KB
patch
obsolete
>From ee77139c3ce21bac8665411c9d5e7c945afcf981 Mon Sep 17 00:00:00 2001 >From: Eric van Gyzen <eric@vangyzen.net> >Date: Fri, 28 Jun 2019 05:16:27 -0500 >Subject: [PATCH 1/2] Save the last callout function executed on each CPU > >Save the last callout function pointer (and its argument) executed >on each CPU for inspection by a debugger. Add a ddb `show callout_last` >command to show these pointers. Add a kernel module that I used >for testing that command. > >Relocate `ce_migration_cpu` to reduce padding and therefore preserve >the size of `struct callout_cpu` (320 bytes on amd64) despite the >added members. > >This should help diagnose reference-after-free bugs where the >callout's mutex has already been freed when `softclock_call_cc` >tries to unlock it. > >You might hope that the pointer would still be available, but it >isn't. The argument to that function is on the stack (because >`softclock_call_cc` uses it later), and that might be enough in >some cases, but even then, it's very laborious. A pointer to the >callout is saved right before these newly added fields, but that >callout might have been freed. We still have the pointer to its >associated mutex, and the name within might be enough, but it might >also have been freed. >--- > sys/kern/kern_timeout.c | 39 +++++++++++- > tools/test/callout_free/Makefile | 4 ++ > tools/test/callout_free/callout_free.c | 87 ++++++++++++++++++++++++++ > 3 files changed, 129 insertions(+), 1 deletion(-) > create mode 100644 tools/test/callout_free/Makefile > create mode 100644 tools/test/callout_free/callout_free.c > >diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c >index 81b4a14ecf08..73f3904d1837 100644 >--- a/sys/kern/kern_timeout.c >+++ b/sys/kern/kern_timeout.c >@@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$"); > > #ifdef DDB > #include <ddb/ddb.h> >+#include <ddb/db_sym.h> > #include <machine/_inttypes.h> > #endif > >@@ -143,12 +144,14 @@ u_int callwheelsize, callwheelmask; > struct cc_exec { > struct callout *cc_curr; > void (*cc_drain)(void *); >+ void *cc_last_func; >+ void *cc_last_arg; > #ifdef SMP > void (*ce_migration_func)(void *); > void *ce_migration_arg; >- int ce_migration_cpu; > sbintime_t ce_migration_time; > sbintime_t ce_migration_prec; >+ int ce_migration_cpu; > #endif > bool cc_cancel; > bool cc_waiting; >@@ -177,6 +180,8 @@ struct callout_cpu { > #define callout_migrating(c) ((c)->c_iflags & CALLOUT_DFRMIGRATION) > > #define cc_exec_curr(cc, dir) cc->cc_exec_entity[dir].cc_curr >+#define cc_exec_last_func(cc, dir) cc->cc_exec_entity[dir].cc_last_func >+#define cc_exec_last_arg(cc, dir) cc->cc_exec_entity[dir].cc_last_arg > #define cc_exec_drain(cc, dir) cc->cc_exec_entity[dir].cc_drain > #define cc_exec_next(cc) cc->cc_next > #define cc_exec_cancel(cc, dir) cc->cc_exec_entity[dir].cc_cancel >@@ -686,6 +691,8 @@ softclock_call_cc(struct callout *c, struct callout_cpu *cc, > c->c_iflags &= ~CALLOUT_PENDING; > > cc_exec_curr(cc, direct) = c; >+ cc_exec_last_func(cc, direct) = c_func; >+ cc_exec_last_arg(cc, direct) = c_arg; > cc_exec_cancel(cc, direct) = false; > cc_exec_drain(cc, direct) = NULL; > CC_UNLOCK(cc); >@@ -1670,4 +1677,34 @@ DB_SHOW_COMMAND(callout, db_show_callout) > > _show_callout((struct callout *)addr); > } >+ >+static void >+_show_last_callout(struct callout_cpu *cc, int direct, const char *dirstr) >+{ >+ void *func, *arg; >+ >+ func = cc_exec_last_func(cc, direct); >+ arg = cc_exec_last_arg(cc, direct); >+ db_printf("last%s callout function: %p ", dirstr, func); >+ db_printsym((db_expr_t)func, DB_STGY_ANY); >+ db_printf("\nlast%s callout argument: %p\n", dirstr, arg); >+} >+ >+DB_SHOW_COMMAND(callout_last, db_show_callout_last) >+{ >+ struct callout_cpu *cc; >+ >+ if (have_addr) { >+ if (addr < 0 || addr > mp_maxid || CPU_ABSENT(addr)) { >+ db_printf("no such cpu: %d\n", (int)addr); >+ return; >+ } >+ cc = CC_CPU(addr); >+ } else { >+ cc = CC_CPU(timeout_cpu); >+ } >+ >+ _show_last_callout(cc, 0, ""); >+ _show_last_callout(cc, 1, " direct"); >+} > #endif /* DDB */ >diff --git a/tools/test/callout_free/Makefile b/tools/test/callout_free/Makefile >new file mode 100644 >index 000000000000..6421c072c5b9 >--- /dev/null >+++ b/tools/test/callout_free/Makefile >@@ -0,0 +1,4 @@ >+KMOD= callout_free >+SRCS= callout_free.c >+ >+.include <bsd.kmod.mk> >diff --git a/tools/test/callout_free/callout_free.c b/tools/test/callout_free/callout_free.c >new file mode 100644 >index 000000000000..4556687e06f6 >--- /dev/null >+++ b/tools/test/callout_free/callout_free.c >@@ -0,0 +1,87 @@ >+/*- >+ * SPDX-License-Identifier: BSD-2-Clause >+ * >+ * Copyright (c) 2019 Eric van Gyzen >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND >+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE >+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE >+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL >+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS >+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT >+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY >+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF >+ * SUCH DAMAGE. >+ * >+ * $FreeBSD$ >+ */ >+ >+/* >+ * Free a pending callout. This was useful for testing the >+ * "show callout_last" ddb command. >+ */ >+ >+#include <sys/param.h> >+#include <sys/conf.h> >+#include <sys/kernel.h> >+#include <sys/lock.h> >+#include <sys/module.h> >+#include <sys/mutex.h> >+#include <sys/systm.h> >+ >+static struct callout callout_free; >+static struct mtx callout_free_mutex; >+static int callout_free_arg; >+ >+static void >+callout_free_func(void *arg) >+{ >+ printf("squirrel!\n"); >+ mtx_destroy(&callout_free_mutex); >+ memset(&callout_free, 'C', sizeof(callout_free)); >+} >+ >+static int >+callout_free_load(module_t mod, int cmd, void *arg) >+{ >+ int error; >+ >+ switch (cmd) { >+ case MOD_LOAD: >+ mtx_init(&callout_free_mutex, "callout_free", NULL, MTX_DEF); >+ /* >+ * Do not pass CALLOUT_RETURNUNLOCKED so the callout >+ * subsystem will unlock the "destroyed" mutex. >+ */ >+ callout_init_mtx(&callout_free, &callout_free_mutex, 0); >+ printf("callout_free_func = %p\n", callout_free_func); >+ printf("callout_free_arg = %p\n", &callout_free_arg); >+ callout_reset(&callout_free, hz/10, callout_free_func, >+ &callout_free_arg); >+ error = 0; >+ break; >+ >+ case MOD_UNLOAD: >+ error = 0; >+ break; >+ >+ default: >+ error = EOPNOTSUPP; >+ break; >+ } >+ >+ return (error); >+} >+ >+DEV_MODULE(callout_free, callout_free_load, NULL); >-- >2.22.0 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 238971
: 205503