cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

trace_printk.c (9106B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * trace binary printk
      4 *
      5 * Copyright (C) 2008 Lai Jiangshan <laijs@cn.fujitsu.com>
      6 *
      7 */
      8#include <linux/seq_file.h>
      9#include <linux/security.h>
     10#include <linux/uaccess.h>
     11#include <linux/kernel.h>
     12#include <linux/ftrace.h>
     13#include <linux/string.h>
     14#include <linux/module.h>
     15#include <linux/mutex.h>
     16#include <linux/ctype.h>
     17#include <linux/list.h>
     18#include <linux/slab.h>
     19
     20#include "trace.h"
     21
     22#ifdef CONFIG_MODULES
     23
     24/*
     25 * modules trace_printk()'s formats are autosaved in struct trace_bprintk_fmt
     26 * which are queued on trace_bprintk_fmt_list.
     27 */
     28static LIST_HEAD(trace_bprintk_fmt_list);
     29
     30/* serialize accesses to trace_bprintk_fmt_list */
     31static DEFINE_MUTEX(btrace_mutex);
     32
     33struct trace_bprintk_fmt {
     34	struct list_head list;
     35	const char *fmt;
     36};
     37
     38static inline struct trace_bprintk_fmt *lookup_format(const char *fmt)
     39{
     40	struct trace_bprintk_fmt *pos;
     41
     42	if (!fmt)
     43		return ERR_PTR(-EINVAL);
     44
     45	list_for_each_entry(pos, &trace_bprintk_fmt_list, list) {
     46		if (!strcmp(pos->fmt, fmt))
     47			return pos;
     48	}
     49	return NULL;
     50}
     51
     52static
     53void hold_module_trace_bprintk_format(const char **start, const char **end)
     54{
     55	const char **iter;
     56	char *fmt;
     57
     58	/* allocate the trace_printk per cpu buffers */
     59	if (start != end)
     60		trace_printk_init_buffers();
     61
     62	mutex_lock(&btrace_mutex);
     63	for (iter = start; iter < end; iter++) {
     64		struct trace_bprintk_fmt *tb_fmt = lookup_format(*iter);
     65		if (tb_fmt) {
     66			if (!IS_ERR(tb_fmt))
     67				*iter = tb_fmt->fmt;
     68			continue;
     69		}
     70
     71		fmt = NULL;
     72		tb_fmt = kmalloc(sizeof(*tb_fmt), GFP_KERNEL);
     73		if (tb_fmt) {
     74			fmt = kmalloc(strlen(*iter) + 1, GFP_KERNEL);
     75			if (fmt) {
     76				list_add_tail(&tb_fmt->list, &trace_bprintk_fmt_list);
     77				strcpy(fmt, *iter);
     78				tb_fmt->fmt = fmt;
     79			} else
     80				kfree(tb_fmt);
     81		}
     82		*iter = fmt;
     83
     84	}
     85	mutex_unlock(&btrace_mutex);
     86}
     87
     88static int module_trace_bprintk_format_notify(struct notifier_block *self,
     89		unsigned long val, void *data)
     90{
     91	struct module *mod = data;
     92	if (mod->num_trace_bprintk_fmt) {
     93		const char **start = mod->trace_bprintk_fmt_start;
     94		const char **end = start + mod->num_trace_bprintk_fmt;
     95
     96		if (val == MODULE_STATE_COMING)
     97			hold_module_trace_bprintk_format(start, end);
     98	}
     99	return NOTIFY_OK;
    100}
    101
    102/*
    103 * The debugfs/tracing/printk_formats file maps the addresses with
    104 * the ASCII formats that are used in the bprintk events in the
    105 * buffer. For userspace tools to be able to decode the events from
    106 * the buffer, they need to be able to map the address with the format.
    107 *
    108 * The addresses of the bprintk formats are in their own section
    109 * __trace_printk_fmt. But for modules we copy them into a link list.
    110 * The code to print the formats and their addresses passes around the
    111 * address of the fmt string. If the fmt address passed into the seq
    112 * functions is within the kernel core __trace_printk_fmt section, then
    113 * it simply uses the next pointer in the list.
    114 *
    115 * When the fmt pointer is outside the kernel core __trace_printk_fmt
    116 * section, then we need to read the link list pointers. The trick is
    117 * we pass the address of the string to the seq function just like
    118 * we do for the kernel core formats. To get back the structure that
    119 * holds the format, we simply use container_of() and then go to the
    120 * next format in the list.
    121 */
    122static const char **
    123find_next_mod_format(int start_index, void *v, const char **fmt, loff_t *pos)
    124{
    125	struct trace_bprintk_fmt *mod_fmt;
    126
    127	if (list_empty(&trace_bprintk_fmt_list))
    128		return NULL;
    129
    130	/*
    131	 * v will point to the address of the fmt record from t_next
    132	 * v will be NULL from t_start.
    133	 * If this is the first pointer or called from start
    134	 * then we need to walk the list.
    135	 */
    136	if (!v || start_index == *pos) {
    137		struct trace_bprintk_fmt *p;
    138
    139		/* search the module list */
    140		list_for_each_entry(p, &trace_bprintk_fmt_list, list) {
    141			if (start_index == *pos)
    142				return &p->fmt;
    143			start_index++;
    144		}
    145		/* pos > index */
    146		return NULL;
    147	}
    148
    149	/*
    150	 * v points to the address of the fmt field in the mod list
    151	 * structure that holds the module print format.
    152	 */
    153	mod_fmt = container_of(v, typeof(*mod_fmt), fmt);
    154	if (mod_fmt->list.next == &trace_bprintk_fmt_list)
    155		return NULL;
    156
    157	mod_fmt = container_of(mod_fmt->list.next, typeof(*mod_fmt), list);
    158
    159	return &mod_fmt->fmt;
    160}
    161
    162static void format_mod_start(void)
    163{
    164	mutex_lock(&btrace_mutex);
    165}
    166
    167static void format_mod_stop(void)
    168{
    169	mutex_unlock(&btrace_mutex);
    170}
    171
    172#else /* !CONFIG_MODULES */
    173__init static int
    174module_trace_bprintk_format_notify(struct notifier_block *self,
    175		unsigned long val, void *data)
    176{
    177	return NOTIFY_OK;
    178}
    179static inline const char **
    180find_next_mod_format(int start_index, void *v, const char **fmt, loff_t *pos)
    181{
    182	return NULL;
    183}
    184static inline void format_mod_start(void) { }
    185static inline void format_mod_stop(void) { }
    186#endif /* CONFIG_MODULES */
    187
    188static bool __read_mostly trace_printk_enabled = true;
    189
    190void trace_printk_control(bool enabled)
    191{
    192	trace_printk_enabled = enabled;
    193}
    194
    195__initdata_or_module static
    196struct notifier_block module_trace_bprintk_format_nb = {
    197	.notifier_call = module_trace_bprintk_format_notify,
    198};
    199
    200int __trace_bprintk(unsigned long ip, const char *fmt, ...)
    201{
    202	int ret;
    203	va_list ap;
    204
    205	if (unlikely(!fmt))
    206		return 0;
    207
    208	if (!trace_printk_enabled)
    209		return 0;
    210
    211	va_start(ap, fmt);
    212	ret = trace_vbprintk(ip, fmt, ap);
    213	va_end(ap);
    214	return ret;
    215}
    216EXPORT_SYMBOL_GPL(__trace_bprintk);
    217
    218int __ftrace_vbprintk(unsigned long ip, const char *fmt, va_list ap)
    219{
    220	if (unlikely(!fmt))
    221		return 0;
    222
    223	if (!trace_printk_enabled)
    224		return 0;
    225
    226	return trace_vbprintk(ip, fmt, ap);
    227}
    228EXPORT_SYMBOL_GPL(__ftrace_vbprintk);
    229
    230int __trace_printk(unsigned long ip, const char *fmt, ...)
    231{
    232	int ret;
    233	va_list ap;
    234
    235	if (!trace_printk_enabled)
    236		return 0;
    237
    238	va_start(ap, fmt);
    239	ret = trace_vprintk(ip, fmt, ap);
    240	va_end(ap);
    241	return ret;
    242}
    243EXPORT_SYMBOL_GPL(__trace_printk);
    244
    245int __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap)
    246{
    247	if (!trace_printk_enabled)
    248		return 0;
    249
    250	return trace_vprintk(ip, fmt, ap);
    251}
    252EXPORT_SYMBOL_GPL(__ftrace_vprintk);
    253
    254bool trace_is_tracepoint_string(const char *str)
    255{
    256	const char **ptr = __start___tracepoint_str;
    257
    258	for (ptr = __start___tracepoint_str; ptr < __stop___tracepoint_str; ptr++) {
    259		if (str == *ptr)
    260			return true;
    261	}
    262	return false;
    263}
    264
    265static const char **find_next(void *v, loff_t *pos)
    266{
    267	const char **fmt = v;
    268	int start_index;
    269	int last_index;
    270
    271	start_index = __stop___trace_bprintk_fmt - __start___trace_bprintk_fmt;
    272
    273	if (*pos < start_index)
    274		return __start___trace_bprintk_fmt + *pos;
    275
    276	/*
    277	 * The __tracepoint_str section is treated the same as the
    278	 * __trace_printk_fmt section. The difference is that the
    279	 * __trace_printk_fmt section should only be used by trace_printk()
    280	 * in a debugging environment, as if anything exists in that section
    281	 * the trace_prink() helper buffers are allocated, which would just
    282	 * waste space in a production environment.
    283	 *
    284	 * The __tracepoint_str sections on the other hand are used by
    285	 * tracepoints which need to map pointers to their strings to
    286	 * the ASCII text for userspace.
    287	 */
    288	last_index = start_index;
    289	start_index = __stop___tracepoint_str - __start___tracepoint_str;
    290
    291	if (*pos < last_index + start_index)
    292		return __start___tracepoint_str + (*pos - last_index);
    293
    294	start_index += last_index;
    295	return find_next_mod_format(start_index, v, fmt, pos);
    296}
    297
    298static void *
    299t_start(struct seq_file *m, loff_t *pos)
    300{
    301	format_mod_start();
    302	return find_next(NULL, pos);
    303}
    304
    305static void *t_next(struct seq_file *m, void * v, loff_t *pos)
    306{
    307	(*pos)++;
    308	return find_next(v, pos);
    309}
    310
    311static int t_show(struct seq_file *m, void *v)
    312{
    313	const char **fmt = v;
    314	const char *str = *fmt;
    315	int i;
    316
    317	if (!*fmt)
    318		return 0;
    319
    320	seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt);
    321
    322	/*
    323	 * Tabs and new lines need to be converted.
    324	 */
    325	for (i = 0; str[i]; i++) {
    326		switch (str[i]) {
    327		case '\n':
    328			seq_puts(m, "\\n");
    329			break;
    330		case '\t':
    331			seq_puts(m, "\\t");
    332			break;
    333		case '\\':
    334			seq_putc(m, '\\');
    335			break;
    336		case '"':
    337			seq_puts(m, "\\\"");
    338			break;
    339		default:
    340			seq_putc(m, str[i]);
    341		}
    342	}
    343	seq_puts(m, "\"\n");
    344
    345	return 0;
    346}
    347
    348static void t_stop(struct seq_file *m, void *p)
    349{
    350	format_mod_stop();
    351}
    352
    353static const struct seq_operations show_format_seq_ops = {
    354	.start = t_start,
    355	.next = t_next,
    356	.show = t_show,
    357	.stop = t_stop,
    358};
    359
    360static int
    361ftrace_formats_open(struct inode *inode, struct file *file)
    362{
    363	int ret;
    364
    365	ret = security_locked_down(LOCKDOWN_TRACEFS);
    366	if (ret)
    367		return ret;
    368
    369	return seq_open(file, &show_format_seq_ops);
    370}
    371
    372static const struct file_operations ftrace_formats_fops = {
    373	.open = ftrace_formats_open,
    374	.read = seq_read,
    375	.llseek = seq_lseek,
    376	.release = seq_release,
    377};
    378
    379static __init int init_trace_printk_function_export(void)
    380{
    381	int ret;
    382
    383	ret = tracing_init_dentry();
    384	if (ret)
    385		return 0;
    386
    387	trace_create_file("printk_formats", TRACE_MODE_READ, NULL,
    388				    NULL, &ftrace_formats_fops);
    389
    390	return 0;
    391}
    392
    393fs_initcall(init_trace_printk_function_export);
    394
    395static __init int init_trace_printk(void)
    396{
    397	return register_module_notifier(&module_trace_bprintk_format_nb);
    398}
    399
    400early_initcall(init_trace_printk);