diff options
Diffstat (limited to 'kernel/trace')
| -rw-r--r-- | kernel/trace/bpf_trace.c | 203 | ||||
| -rw-r--r-- | kernel/trace/fgraph.c | 14 | ||||
| -rw-r--r-- | kernel/trace/fprobe.c | 7 | ||||
| -rw-r--r-- | kernel/trace/ftrace.c | 21 | ||||
| -rw-r--r-- | kernel/trace/ring_buffer.c | 2 | ||||
| -rw-r--r-- | kernel/trace/rv/monitors/sleep/sleep.c | 4 | ||||
| -rw-r--r-- | kernel/trace/rv/rv.c | 4 | ||||
| -rw-r--r-- | kernel/trace/trace.c | 35 | ||||
| -rw-r--r-- | kernel/trace/trace.h | 14 | ||||
| -rw-r--r-- | kernel/trace/trace_dynevent.c | 4 | ||||
| -rw-r--r-- | kernel/trace/trace_events.c | 3 | ||||
| -rw-r--r-- | kernel/trace/trace_events_user.c | 4 | ||||
| -rw-r--r-- | kernel/trace/trace_fprobe.c | 10 | ||||
| -rw-r--r-- | kernel/trace/trace_functions_graph.c | 22 | ||||
| -rw-r--r-- | kernel/trace/trace_kprobe.c | 13 | ||||
| -rw-r--r-- | kernel/trace/trace_osnoise.c | 10 | ||||
| -rw-r--r-- | kernel/trace/trace_probe.h | 9 | ||||
| -rw-r--r-- | kernel/trace/trace_sched_switch.c | 3 | ||||
| -rw-r--r-- | kernel/trace/trace_syscalls.c | 26 | ||||
| -rw-r--r-- | kernel/trace/trace_uprobe.c | 12 | ||||
| -rw-r--r-- | kernel/trace/tracing_map.c | 2 | 
21 files changed, 162 insertions, 260 deletions
| diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 3ae52978cae6..4f87c16d915a 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -22,7 +22,6 @@  #include <linux/bsearch.h>  #include <linux/sort.h>  #include <linux/key.h> -#include <linux/verification.h>  #include <linux/namei.h>  #include <net/bpf_sk_storage.h> @@ -900,7 +899,7 @@ const struct bpf_func_proto bpf_send_signal_thread_proto = {  	.arg1_type	= ARG_ANYTHING,  }; -BPF_CALL_3(bpf_d_path, struct path *, path, char *, buf, u32, sz) +BPF_CALL_3(bpf_d_path, const struct path *, path, char *, buf, u32, sz)  {  	struct path copy;  	long len; @@ -1241,188 +1240,6 @@ static const struct bpf_func_proto bpf_get_func_arg_cnt_proto = {  	.arg1_type	= ARG_PTR_TO_CTX,  }; -#ifdef CONFIG_KEYS -__bpf_kfunc_start_defs(); - -/** - * bpf_lookup_user_key - lookup a key by its serial - * @serial: key handle serial number - * @flags: lookup-specific flags - * - * Search a key with a given *serial* and the provided *flags*. - * If found, increment the reference count of the key by one, and - * return it in the bpf_key structure. - * - * The bpf_key structure must be passed to bpf_key_put() when done - * with it, so that the key reference count is decremented and the - * bpf_key structure is freed. - * - * Permission checks are deferred to the time the key is used by - * one of the available key-specific kfuncs. - * - * Set *flags* with KEY_LOOKUP_CREATE, to attempt creating a requested - * special keyring (e.g. session keyring), if it doesn't yet exist. - * Set *flags* with KEY_LOOKUP_PARTIAL, to lookup a key without waiting - * for the key construction, and to retrieve uninstantiated keys (keys - * without data attached to them). - * - * Return: a bpf_key pointer with a valid key pointer if the key is found, a - *         NULL pointer otherwise. - */ -__bpf_kfunc struct bpf_key *bpf_lookup_user_key(s32 serial, u64 flags) -{ -	key_ref_t key_ref; -	struct bpf_key *bkey; - -	if (flags & ~KEY_LOOKUP_ALL) -		return NULL; - -	/* -	 * Permission check is deferred until the key is used, as the -	 * intent of the caller is unknown here. -	 */ -	key_ref = lookup_user_key(serial, flags, KEY_DEFER_PERM_CHECK); -	if (IS_ERR(key_ref)) -		return NULL; - -	bkey = kmalloc(sizeof(*bkey), GFP_KERNEL); -	if (!bkey) { -		key_put(key_ref_to_ptr(key_ref)); -		return NULL; -	} - -	bkey->key = key_ref_to_ptr(key_ref); -	bkey->has_ref = true; - -	return bkey; -} - -/** - * bpf_lookup_system_key - lookup a key by a system-defined ID - * @id: key ID - * - * Obtain a bpf_key structure with a key pointer set to the passed key ID. - * The key pointer is marked as invalid, to prevent bpf_key_put() from - * attempting to decrement the key reference count on that pointer. The key - * pointer set in such way is currently understood only by - * verify_pkcs7_signature(). - * - * Set *id* to one of the values defined in include/linux/verification.h: - * 0 for the primary keyring (immutable keyring of system keys); - * VERIFY_USE_SECONDARY_KEYRING for both the primary and secondary keyring - * (where keys can be added only if they are vouched for by existing keys - * in those keyrings); VERIFY_USE_PLATFORM_KEYRING for the platform - * keyring (primarily used by the integrity subsystem to verify a kexec'ed - * kerned image and, possibly, the initramfs signature). - * - * Return: a bpf_key pointer with an invalid key pointer set from the - *         pre-determined ID on success, a NULL pointer otherwise - */ -__bpf_kfunc struct bpf_key *bpf_lookup_system_key(u64 id) -{ -	struct bpf_key *bkey; - -	if (system_keyring_id_check(id) < 0) -		return NULL; - -	bkey = kmalloc(sizeof(*bkey), GFP_ATOMIC); -	if (!bkey) -		return NULL; - -	bkey->key = (struct key *)(unsigned long)id; -	bkey->has_ref = false; - -	return bkey; -} - -/** - * bpf_key_put - decrement key reference count if key is valid and free bpf_key - * @bkey: bpf_key structure - * - * Decrement the reference count of the key inside *bkey*, if the pointer - * is valid, and free *bkey*. - */ -__bpf_kfunc void bpf_key_put(struct bpf_key *bkey) -{ -	if (bkey->has_ref) -		key_put(bkey->key); - -	kfree(bkey); -} - -#ifdef CONFIG_SYSTEM_DATA_VERIFICATION -/** - * bpf_verify_pkcs7_signature - verify a PKCS#7 signature - * @data_p: data to verify - * @sig_p: signature of the data - * @trusted_keyring: keyring with keys trusted for signature verification - * - * Verify the PKCS#7 signature *sig_ptr* against the supplied *data_ptr* - * with keys in a keyring referenced by *trusted_keyring*. - * - * Return: 0 on success, a negative value on error. - */ -__bpf_kfunc int bpf_verify_pkcs7_signature(struct bpf_dynptr *data_p, -			       struct bpf_dynptr *sig_p, -			       struct bpf_key *trusted_keyring) -{ -	struct bpf_dynptr_kern *data_ptr = (struct bpf_dynptr_kern *)data_p; -	struct bpf_dynptr_kern *sig_ptr = (struct bpf_dynptr_kern *)sig_p; -	const void *data, *sig; -	u32 data_len, sig_len; -	int ret; - -	if (trusted_keyring->has_ref) { -		/* -		 * Do the permission check deferred in bpf_lookup_user_key(). -		 * See bpf_lookup_user_key() for more details. -		 * -		 * A call to key_task_permission() here would be redundant, as -		 * it is already done by keyring_search() called by -		 * find_asymmetric_key(). -		 */ -		ret = key_validate(trusted_keyring->key); -		if (ret < 0) -			return ret; -	} - -	data_len = __bpf_dynptr_size(data_ptr); -	data = __bpf_dynptr_data(data_ptr, data_len); -	sig_len = __bpf_dynptr_size(sig_ptr); -	sig = __bpf_dynptr_data(sig_ptr, sig_len); - -	return verify_pkcs7_signature(data, data_len, sig, sig_len, -				      trusted_keyring->key, -				      VERIFYING_UNSPECIFIED_SIGNATURE, NULL, -				      NULL); -} -#endif /* CONFIG_SYSTEM_DATA_VERIFICATION */ - -__bpf_kfunc_end_defs(); - -BTF_KFUNCS_START(key_sig_kfunc_set) -BTF_ID_FLAGS(func, bpf_lookup_user_key, KF_ACQUIRE | KF_RET_NULL | KF_SLEEPABLE) -BTF_ID_FLAGS(func, bpf_lookup_system_key, KF_ACQUIRE | KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_key_put, KF_RELEASE) -#ifdef CONFIG_SYSTEM_DATA_VERIFICATION -BTF_ID_FLAGS(func, bpf_verify_pkcs7_signature, KF_SLEEPABLE) -#endif -BTF_KFUNCS_END(key_sig_kfunc_set) - -static const struct btf_kfunc_id_set bpf_key_sig_kfunc_set = { -	.owner = THIS_MODULE, -	.set = &key_sig_kfunc_set, -}; - -static int __init bpf_key_sig_kfuncs_init(void) -{ -	return register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, -					 &bpf_key_sig_kfunc_set); -} - -late_initcall(bpf_key_sig_kfuncs_init); -#endif /* CONFIG_KEYS */ -  static const struct bpf_func_proto *  bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)  { @@ -1521,8 +1338,6 @@ static bool kprobe_prog_is_valid_access(int off, int size, enum bpf_access_type  {  	if (off < 0 || off >= sizeof(struct pt_regs))  		return false; -	if (type != BPF_READ) -		return false;  	if (off % size != 0)  		return false;  	/* @@ -1532,6 +1347,9 @@ static bool kprobe_prog_is_valid_access(int off, int size, enum bpf_access_type  	if (off + size > sizeof(struct pt_regs))  		return false; +	if (type == BPF_WRITE) +		prog->aux->kprobe_write_ctx = true; +  	return true;  } @@ -2728,20 +2546,25 @@ kprobe_multi_link_prog_run(struct bpf_kprobe_multi_link *link,  	struct pt_regs *regs;  	int err; +	/* +	 * graph tracer framework ensures we won't migrate, so there is no need +	 * to use migrate_disable for bpf_prog_run again. The check here just for +	 * __this_cpu_inc_return. +	 */ +	cant_sleep(); +  	if (unlikely(__this_cpu_inc_return(bpf_prog_active) != 1)) {  		bpf_prog_inc_misses_counter(link->link.prog);  		err = 1;  		goto out;  	} -	migrate_disable();  	rcu_read_lock();  	regs = ftrace_partial_regs(fregs, bpf_kprobe_multi_pt_regs_ptr());  	old_run_ctx = bpf_set_run_ctx(&run_ctx.session_ctx.run_ctx);  	err = bpf_prog_run(link->link.prog, regs);  	bpf_reset_run_ctx(old_run_ctx);  	rcu_read_unlock(); -	migrate_enable();   out:  	__this_cpu_dec(bpf_prog_active); @@ -2913,6 +2736,10 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr  	if (!is_kprobe_multi(prog))  		return -EINVAL; +	/* Writing to context is not allowed for kprobes. */ +	if (prog->aux->kprobe_write_ctx) +		return -EINVAL; +  	flags = attr->link_create.kprobe_multi.flags;  	if (flags & ~BPF_F_KPROBE_MULTI_RETURN)  		return -EINVAL; diff --git a/kernel/trace/fgraph.c b/kernel/trace/fgraph.c index f4d200f0c610..484ad7a18463 100644 --- a/kernel/trace/fgraph.c +++ b/kernel/trace/fgraph.c @@ -815,6 +815,7 @@ __ftrace_return_to_handler(struct ftrace_regs *fregs, unsigned long frame_pointe  	unsigned long bitmap;  	unsigned long ret;  	int offset; +	int bit;  	int i;  	ret_stack = ftrace_pop_return_trace(&trace, &ret, frame_pointer, &offset); @@ -829,6 +830,15 @@ __ftrace_return_to_handler(struct ftrace_regs *fregs, unsigned long frame_pointe  	if (fregs)  		ftrace_regs_set_instruction_pointer(fregs, ret); +	bit = ftrace_test_recursion_trylock(trace.func, ret); +	/* +	 * This can fail because ftrace_test_recursion_trylock() allows one nest +	 * call. If we are already in a nested call, then we don't probe this and +	 * just return the original return address. +	 */ +	if (unlikely(bit < 0)) +		goto out; +  #ifdef CONFIG_FUNCTION_GRAPH_RETVAL  	trace.retval = ftrace_regs_get_return_value(fregs);  #endif @@ -852,6 +862,8 @@ __ftrace_return_to_handler(struct ftrace_regs *fregs, unsigned long frame_pointe  		}  	} +	ftrace_test_recursion_unlock(bit); +out:  	/*  	 * The ftrace_graph_return() may still access the current  	 * ret_stack structure, we need to make sure the update of @@ -1397,6 +1409,8 @@ error:  		ftrace_graph_active--;  		gops->saved_func = NULL;  		fgraph_lru_release_index(i); +		if (!ftrace_graph_active) +			unregister_pm_notifier(&ftrace_suspend_notifier);  	}  	return ret;  } diff --git a/kernel/trace/fprobe.c b/kernel/trace/fprobe.c index c8034dfc1070..5a807d62e76d 100644 --- a/kernel/trace/fprobe.c +++ b/kernel/trace/fprobe.c @@ -428,8 +428,9 @@ static int fprobe_addr_list_add(struct fprobe_addr_list *alist, unsigned long ad  {  	unsigned long *addrs; -	if (alist->index >= alist->size) -		return -ENOMEM; +	/* Previously we failed to expand the list. */ +	if (alist->index == alist->size) +		return -ENOSPC;  	alist->addrs[alist->index++] = addr;  	if (alist->index < alist->size) @@ -489,7 +490,7 @@ static int fprobe_module_callback(struct notifier_block *nb,  	for (i = 0; i < FPROBE_IP_TABLE_SIZE; i++)  		fprobe_remove_node_in_module(mod, &fprobe_ip_table[i], &alist); -	if (alist.index < alist.size && alist.index > 0) +	if (alist.index > 0)  		ftrace_set_filter_ips(&fprobe_graph_ops.ops,  				      alist.addrs, alist.index, 1, 0);  	mutex_unlock(&fprobe_mutex); diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 00b76d450a89..42bd2ba68a82 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -4661,13 +4661,17 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag,  	        } else {  			iter->hash = alloc_and_copy_ftrace_hash(size_bits, hash);  		} +	} else { +		if (hash) +			iter->hash = alloc_and_copy_ftrace_hash(hash->size_bits, hash); +		else +			iter->hash = EMPTY_HASH; +	} -		if (!iter->hash) { -			trace_parser_put(&iter->parser); -			goto out_unlock; -		} -	} else -		iter->hash = hash; +	if (!iter->hash) { +		trace_parser_put(&iter->parser); +		goto out_unlock; +	}  	ret = 0; @@ -6543,9 +6547,6 @@ int ftrace_regex_release(struct inode *inode, struct file *file)  		ftrace_hash_move_and_update_ops(iter->ops, orig_hash,  						      iter->hash, filter_hash);  		mutex_unlock(&ftrace_lock); -	} else { -		/* For read only, the hash is the ops hash */ -		iter->hash = NULL;  	}  	mutex_unlock(&iter->ops->func_hash->regex_lock); @@ -7534,6 +7535,8 @@ void ftrace_module_enable(struct module *mod)  		if (!within_module(rec->ip, mod))  			break; +		cond_resched(); +  		/* Weak functions should still be ignored */  		if (!test_for_valid_rec(rec)) {  			/* Clear all other flags. Should not be enabled anyway */ diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index bb71a0dc9d69..43460949ad3f 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -7666,7 +7666,7 @@ static __init int test_ringbuffer(void)  	rb_test_started = true;  	set_current_state(TASK_INTERRUPTIBLE); -	/* Just run for 10 seconds */; +	/* Just run for 10 seconds */  	schedule_timeout(10 * HZ);  	kthread_stop(rb_hammer); diff --git a/kernel/trace/rv/monitors/sleep/sleep.c b/kernel/trace/rv/monitors/sleep/sleep.c index eea447b06907..c1347da69e9d 100644 --- a/kernel/trace/rv/monitors/sleep/sleep.c +++ b/kernel/trace/rv/monitors/sleep/sleep.c @@ -127,7 +127,9 @@ static void handle_sys_enter(void *data, struct pt_regs *regs, long id)  	mon = ltl_get_monitor(current);  	switch (id) { +#ifdef __NR_clock_nanosleep  	case __NR_clock_nanosleep: +#endif  #ifdef __NR_clock_nanosleep_time64  	case __NR_clock_nanosleep_time64:  #endif @@ -138,7 +140,9 @@ static void handle_sys_enter(void *data, struct pt_regs *regs, long id)  		ltl_atom_update(current, LTL_CLOCK_NANOSLEEP, true);  		break; +#ifdef __NR_futex  	case __NR_futex: +#endif  #ifdef __NR_futex_time64  	case __NR_futex_time64:  #endif diff --git a/kernel/trace/rv/rv.c b/kernel/trace/rv/rv.c index 1482e91c39f4..48338520376f 100644 --- a/kernel/trace/rv/rv.c +++ b/kernel/trace/rv/rv.c @@ -495,7 +495,7 @@ static void *available_monitors_next(struct seq_file *m, void *p, loff_t *pos)   */  static void *enabled_monitors_next(struct seq_file *m, void *p, loff_t *pos)  { -	struct rv_monitor *mon = p; +	struct rv_monitor *mon = container_of(p, struct rv_monitor, list);  	(*pos)++; @@ -805,7 +805,7 @@ int rv_register_monitor(struct rv_monitor *monitor, struct rv_monitor *parent)  	retval = create_monitor_dir(monitor, parent);  	if (retval) -		return retval; +		goto out_unlock;  	/* keep children close to the parent for easier visualisation */  	if (parent) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 4283ed4e8f59..156e7e0bf559 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -834,7 +834,10 @@ int trace_pid_write(struct trace_pid_list *filtered_pids,  		/* copy the current bits to the new max */  		ret = trace_pid_list_first(filtered_pids, &pid);  		while (!ret) { -			trace_pid_list_set(pid_list, pid); +			ret = trace_pid_list_set(pid_list, pid); +			if (ret < 0) +				goto out; +  			ret = trace_pid_list_next(filtered_pids, pid + 1, &pid);  			nr_pids++;  		} @@ -871,6 +874,7 @@ int trace_pid_write(struct trace_pid_list *filtered_pids,  		trace_parser_clear(&parser);  		ret = 0;  	} + out:  	trace_parser_put(&parser);  	if (ret < 0) { @@ -1816,7 +1820,7 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,  	ret = get_user(ch, ubuf++);  	if (ret) -		return ret; +		goto fail;  	read++;  	cnt--; @@ -1830,7 +1834,7 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,  		while (cnt && isspace(ch)) {  			ret = get_user(ch, ubuf++);  			if (ret) -				return ret; +				goto fail;  			read++;  			cnt--;  		} @@ -1848,12 +1852,14 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,  	while (cnt && !isspace(ch) && ch) {  		if (parser->idx < parser->size - 1)  			parser->buffer[parser->idx++] = ch; -		else -			return -EINVAL; +		else { +			ret = -EINVAL; +			goto fail; +		}  		ret = get_user(ch, ubuf++);  		if (ret) -			return ret; +			goto fail;  		read++;  		cnt--;  	} @@ -1868,11 +1874,15 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,  		/* Make sure the parsed string always terminates with '\0'. */  		parser->buffer[parser->idx] = 0;  	} else { -		return -EINVAL; +		ret = -EINVAL; +		goto fail;  	}  	*ppos += read;  	return read; +fail: +	trace_parser_fail(parser); +	return ret;  }  /* TODO add a seq_buf_to_buffer() */ @@ -7203,7 +7213,7 @@ static ssize_t write_marker_to_buffer(struct trace_array *tr, const char __user  	entry = ring_buffer_event_data(event);  	entry->ip = ip; -	len = __copy_from_user_inatomic(&entry->buf, ubuf, cnt); +	len = copy_from_user_nofault(&entry->buf, ubuf, cnt);  	if (len) {  		memcpy(&entry->buf, FAULTED_STR, FAULTED_SIZE);  		cnt = FAULTED_SIZE; @@ -7300,7 +7310,7 @@ static ssize_t write_raw_marker_to_buffer(struct trace_array *tr,  	entry = ring_buffer_event_data(event); -	len = __copy_from_user_inatomic(&entry->id, ubuf, cnt); +	len = copy_from_user_nofault(&entry->id, ubuf, cnt);  	if (len) {  		entry->id = -1;  		memcpy(&entry->buf, FAULTED_STR, FAULTED_SIZE); @@ -10201,8 +10211,7 @@ static struct vfsmount *trace_automount(struct dentry *mntpt, void *ingore)  	pr_warn("NOTICE: Automounting of tracing to debugfs is deprecated and will be removed in 2030\n"); -	ret = vfs_parse_fs_string(fc, "source", -				  "tracefs", strlen("tracefs")); +	ret = vfs_parse_fs_string(fc, "source", "tracefs");  	if (!ret)  		mnt = fc_mount(fc);  	else @@ -10632,10 +10641,10 @@ static void ftrace_dump_one(struct trace_array *tr, enum ftrace_dump_mode dump_m  			ret = print_trace_line(&iter);  			if (ret != TRACE_TYPE_NO_CONSUME)  				trace_consume(&iter); + +			trace_printk_seq(&iter.seq);  		}  		touch_nmi_watchdog(); - -		trace_printk_seq(&iter.seq);  	}  	if (!cnt) diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 1dbf1d3cf2f1..85eabb454bee 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -380,8 +380,8 @@ struct trace_array {  #ifdef CONFIG_FTRACE_SYSCALLS  	int			sys_refcount_enter;  	int			sys_refcount_exit; -	struct trace_event_file __rcu *enter_syscall_files[NR_syscalls]; -	struct trace_event_file __rcu *exit_syscall_files[NR_syscalls]; +	struct trace_event_file	*enter_syscall_files[NR_syscalls]; +	struct trace_event_file	*exit_syscall_files[NR_syscalls];  #endif  	int			stop_count;  	int			clock_id; @@ -1292,6 +1292,7 @@ bool ftrace_event_is_function(struct trace_event_call *call);   */  struct trace_parser {  	bool		cont; +	bool		fail;  	char		*buffer;  	unsigned	idx;  	unsigned	size; @@ -1299,7 +1300,7 @@ struct trace_parser {  static inline bool trace_parser_loaded(struct trace_parser *parser)  { -	return (parser->idx != 0); +	return !parser->fail && parser->idx != 0;  }  static inline bool trace_parser_cont(struct trace_parser *parser) @@ -1313,6 +1314,11 @@ static inline void trace_parser_clear(struct trace_parser *parser)  	parser->idx = 0;  } +static inline void trace_parser_fail(struct trace_parser *parser) +{ +	parser->fail = true; +} +  extern int trace_parser_get_init(struct trace_parser *parser, int size);  extern void trace_parser_put(struct trace_parser *parser);  extern int trace_get_user(struct trace_parser *parser, const char __user *ubuf, @@ -2204,7 +2210,7 @@ static inline bool is_good_system_name(const char *name)  static inline void sanitize_event_name(char *name)  {  	while (*name++ != '\0') -		if (*name == ':' || *name == '.') +		if (*name == ':' || *name == '.' || *name == '*')  			*name = '_';  } diff --git a/kernel/trace/trace_dynevent.c b/kernel/trace/trace_dynevent.c index 5d64a18cacac..d06854bd32b3 100644 --- a/kernel/trace/trace_dynevent.c +++ b/kernel/trace/trace_dynevent.c @@ -230,6 +230,10 @@ static int dyn_event_open(struct inode *inode, struct file *file)  {  	int ret; +	ret = security_locked_down(LOCKDOWN_TRACEFS); +	if (ret) +		return ret; +  	ret = tracing_check_open_get_tr(NULL);  	if (ret)  		return ret; diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 9f3e9537417d..e00da4182deb 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -1629,11 +1629,10 @@ static void *s_start(struct seq_file *m, loff_t *pos)  	loff_t l;  	iter = kzalloc(sizeof(*iter), GFP_KERNEL); +	mutex_lock(&event_mutex);  	if (!iter)  		return NULL; -	mutex_lock(&event_mutex); -  	iter->type = SET_EVENT_FILE;  	iter->file = list_entry(&tr->events, struct trace_event_file, list); diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c index af42aaa3d172..c428dafe7496 100644 --- a/kernel/trace/trace_events_user.c +++ b/kernel/trace/trace_events_user.c @@ -496,7 +496,7 @@ static bool user_event_enabler_queue_fault(struct user_event_mm *mm,  {  	struct user_event_enabler_fault *fault; -	fault = kmem_cache_zalloc(fault_cache, GFP_NOWAIT | __GFP_NOWARN); +	fault = kmem_cache_zalloc(fault_cache, GFP_NOWAIT);  	if (!fault)  		return false; @@ -835,7 +835,7 @@ void user_event_mm_remove(struct task_struct *t)  	 * so we use a work queue after call_rcu() to run within.  	 */  	INIT_RCU_WORK(&mm->put_rwork, delayed_user_event_mm_put); -	queue_rcu_work(system_wq, &mm->put_rwork); +	queue_rcu_work(system_percpu_wq, &mm->put_rwork);  }  void user_event_mm_dup(struct task_struct *t, struct user_event_mm *old_mm) diff --git a/kernel/trace/trace_fprobe.c b/kernel/trace/trace_fprobe.c index b36ade43d4b3..ad9d6347b5fa 100644 --- a/kernel/trace/trace_fprobe.c +++ b/kernel/trace/trace_fprobe.c @@ -522,13 +522,14 @@ static int fentry_dispatcher(struct fprobe *fp, unsigned long entry_ip,  			     void *entry_data)  {  	struct trace_fprobe *tf = container_of(fp, struct trace_fprobe, fp); +	unsigned int flags = trace_probe_load_flag(&tf->tp);  	int ret = 0; -	if (trace_probe_test_flag(&tf->tp, TP_FLAG_TRACE)) +	if (flags & TP_FLAG_TRACE)  		fentry_trace_func(tf, entry_ip, fregs);  #ifdef CONFIG_PERF_EVENTS -	if (trace_probe_test_flag(&tf->tp, TP_FLAG_PROFILE)) +	if (flags & TP_FLAG_PROFILE)  		ret = fentry_perf_func(tf, entry_ip, fregs);  #endif  	return ret; @@ -540,11 +541,12 @@ static void fexit_dispatcher(struct fprobe *fp, unsigned long entry_ip,  			     void *entry_data)  {  	struct trace_fprobe *tf = container_of(fp, struct trace_fprobe, fp); +	unsigned int flags = trace_probe_load_flag(&tf->tp); -	if (trace_probe_test_flag(&tf->tp, TP_FLAG_TRACE)) +	if (flags & TP_FLAG_TRACE)  		fexit_trace_func(tf, entry_ip, ret_ip, fregs, entry_data);  #ifdef CONFIG_PERF_EVENTS -	if (trace_probe_test_flag(&tf->tp, TP_FLAG_PROFILE)) +	if (flags & TP_FLAG_PROFILE)  		fexit_perf_func(tf, entry_ip, ret_ip, fregs, entry_data);  #endif  } diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 66e1a527cf1a..a7f4b9a47a71 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c @@ -27,14 +27,21 @@ struct fgraph_cpu_data {  	unsigned long	enter_funcs[FTRACE_RETFUNC_DEPTH];  }; +struct fgraph_ent_args { +	struct ftrace_graph_ent_entry	ent; +	/* Force the sizeof of args[] to have FTRACE_REGS_MAX_ARGS entries */ +	unsigned long			args[FTRACE_REGS_MAX_ARGS]; +}; +  struct fgraph_data {  	struct fgraph_cpu_data __percpu *cpu_data;  	/* Place to preserve last processed entry. */  	union { -		struct ftrace_graph_ent_entry	ent; +		struct fgraph_ent_args		ent; +		/* TODO allow retaddr to have args */  		struct fgraph_retaddr_ent_entry	rent; -	} ent; +	};  	struct ftrace_graph_ret_entry	ret;  	int				failed;  	int				cpu; @@ -627,10 +634,13 @@ get_return_for_leaf(struct trace_iterator *iter,  			 * Save current and next entries for later reference  			 * if the output fails.  			 */ -			if (unlikely(curr->ent.type == TRACE_GRAPH_RETADDR_ENT)) -				data->ent.rent = *(struct fgraph_retaddr_ent_entry *)curr; -			else -				data->ent.ent = *curr; +			if (unlikely(curr->ent.type == TRACE_GRAPH_RETADDR_ENT)) { +				data->rent = *(struct fgraph_retaddr_ent_entry *)curr; +			} else { +				int size = min((int)sizeof(data->ent), (int)iter->ent_size); + +				memcpy(&data->ent, curr, size); +			}  			/*  			 * If the next event is not a return type, then  			 * we only care about what type it is. Otherwise we can diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index ccae62d4fb91..ee8171b19bee 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -908,6 +908,8 @@ static int trace_kprobe_create_internal(int argc, const char *argv[],  			return -EINVAL;  		}  		buf = kmemdup(&argv[0][1], len + 1, GFP_KERNEL); +		if (!buf) +			return -ENOMEM;  		buf[len] = '\0';  		ret = kstrtouint(buf, 0, &maxactive);  		if (ret || !maxactive) { @@ -1813,14 +1815,15 @@ static int kprobe_register(struct trace_event_call *event,  static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs)  {  	struct trace_kprobe *tk = container_of(kp, struct trace_kprobe, rp.kp); +	unsigned int flags = trace_probe_load_flag(&tk->tp);  	int ret = 0;  	raw_cpu_inc(*tk->nhit); -	if (trace_probe_test_flag(&tk->tp, TP_FLAG_TRACE)) +	if (flags & TP_FLAG_TRACE)  		kprobe_trace_func(tk, regs);  #ifdef CONFIG_PERF_EVENTS -	if (trace_probe_test_flag(&tk->tp, TP_FLAG_PROFILE)) +	if (flags & TP_FLAG_PROFILE)  		ret = kprobe_perf_func(tk, regs);  #endif  	return ret; @@ -1832,6 +1835,7 @@ kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs)  {  	struct kretprobe *rp = get_kretprobe(ri);  	struct trace_kprobe *tk; +	unsigned int flags;  	/*  	 * There is a small chance that get_kretprobe(ri) returns NULL when @@ -1844,10 +1848,11 @@ kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs)  	tk = container_of(rp, struct trace_kprobe, rp);  	raw_cpu_inc(*tk->nhit); -	if (trace_probe_test_flag(&tk->tp, TP_FLAG_TRACE)) +	flags = trace_probe_load_flag(&tk->tp); +	if (flags & TP_FLAG_TRACE)  		kretprobe_trace_func(tk, ri, regs);  #ifdef CONFIG_PERF_EVENTS -	if (trace_probe_test_flag(&tk->tp, TP_FLAG_PROFILE)) +	if (flags & TP_FLAG_PROFILE)  		kretprobe_perf_func(tk, ri, regs);  #endif  	return 0;	/* We don't tweak kernel, so just return 0 */ diff --git a/kernel/trace/trace_osnoise.c b/kernel/trace/trace_osnoise.c index fd259da0aa64..12ee346820da 100644 --- a/kernel/trace/trace_osnoise.c +++ b/kernel/trace/trace_osnoise.c @@ -271,7 +271,7 @@ static inline void tlat_var_reset(void)  	 * So far, all the values are initialized as 0, so  	 * zeroing the structure is perfect.  	 */ -	for_each_cpu(cpu, cpu_online_mask) { +	for_each_online_cpu(cpu) {  		tlat_var = per_cpu_ptr(&per_cpu_timerlat_var, cpu);  		if (tlat_var->kthread)  			hrtimer_cancel(&tlat_var->timer); @@ -295,7 +295,7 @@ static inline void osn_var_reset(void)  	 * So far, all the values are initialized as 0, so  	 * zeroing the structure is perfect.  	 */ -	for_each_cpu(cpu, cpu_online_mask) { +	for_each_online_cpu(cpu) {  		osn_var = per_cpu_ptr(&per_cpu_osnoise_var, cpu);  		memset(osn_var, 0, sizeof(*osn_var));  	} @@ -2322,12 +2322,16 @@ osnoise_cpus_write(struct file *filp, const char __user *ubuf, size_t count,  	int running, err;  	char *buf __free(kfree) = NULL; -	buf = kmalloc(count, GFP_KERNEL); +	if (count < 1) +		return 0; + +	buf = kmalloc(count + 1, GFP_KERNEL);  	if (!buf)  		return -ENOMEM;  	if (copy_from_user(buf, ubuf, count))  		return -EFAULT; +	buf[count] = '\0';  	if (!zalloc_cpumask_var(&osnoise_cpumask_new, GFP_KERNEL))  		return -ENOMEM; diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index 842383fbc03b..08b5bda24da2 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -271,16 +271,21 @@ struct event_file_link {  	struct list_head		list;  }; +static inline unsigned int trace_probe_load_flag(struct trace_probe *tp) +{ +	return smp_load_acquire(&tp->event->flags); +} +  static inline bool trace_probe_test_flag(struct trace_probe *tp,  					 unsigned int flag)  { -	return !!(tp->event->flags & flag); +	return !!(trace_probe_load_flag(tp) & flag);  }  static inline void trace_probe_set_flag(struct trace_probe *tp,  					unsigned int flag)  { -	tp->event->flags |= flag; +	smp_store_release(&tp->event->flags, tp->event->flags | flag);  }  static inline void trace_probe_clear_flag(struct trace_probe *tp, diff --git a/kernel/trace/trace_sched_switch.c b/kernel/trace/trace_sched_switch.c index cb49f7279dc8..c46d584ded3b 100644 --- a/kernel/trace/trace_sched_switch.c +++ b/kernel/trace/trace_sched_switch.c @@ -224,7 +224,6 @@ static struct saved_cmdlines_buffer *allocate_cmdlines_buffer(unsigned int val)  	/* Place map_cmdline_to_pid array right after saved_cmdlines */  	s->map_cmdline_to_pid = (unsigned *)&s->saved_cmdlines[val * TASK_COMM_LEN]; -	s->cmdline_idx = 0;  	memset(&s->map_pid_to_cmdline, NO_CMDLINE_MAP,  	       sizeof(s->map_pid_to_cmdline));  	memset(s->map_cmdline_to_pid, NO_CMDLINE_MAP, @@ -248,6 +247,8 @@ int trace_save_cmdline(struct task_struct *tsk)  	if (!tsk->pid)  		return 1; +	BUILD_BUG_ON(!is_power_of_2(PID_MAX_DEFAULT)); +  	tpid = tsk->pid & (PID_MAX_DEFAULT - 1);  	/* diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 46aab0ab9350..0f932b22f9ec 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -153,14 +153,20 @@ print_syscall_enter(struct trace_iterator *iter, int flags,  		if (trace_seq_has_overflowed(s))  			goto end; +		if (i) +			trace_seq_puts(s, ", "); +  		/* parameter types */  		if (tr && tr->trace_flags & TRACE_ITER_VERBOSE)  			trace_seq_printf(s, "%s ", entry->types[i]);  		/* parameter values */ -		trace_seq_printf(s, "%s: %lx%s", entry->args[i], -				 trace->args[i], -				 i == entry->nb_args - 1 ? "" : ", "); +		if (trace->args[i] < 10) +			trace_seq_printf(s, "%s: %lu", entry->args[i], +					 trace->args[i]); +		else +			trace_seq_printf(s, "%s: 0x%lx", entry->args[i], +					 trace->args[i]);  	}  	trace_seq_putc(s, ')'); @@ -310,8 +316,7 @@ static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id)  	if (syscall_nr < 0 || syscall_nr >= NR_syscalls)  		return; -	/* Here we're inside tp handler's rcu_read_lock_sched (__DO_TRACE) */ -	trace_file = rcu_dereference_sched(tr->enter_syscall_files[syscall_nr]); +	trace_file = READ_ONCE(tr->enter_syscall_files[syscall_nr]);  	if (!trace_file)  		return; @@ -356,8 +361,7 @@ static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret)  	if (syscall_nr < 0 || syscall_nr >= NR_syscalls)  		return; -	/* Here we're inside tp handler's rcu_read_lock_sched (__DO_TRACE()) */ -	trace_file = rcu_dereference_sched(tr->exit_syscall_files[syscall_nr]); +	trace_file = READ_ONCE(tr->exit_syscall_files[syscall_nr]);  	if (!trace_file)  		return; @@ -393,7 +397,7 @@ static int reg_event_syscall_enter(struct trace_event_file *file,  	if (!tr->sys_refcount_enter)  		ret = register_trace_sys_enter(ftrace_syscall_enter, tr);  	if (!ret) { -		rcu_assign_pointer(tr->enter_syscall_files[num], file); +		WRITE_ONCE(tr->enter_syscall_files[num], file);  		tr->sys_refcount_enter++;  	}  	mutex_unlock(&syscall_trace_lock); @@ -411,7 +415,7 @@ static void unreg_event_syscall_enter(struct trace_event_file *file,  		return;  	mutex_lock(&syscall_trace_lock);  	tr->sys_refcount_enter--; -	RCU_INIT_POINTER(tr->enter_syscall_files[num], NULL); +	WRITE_ONCE(tr->enter_syscall_files[num], NULL);  	if (!tr->sys_refcount_enter)  		unregister_trace_sys_enter(ftrace_syscall_enter, tr);  	mutex_unlock(&syscall_trace_lock); @@ -431,7 +435,7 @@ static int reg_event_syscall_exit(struct trace_event_file *file,  	if (!tr->sys_refcount_exit)  		ret = register_trace_sys_exit(ftrace_syscall_exit, tr);  	if (!ret) { -		rcu_assign_pointer(tr->exit_syscall_files[num], file); +		WRITE_ONCE(tr->exit_syscall_files[num], file);  		tr->sys_refcount_exit++;  	}  	mutex_unlock(&syscall_trace_lock); @@ -449,7 +453,7 @@ static void unreg_event_syscall_exit(struct trace_event_file *file,  		return;  	mutex_lock(&syscall_trace_lock);  	tr->sys_refcount_exit--; -	RCU_INIT_POINTER(tr->exit_syscall_files[num], NULL); +	WRITE_ONCE(tr->exit_syscall_files[num], NULL);  	if (!tr->sys_refcount_exit)  		unregister_trace_sys_exit(ftrace_syscall_exit, tr);  	mutex_unlock(&syscall_trace_lock); diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index 8b0bcc0d8f41..430d09c49462 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c @@ -1547,6 +1547,7 @@ static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs,  	struct trace_uprobe *tu;  	struct uprobe_dispatch_data udd;  	struct uprobe_cpu_buffer *ucb = NULL; +	unsigned int flags;  	int ret = 0;  	tu = container_of(con, struct trace_uprobe, consumer); @@ -1561,11 +1562,12 @@ static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs,  	if (WARN_ON_ONCE(!uprobe_cpu_buffer))  		return 0; -	if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE)) +	flags = trace_probe_load_flag(&tu->tp); +	if (flags & TP_FLAG_TRACE)  		ret |= uprobe_trace_func(tu, regs, &ucb);  #ifdef CONFIG_PERF_EVENTS -	if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE)) +	if (flags & TP_FLAG_PROFILE)  		ret |= uprobe_perf_func(tu, regs, &ucb);  #endif  	uprobe_buffer_put(ucb); @@ -1579,6 +1581,7 @@ static int uretprobe_dispatcher(struct uprobe_consumer *con,  	struct trace_uprobe *tu;  	struct uprobe_dispatch_data udd;  	struct uprobe_cpu_buffer *ucb = NULL; +	unsigned int flags;  	tu = container_of(con, struct trace_uprobe, consumer); @@ -1590,11 +1593,12 @@ static int uretprobe_dispatcher(struct uprobe_consumer *con,  	if (WARN_ON_ONCE(!uprobe_cpu_buffer))  		return 0; -	if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE)) +	flags = trace_probe_load_flag(&tu->tp); +	if (flags & TP_FLAG_TRACE)  		uretprobe_trace_func(tu, func, regs, &ucb);  #ifdef CONFIG_PERF_EVENTS -	if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE)) +	if (flags & TP_FLAG_PROFILE)  		uretprobe_perf_func(tu, func, regs, &ucb);  #endif  	uprobe_buffer_put(ucb); diff --git a/kernel/trace/tracing_map.c b/kernel/trace/tracing_map.c index 1921ade45be3..7f8da4dab69d 100644 --- a/kernel/trace/tracing_map.c +++ b/kernel/trace/tracing_map.c @@ -1076,7 +1076,7 @@ int tracing_map_sort_entries(struct tracing_map *map,  	struct tracing_map_sort_entry *sort_entry, **entries;  	int i, n_entries, ret; -	entries = vmalloc(array_size(sizeof(sort_entry), map->max_elts)); +	entries = vmalloc_array(map->max_elts, sizeof(sort_entry));  	if (!entries)  		return -ENOMEM; | 
