[PATCH] livepatch: test_printk() patch

From: Petr Mladek
Date: Tue Mar 08 2016 - 07:51:02 EST


!!!!IMPORTANT!!!

The patch is a bit ugly because cmdline_proc_show() can be called
also by some other code. So, you might get the crash earlier than
you expect.
---
include/linux/printk.h | 3 +++
kernel/livepatch/core.c | 1 +
kernel/printk/printk.c | 23 +++++++++++++++++++++
samples/livepatch/livepatch-sample.c | 39 ++++++++++++++++++++++++++++++++++++
4 files changed, 66 insertions(+)

diff --git a/include/linux/printk.h b/include/linux/printk.h
index 9ccbdf2c1453..ffe0ceb56972 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -125,6 +125,9 @@ void early_printk(const char *s, ...) { }
typedef __printf(1, 0) int (*printk_func_t)(const char *fmt, va_list args);

#ifdef CONFIG_PRINTK
+int vprintk_default(const char *fmt, va_list args);
+int test_printk(const char *fmt, ...);
+
asmlinkage __printf(5, 0)
int vprintk_emit(int facility, int level,
const char *dict, size_t dictlen,
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index e2dbf0127f0f..7d0a6029043c 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -615,6 +615,7 @@ static ssize_t enabled_show(struct kobject *kobj,
struct klp_patch *patch;

patch = container_of(kobj, struct klp_patch, kobj);
+ printk("patch enabled: %d\n", patch->state);
return snprintf(buf, PAGE_SIZE-1, "%d\n", patch->state);
}

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index c963ba534a78..9f785bfbb3fd 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1920,6 +1920,29 @@ asmlinkage __visible int printk(const char *fmt, ...)
}
EXPORT_SYMBOL(printk);

+int test_printk(const char *fmt, ...)
+{
+ printk_func_t vprintk_func;
+ va_list args;
+ int r;
+
+ va_start(args, fmt);
+
+ /*
+ * If a caller overrides the per_cpu printk_func, then it needs
+ * to disable preemption when calling printk(). Otherwise
+ * the printk_func should be set to the default. No need to
+ * disable preemption here.
+ */
+ vprintk_func = this_cpu_read(printk_func);
+ r = vprintk_func(fmt, args);
+
+ va_end(args);
+
+ return r;
+}
+EXPORT_SYMBOL(test_printk);
+
#else /* CONFIG_PRINTK */

#define LOG_LINE_MAX 0
diff --git a/samples/livepatch/livepatch-sample.c b/samples/livepatch/livepatch-sample.c
index fb8c8614e728..d5c09bc629e8 100644
--- a/samples/livepatch/livepatch-sample.c
+++ b/samples/livepatch/livepatch-sample.c
@@ -40,16 +40,53 @@
*/

#include <linux/seq_file.h>
+#include <linux/printk.h>
static int livepatch_cmdline_proc_show(struct seq_file *m, void *v)
{
+ static int count;
+
+ if (!count++)
+ trace_printk("%s\n", "this has been live patched");
+ else
+ printk("%s\n", "this has been live patched");
+
seq_printf(m, "%s\n", "this has been live patched");
return 0;
}

+asmlinkage static int livepatch_printk(const char *fmt, ...)
+{
+ va_list args, args2;
+ int r = 0;
+
+ va_start(args, fmt);
+
+ /*
+ * If a caller overrides the per_cpu printk_func, then it needs
+ * to disable preemption when calling printk(). Otherwise
+ * the printk_func should be set to the default. No need to
+ * disable preemption here.
+ */
+ vprintk_default(fmt, args);
+
+ va_end(args);
+
+ va_start(args2, fmt);
+ ftrace_vprintk(fmt, args2);
+ va_end(args2);
+
+
+ return r;
+}
+
static struct klp_func funcs[] = {
{
.old_name = "cmdline_proc_show",
.new_func = livepatch_cmdline_proc_show,
+ },
+ {
+ .old_name = "printk",
+ .new_func = livepatch_printk,
}, { }
};

@@ -77,6 +114,8 @@ static int livepatch_init(void)
WARN_ON(klp_unregister_patch(&patch));
return ret;
}
+ /* Make sure that trace_printk buffers are allocated. */
+ trace_printk("LivePatch sample loaded\n");
return 0;
}

--
1.8.5.6