lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Wed, 30 Nov 2011 12:56:47 -0700
From:	jim.cromie@...il.com
To:	jbaron@...hat.com
Cc:	greg@...ah.com, joe@...ches.com, bart.vanassche@...il.com,
	linux-kernel@...r.kernel.org, Jim Cromie <jim.cromie@...il.com>,
	Thomas Renninger <trenn@...e.de>,
	Rusty Russell <rusty@...tcorp.com.au>
Subject: [PATCH 18/25] dynamic_debug: Introduce global fake module param module.ddebug

From: Jim Cromie <jim.cromie@...il.com>

Rework Thomas Renninger's $module.ddebug boot-time debugging feature,
from https://lkml.org/lkml/2010/9/15/397

Dynamic Debug allows enabling of pr_debug and dev_dbg messages at
runtime.  This is controlled via $DBGFS/dynamic_debug/control.  One
major drawback is that the whole initialization of a module cannot be
tracked, because ddebug is only aware of debug strings of loaded
modules.  But this is the most interesting part...

This patch introduces a fake module parameter module.ddebug (not shown
in /sys/module/*/parameters, thus it does not use any resources).  If
a module passes ddebug as a module parameter (e.g. via module.ddebug
kernel boot param or via "modprobe module ddebug"), all debug strings
of this module get activated by issuing "module module_name +p"
internally (not via sysfs) when the module gets loaded.
A later patch extends this with an arg: module.ddebug="+mfp"

Modules must not use "ddebug" as module parameter or it will get
ignored.  If it's tried, a warning will show up at module load time
that it will get ignored (only works for not built-in modules).
TBD: how to use BUILD_BUG_ON() to detect this earlier ...

Originally tested (by Thomas) with (additional added pr_debug messages):
options hp-wmi ddebug
in modprobe.conf
-> works and pr_debug messages issued at module initialization time show
up. Also "p" flag gets set for the whole hp-wmi module:
grep hp-wmi /sys/../dynamic_debug/control
also tested with compiled-in modules, e.g. pnp.ddebug and an additional
patch later in the patch series which instruments pnp code to work with ddebug.

Signed-off-by: Jim Cromie <jim.cromie@...il.com>
CC: Thomas Renninger <trenn@...e.de>
CC: Rusty Russell <rusty@...tcorp.com.au>
---
 Documentation/dynamic-debug-howto.txt |   28 +++++++++++-
 include/linux/dynamic_debug.h         |   17 +++++++
 include/linux/moduleparam.h           |    3 +
 kernel/module.c                       |    1 +
 kernel/params.c                       |   13 +++++-
 lib/dynamic_debug.c                   |   82 ++++++++++++++++++++++++++++++++-
 6 files changed, 140 insertions(+), 4 deletions(-)

diff --git a/Documentation/dynamic-debug-howto.txt b/Documentation/dynamic-debug-howto.txt
index 989a892..269065d 100644
--- a/Documentation/dynamic-debug-howto.txt
+++ b/Documentation/dynamic-debug-howto.txt
@@ -219,7 +219,7 @@ Note also that there is no convenient syntax to remove all
 the flags at once, you need to use "-flmpt".
 
 
-Debug messages during boot process
+Debug messages during Boot Process
 ==================================
 
 To be able to activate debug messages during the boot process,
@@ -238,6 +238,32 @@ PCI (or other devices) initialization also is a hot candidate for using
 this boot parameter for debugging purposes.
 
 
+Debug Messages at Module Initialization Time
+============================================
+
+Enabling debug messages inside a module is only possible if the module itself
+is loaded already. If you unload a module, the dynamic debug flags associated
+to its debug messages are lost.
+Therefore, enabling debug messages that get processed at module initialization
+time through the <debugfs>/dynamic_debug/control interface is not possible.
+Instead, a "ddebug" module paramter can be passed:
+
+	- via kernel boot parameter:
+	  module.ddebug
+
+	- as an ordinary module parameter via modprobe
+	  modprobe module ddebug
+
+	- or the parameter can be used permanently via modprobe.conf(.local)
+	  options module ddebug
+
+The ddebug option is not implemented as an ordinary module parameter and thus
+will not show up in /sys/module/module_name/parameters/ddebug
+The settings can get reverted through the sysfs interface again when the
+module got loaded as soon as debug messages are not needed anymore:
+echo "module module_name -p" > <debugfs>/dynamic_debug/control
+as described in the "Command Language Reference" chapter above.
+
 Examples
 ========
 
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 7e3c53a..d6f5b5c 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -39,11 +39,18 @@ struct _ddebug {
 int ddebug_add_module(struct _ddebug *tab, unsigned int n,
 				const char *modname);
 
+struct kernel_param;
+
 #if defined(CONFIG_DYNAMIC_DEBUG)
 extern int ddebug_remove_module(const char *mod_name);
+
 extern __printf(2, 3)
 int __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...);
 
+extern int ddebug_exec_query(char *query_string);
+extern void ddebug_module_parse_args(const char *name, char* args,
+				struct kernel_param *params, unsigned num);
+
 struct device;
 
 extern __printf(3, 4)
@@ -98,6 +105,16 @@ static inline int ddebug_remove_module(const char *mod)
 {
 	return 0;
 }
+static inline int ddebug_exec_query(char *query_string)
+{
+	return 0;
+}
+static inline void ddebug_module_parse_args(const char *name, char* args,
+					struct kernel_param *params,
+					unsigned num)
+{
+	return 0;
+}
 
 #define dynamic_pr_debug(fmt, ...)					\
 	do { if (0) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); } while (0)
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index 7939f63..e62e5ce 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -433,4 +433,7 @@ static inline void module_param_sysfs_remove(struct module *mod)
 { }
 #endif
 
+/* For being able to parse parameters the same way params.c does */
+extern char *next_arg(char *args, char **param, char **val);
+
 #endif /* _LINUX_MODULE_PARAMS_H */
diff --git a/kernel/module.c b/kernel/module.c
index 30ffed4..3806d7e 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2892,6 +2892,7 @@ static struct module *load_module(void __user *umod,
 	list_add_rcu(&mod->list, &modules);
 	mutex_unlock(&module_mutex);
 
+	ddebug_module_parse_args(mod->name, mod->args, mod->kp, mod->num_kp);
 	/* Module is ready to execute: parsing args may do that. */
 	err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, NULL);
 	if (err < 0)
diff --git a/kernel/params.c b/kernel/params.c
index 65aae11..313ea84 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -98,6 +98,7 @@ static int parse_one(char *param,
 {
 	unsigned int i;
 	int err;
+	char *tmp;
 
 	/* Find parameter */
 	for (i = 0; i < num_params; i++) {
@@ -114,6 +115,16 @@ static int parse_one(char *param,
 		}
 	}
 
+	/*
+	 * Ignore ddebug module params and module.ddebug boot params:
+	 * Documentation/dynamic-debug-howto.txt
+	 */
+	tmp = strstr(param, ".ddebug");
+	if (parameq(param, "ddebug") || (tmp && strlen(tmp) == 7)) {
+		DEBUGP("Ignoring ddebug parameter %s\n", param);
+		return 0;
+	}
+
 	if (handle_unknown) {
 		DEBUGP("Unknown argument: calling %p\n", handle_unknown);
 		return handle_unknown(param, val);
@@ -125,7 +136,7 @@ static int parse_one(char *param,
 
 /* You can use " around spaces, but can't escape ". */
 /* Hyphens and underscores equivalent in parameter names. */
-static char *next_arg(char *args, char **param, char **val)
+char *next_arg(char *args, char **param, char **val)
 {
 	unsigned int i, equals = 0;
 	int in_quote = 0, quoted = 0;
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 516ad4e..bb66251 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -13,6 +13,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
 
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kallsyms.h>
@@ -34,6 +35,8 @@
 #include <linux/device.h>
 #include <linux/netdevice.h>
 
+#include <asm/setup.h>
+
 extern struct _ddebug __start___verbose[];
 extern struct _ddebug __stop___verbose[];
 
@@ -446,7 +449,7 @@ static int ddebug_parse_flags(const char *str, unsigned int *flagsp,
 	return 0;
 }
 
-static int ddebug_exec_query(char *query_string)
+int ddebug_exec_query(char *query_string)
 {
 	unsigned int flags = 0, mask = 0;
 	struct ddebug_query query;
@@ -454,6 +457,9 @@ static int ddebug_exec_query(char *query_string)
 	int nwords, nfound;
 	char *words[MAXWORDS];
 
+	if (verbose)
+		printk(KERN_INFO "%s: got query: %s\n", __func__, query_string);
+
 	nwords = ddebug_tokenize(query_string, words, MAXWORDS);
 	if (nwords <= 0)
 		return -EINVAL;
@@ -618,7 +624,7 @@ static __initdata char ddebug_setup_string[DDEBUG_STRING_SIZE];
 
 static __init int ddebug_setup_query(char *str)
 {
-	if (strlen(str) >= 1024) {
+	if (strlen(str) >= DDEBUG_STRING_SIZE) {
 		pr_warn("ddebug boot param string too large\n");
 		return 0;
 	}
@@ -872,6 +878,76 @@ int ddebug_add_module(struct _ddebug *tab, unsigned int n,
 }
 EXPORT_SYMBOL_GPL(ddebug_add_module);
 
+/* We search for *ddebug* module params */
+void ddebug_module_parse_args(const char *name, char* args,
+			      struct kernel_param *params, unsigned num)
+{
+	char ddebug[DDEBUG_STRING_SIZE], *param, *val, *args_it, *arg_dup_ptr;
+	int i;
+
+	/*
+	 * We must not modify the passed args string and need to store the
+	 * kstrdup pointer to be able to free memory later, TBD: find a way
+	 * to do this nicer
+	 */
+	arg_dup_ptr = args_it = kstrdup(args, GFP_KERNEL);
+
+	if (verbose)
+		printk(KERN_INFO "%s: Parsing ARGS: -%s- of %s\n",
+		       __func__, args_it, name);
+
+	for (i = 0; i < num; i++) {
+		if (!strcmp("ddebug", params[i].name))
+			pr_warning("Module %s uses reserved keyword "
+				   "*ddebug* as parameter\n", name);
+	}
+
+	/* Chew leading spaces */
+	args_it = skip_spaces(args_it);
+
+	while (*args_it) {
+		args_it = next_arg(args_it, &param, &val);
+		if (verbose)
+			printk(KERN_INFO "%s: Param: %s, val: %s\n",
+			       __func__, param, val);
+		if (!strcmp(param, "ddebug")) {
+			pr_info("Enabling debugging for module %s\n", name);
+			snprintf(ddebug, DDEBUG_STRING_SIZE, "module %s +p",
+				 name);
+			ddebug_exec_query(ddebug);
+		}
+	}
+	kfree(arg_dup_ptr);
+	if (verbose)
+		printk(KERN_INFO "%s: Finished %s parsing\n",  __func__, name);
+}
+/* We search for module.ddebug kernel boot params */
+static void ddebug_boot_parse_args(void)
+{
+	char tmp_cmd_arr[COMMAND_LINE_SIZE], *tmp_cmd_ptr, *param, *val, *tmp;
+	char module[MODULE_NAME_LEN], ddebug[DDEBUG_STRING_SIZE];
+
+	/* next_arg touches the passed buffer and chops each argument */
+	strlcpy(tmp_cmd_arr, saved_command_line, COMMAND_LINE_SIZE);
+	/* Chew leading spaces */
+	tmp_cmd_ptr = skip_spaces(tmp_cmd_arr);
+
+	while (*tmp_cmd_ptr) {
+		tmp_cmd_ptr = next_arg(tmp_cmd_ptr, &param, &val);
+		if (verbose)
+			printk(KERN_INFO "%s: Param: %s, val: %s\n",
+			       __func__, param, val);
+		tmp = strstr(param, ".ddebug");
+		if (tmp && strlen(tmp) == 7) {
+			strlcpy(module, param, tmp - param + 1);
+			pr_info("Enabling debugging for module %s\n", module);
+			snprintf(ddebug, DDEBUG_STRING_SIZE, "module %s +p",
+				 module);
+			ddebug_exec_query(ddebug);
+		}
+	}
+}
+
 static void ddebug_table_free(struct ddebug_table *dt)
 {
 	list_del_init(&dt->link);
@@ -979,6 +1055,8 @@ static int __init dynamic_debug_init(void)
 		ret = 0;
 	}
 
+	ddebug_boot_parse_args();
+
 out_free:
 	if (ret)
 		ddebug_remove_all_tables();
-- 
1.7.7.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ