From: Greg Kroah-Hartman Date: Wed, 15 Nov 2023 11:52:43 +0000 (-0500) Subject: 6.5-stable patches X-Git-Tag: v4.14.330~37 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ea313d828be362964308c61f6c11f2736d33d2f7;p=thirdparty%2Fkernel%2Fstable-queue.git 6.5-stable patches added patches: selftests-mptcp-fix-wait_rm_addr-sf-parameters.patch tracing-have-trace_event_file-have-ref-counters.patch --- diff --git a/queue-6.5/selftests-mptcp-fix-wait_rm_addr-sf-parameters.patch b/queue-6.5/selftests-mptcp-fix-wait_rm_addr-sf-parameters.patch new file mode 100644 index 00000000000..ea1af104263 --- /dev/null +++ b/queue-6.5/selftests-mptcp-fix-wait_rm_addr-sf-parameters.patch @@ -0,0 +1,79 @@ +From 9168ea02b898d3dde98b51e4bd3fb082bd438dab Mon Sep 17 00:00:00 2001 +From: Geliang Tang +Date: Wed, 25 Oct 2023 16:37:03 -0700 +Subject: selftests: mptcp: fix wait_rm_addr/sf parameters + +From: Geliang Tang + +commit 9168ea02b898d3dde98b51e4bd3fb082bd438dab upstream. + +The second input parameter of 'wait_rm_addr/sf $1 1' is misused. If it's +1, wait_rm_addr/sf will never break, and will loop ten times, then +'wait_rm_addr/sf' equals to 'sleep 1'. This delay time is too long, +which can sometimes make the tests fail. + +A better way to use wait_rm_addr/sf is to use rm_addr/sf_count to obtain +the current value, and then pass into wait_rm_addr/sf. + +Fixes: 4369c198e599 ("selftests: mptcp: test userspace pm out of transfer") +Cc: stable@vger.kernel.org +Suggested-by: Matthieu Baerts +Reviewed-by: Matthieu Baerts +Signed-off-by: Geliang Tang +Signed-off-by: Mat Martineau +Link: https://lore.kernel.org/r/20231025-send-net-next-20231025-v1-2-db8f25f798eb@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + tools/testing/selftests/net/mptcp/mptcp_join.sh | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +--- a/tools/testing/selftests/net/mptcp/mptcp_join.sh ++++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh +@@ -3259,6 +3259,7 @@ userspace_pm_rm_sf_addr_ns1() + local addr=$1 + local id=$2 + local tk sp da dp ++ local cnt_addr cnt_sf + + tk=$(grep "type:1," "$evts_ns1" | + sed -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q') +@@ -3268,11 +3269,13 @@ userspace_pm_rm_sf_addr_ns1() + sed -n 's/.*\(daddr6:\)\([0-9a-f:.]*\).*$/\2/p;q') + dp=$(grep "type:10" "$evts_ns1" | + sed -n 's/.*\(dport:\)\([[:digit:]]*\).*$/\2/p;q') ++ cnt_addr=$(rm_addr_count ${ns1}) ++ cnt_sf=$(rm_sf_count ${ns1}) + ip netns exec $ns1 ./pm_nl_ctl rem token $tk id $id + ip netns exec $ns1 ./pm_nl_ctl dsf lip "::ffff:$addr" \ + lport $sp rip $da rport $dp token $tk +- wait_rm_addr $ns1 1 +- wait_rm_sf $ns1 1 ++ wait_rm_addr $ns1 "${cnt_addr}" ++ wait_rm_sf $ns1 "${cnt_sf}" + } + + userspace_pm_add_sf() +@@ -3294,17 +3297,20 @@ userspace_pm_rm_sf_addr_ns2() + local addr=$1 + local id=$2 + local tk da dp sp ++ local cnt_addr cnt_sf + + tk=$(sed -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q' "$evts_ns2") + da=$(sed -n 's/.*\(daddr4:\)\([0-9.]*\).*$/\2/p;q' "$evts_ns2") + dp=$(sed -n 's/.*\(dport:\)\([[:digit:]]*\).*$/\2/p;q' "$evts_ns2") + sp=$(grep "type:10" "$evts_ns2" | + sed -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q') ++ cnt_addr=$(rm_addr_count ${ns2}) ++ cnt_sf=$(rm_sf_count ${ns2}) + ip netns exec $ns2 ./pm_nl_ctl rem token $tk id $id + ip netns exec $ns2 ./pm_nl_ctl dsf lip $addr lport $sp \ + rip $da rport $dp token $tk +- wait_rm_addr $ns2 1 +- wait_rm_sf $ns2 1 ++ wait_rm_addr $ns2 "${cnt_addr}" ++ wait_rm_sf $ns2 "${cnt_sf}" + } + + userspace_tests() diff --git a/queue-6.5/series b/queue-6.5/series index f019c71fdc0..ee828b7b20f 100644 --- a/queue-6.5/series +++ b/queue-6.5/series @@ -541,3 +541,5 @@ alsa-hda-realtek-add-support-dual-speaker-for-dell.patch fbdev-fsl-diu-fb-mark-wr_reg_wa-static.patch tracing-kprobes-fix-the-order-of-argument-descriptio.patch revert-drm-ast-report-connection-status-on-display-p.patch +selftests-mptcp-fix-wait_rm_addr-sf-parameters.patch +tracing-have-trace_event_file-have-ref-counters.patch diff --git a/queue-6.5/tracing-have-trace_event_file-have-ref-counters.patch b/queue-6.5/tracing-have-trace_event_file-have-ref-counters.patch new file mode 100644 index 00000000000..4b7448aadee --- /dev/null +++ b/queue-6.5/tracing-have-trace_event_file-have-ref-counters.patch @@ -0,0 +1,252 @@ +From bb32500fb9b78215e4ef6ee8b4345c5f5d7eafb4 Mon Sep 17 00:00:00 2001 +From: "Steven Rostedt (Google)" +Date: Tue, 31 Oct 2023 12:24:53 -0400 +Subject: tracing: Have trace_event_file have ref counters + +From: Steven Rostedt (Google) + +commit bb32500fb9b78215e4ef6ee8b4345c5f5d7eafb4 upstream. + +The following can crash the kernel: + + # cd /sys/kernel/tracing + # echo 'p:sched schedule' > kprobe_events + # exec 5>>events/kprobes/sched/enable + # > kprobe_events + # exec 5>&- + +The above commands: + + 1. Change directory to the tracefs directory + 2. Create a kprobe event (doesn't matter what one) + 3. Open bash file descriptor 5 on the enable file of the kprobe event + 4. Delete the kprobe event (removes the files too) + 5. Close the bash file descriptor 5 + +The above causes a crash! + + BUG: kernel NULL pointer dereference, address: 0000000000000028 + #PF: supervisor read access in kernel mode + #PF: error_code(0x0000) - not-present page + PGD 0 P4D 0 + Oops: 0000 [#1] PREEMPT SMP PTI + CPU: 6 PID: 877 Comm: bash Not tainted 6.5.0-rc4-test-00008-g2c6b6b1029d4-dirty #186 + Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014 + RIP: 0010:tracing_release_file_tr+0xc/0x50 + +What happens here is that the kprobe event creates a trace_event_file +"file" descriptor that represents the file in tracefs to the event. It +maintains state of the event (is it enabled for the given instance?). +Opening the "enable" file gets a reference to the event "file" descriptor +via the open file descriptor. When the kprobe event is deleted, the file is +also deleted from the tracefs system which also frees the event "file" +descriptor. + +But as the tracefs file is still opened by user space, it will not be +totally removed until the final dput() is called on it. But this is not +true with the event "file" descriptor that is already freed. If the user +does a write to or simply closes the file descriptor it will reference the +event "file" descriptor that was just freed, causing a use-after-free bug. + +To solve this, add a ref count to the event "file" descriptor as well as a +new flag called "FREED". The "file" will not be freed until the last +reference is released. But the FREE flag will be set when the event is +removed to prevent any more modifications to that event from happening, +even if there's still a reference to the event "file" descriptor. + +Link: https://lore.kernel.org/linux-trace-kernel/20231031000031.1e705592@gandalf.local.home/ +Link: https://lore.kernel.org/linux-trace-kernel/20231031122453.7a48b923@gandalf.local.home + +Cc: stable@vger.kernel.org +Cc: Mark Rutland +Fixes: f5ca233e2e66d ("tracing: Increase trace array ref count on enable and filter files") +Reported-by: Beau Belgrave +Tested-by: Beau Belgrave +Reviewed-by: Masami Hiramatsu (Google) +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/trace_events.h | 4 +++ + kernel/trace/trace.c | 15 +++++++++++++ + kernel/trace/trace.h | 3 ++ + kernel/trace/trace_events.c | 42 ++++++++++++++++++++++++------------- + kernel/trace/trace_events_filter.c | 3 ++ + 5 files changed, 53 insertions(+), 14 deletions(-) + +--- a/include/linux/trace_events.h ++++ b/include/linux/trace_events.h +@@ -492,6 +492,7 @@ enum { + EVENT_FILE_FL_TRIGGER_COND_BIT, + EVENT_FILE_FL_PID_FILTER_BIT, + EVENT_FILE_FL_WAS_ENABLED_BIT, ++ EVENT_FILE_FL_FREED_BIT, + }; + + extern struct trace_event_file *trace_get_event_file(const char *instance, +@@ -630,6 +631,7 @@ extern int __kprobe_event_add_fields(str + * TRIGGER_COND - When set, one or more triggers has an associated filter + * PID_FILTER - When set, the event is filtered based on pid + * WAS_ENABLED - Set when enabled to know to clear trace on module removal ++ * FREED - File descriptor is freed, all fields should be considered invalid + */ + enum { + EVENT_FILE_FL_ENABLED = (1 << EVENT_FILE_FL_ENABLED_BIT), +@@ -643,6 +645,7 @@ enum { + EVENT_FILE_FL_TRIGGER_COND = (1 << EVENT_FILE_FL_TRIGGER_COND_BIT), + EVENT_FILE_FL_PID_FILTER = (1 << EVENT_FILE_FL_PID_FILTER_BIT), + EVENT_FILE_FL_WAS_ENABLED = (1 << EVENT_FILE_FL_WAS_ENABLED_BIT), ++ EVENT_FILE_FL_FREED = (1 << EVENT_FILE_FL_FREED_BIT), + }; + + struct trace_event_file { +@@ -671,6 +674,7 @@ struct trace_event_file { + * caching and such. Which is mostly OK ;-) + */ + unsigned long flags; ++ atomic_t ref; /* ref count for opened files */ + atomic_t sm_ref; /* soft-mode reference counter */ + atomic_t tm_ref; /* trigger-mode reference counter */ + }; +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@ -5000,6 +5000,20 @@ int tracing_open_file_tr(struct inode *i + if (ret) + return ret; + ++ mutex_lock(&event_mutex); ++ ++ /* Fail if the file is marked for removal */ ++ if (file->flags & EVENT_FILE_FL_FREED) { ++ trace_array_put(file->tr); ++ ret = -ENODEV; ++ } else { ++ event_file_get(file); ++ } ++ ++ mutex_unlock(&event_mutex); ++ if (ret) ++ return ret; ++ + filp->private_data = inode->i_private; + + return 0; +@@ -5010,6 +5024,7 @@ int tracing_release_file_tr(struct inode + struct trace_event_file *file = inode->i_private; + + trace_array_put(file->tr); ++ event_file_put(file); + + return 0; + } +--- a/kernel/trace/trace.h ++++ b/kernel/trace/trace.h +@@ -1656,6 +1656,9 @@ extern void event_trigger_unregister(str + char *glob, + struct event_trigger_data *trigger_data); + ++extern void event_file_get(struct trace_event_file *file); ++extern void event_file_put(struct trace_event_file *file); ++ + /** + * struct event_trigger_ops - callbacks for trace event triggers + * +--- a/kernel/trace/trace_events.c ++++ b/kernel/trace/trace_events.c +@@ -990,26 +990,39 @@ static void remove_subsystem(struct trac + } + } + ++void event_file_get(struct trace_event_file *file) ++{ ++ atomic_inc(&file->ref); ++} ++ ++void event_file_put(struct trace_event_file *file) ++{ ++ if (WARN_ON_ONCE(!atomic_read(&file->ref))) { ++ if (file->flags & EVENT_FILE_FL_FREED) ++ kmem_cache_free(file_cachep, file); ++ return; ++ } ++ ++ if (atomic_dec_and_test(&file->ref)) { ++ /* Count should only go to zero when it is freed */ ++ if (WARN_ON_ONCE(!(file->flags & EVENT_FILE_FL_FREED))) ++ return; ++ kmem_cache_free(file_cachep, file); ++ } ++} ++ + static void remove_event_file_dir(struct trace_event_file *file) + { + struct dentry *dir = file->dir; + struct dentry *child; + +- if (dir) { +- spin_lock(&dir->d_lock); /* probably unneeded */ +- list_for_each_entry(child, &dir->d_subdirs, d_child) { +- if (d_really_is_positive(child)) /* probably unneeded */ +- d_inode(child)->i_private = NULL; +- } +- spin_unlock(&dir->d_lock); +- +- tracefs_remove(dir); +- } ++ tracefs_remove(dir); + + list_del(&file->list); + remove_subsystem(file->system); + free_event_filter(file->filter); +- kmem_cache_free(file_cachep, file); ++ file->flags |= EVENT_FILE_FL_FREED; ++ event_file_put(file); + } + + /* +@@ -1382,7 +1395,7 @@ event_enable_read(struct file *filp, cha + flags = file->flags; + mutex_unlock(&event_mutex); + +- if (!file) ++ if (!file || flags & EVENT_FILE_FL_FREED) + return -ENODEV; + + if (flags & EVENT_FILE_FL_ENABLED && +@@ -1420,7 +1433,7 @@ event_enable_write(struct file *filp, co + ret = -ENODEV; + mutex_lock(&event_mutex); + file = event_file_data(filp); +- if (likely(file)) ++ if (likely(file && !(file->flags & EVENT_FILE_FL_FREED))) + ret = ftrace_event_enable_disable(file, val); + mutex_unlock(&event_mutex); + break; +@@ -1694,7 +1707,7 @@ event_filter_read(struct file *filp, cha + + mutex_lock(&event_mutex); + file = event_file_data(filp); +- if (file) ++ if (file && !(file->flags & EVENT_FILE_FL_FREED)) + print_event_filter(file, s); + mutex_unlock(&event_mutex); + +@@ -2810,6 +2823,7 @@ trace_create_new_event(struct trace_even + atomic_set(&file->tm_ref, 0); + INIT_LIST_HEAD(&file->triggers); + list_add(&file->list, &tr->events); ++ event_file_get(file); + + return file; + } +--- a/kernel/trace/trace_events_filter.c ++++ b/kernel/trace/trace_events_filter.c +@@ -2088,6 +2088,9 @@ int apply_event_filter(struct trace_even + struct event_filter *filter = NULL; + int err; + ++ if (file->flags & EVENT_FILE_FL_FREED) ++ return -ENODEV; ++ + if (!strcmp(strstrip(filter_string), "0")) { + filter_disable(file); + filter = event_filter(file);