From 89f2ee5b3cf2473a1f6ebcb0c031095ba198398b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 24 Nov 2023 16:07:05 +0000 Subject: [PATCH] 6.5-stable patches added patches: powerpc-powernv-fix-fortify-source-warnings-in-opal-prd.c.patch tracing-have-trace_event_file-have-ref-counters.patch --- ...ortify-source-warnings-in-opal-prd.c.patch | 92 +++++++ queue-6.5/series | 2 + ...e-trace_event_file-have-ref-counters.patch | 252 ++++++++++++++++++ 3 files changed, 346 insertions(+) create mode 100644 queue-6.5/powerpc-powernv-fix-fortify-source-warnings-in-opal-prd.c.patch create mode 100644 queue-6.5/tracing-have-trace_event_file-have-ref-counters.patch diff --git a/queue-6.5/powerpc-powernv-fix-fortify-source-warnings-in-opal-prd.c.patch b/queue-6.5/powerpc-powernv-fix-fortify-source-warnings-in-opal-prd.c.patch new file mode 100644 index 00000000000..0675bb1d82b --- /dev/null +++ b/queue-6.5/powerpc-powernv-fix-fortify-source-warnings-in-opal-prd.c.patch @@ -0,0 +1,92 @@ +From feea65a338e52297b68ceb688eaf0ffc50310a83 Mon Sep 17 00:00:00 2001 +From: Michael Ellerman +Date: Tue, 22 Aug 2023 00:28:19 +1000 +Subject: powerpc/powernv: Fix fortify source warnings in opal-prd.c + +From: Michael Ellerman + +commit feea65a338e52297b68ceb688eaf0ffc50310a83 upstream. + +As reported by Mahesh & Aneesh, opal_prd_msg_notifier() triggers a +FORTIFY_SOURCE warning: + + memcpy: detected field-spanning write (size 32) of single field "&item->msg" at arch/powerpc/platforms/powernv/opal-prd.c:355 (size 4) + WARNING: CPU: 9 PID: 660 at arch/powerpc/platforms/powernv/opal-prd.c:355 opal_prd_msg_notifier+0x174/0x188 [opal_prd] + NIP opal_prd_msg_notifier+0x174/0x188 [opal_prd] + LR opal_prd_msg_notifier+0x170/0x188 [opal_prd] + Call Trace: + opal_prd_msg_notifier+0x170/0x188 [opal_prd] (unreliable) + notifier_call_chain+0xc0/0x1b0 + atomic_notifier_call_chain+0x2c/0x40 + opal_message_notify+0xf4/0x2c0 + +This happens because the copy is targeting item->msg, which is only 4 +bytes in size, even though the enclosing item was allocated with extra +space following the msg. + +To fix the warning define struct opal_prd_msg with a union of the header +and a flex array, and have the memcpy target the flex array. + +Reported-by: "Aneesh Kumar K.V" +Reported-by: Mahesh Salgaonkar +Tested-by: Mahesh Salgaonkar +Reviewed-by: Mahesh Salgaonkar +Signed-off-by: Michael Ellerman +Link: https://msgid.link/20230821142820.497107-1-mpe@ellerman.id.au +Signed-off-by: Greg Kroah-Hartman +--- + arch/powerpc/platforms/powernv/opal-prd.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +--- a/arch/powerpc/platforms/powernv/opal-prd.c ++++ b/arch/powerpc/platforms/powernv/opal-prd.c +@@ -24,13 +24,20 @@ + #include + + ++struct opal_prd_msg { ++ union { ++ struct opal_prd_msg_header header; ++ DECLARE_FLEX_ARRAY(u8, data); ++ }; ++}; ++ + /* + * The msg member must be at the end of the struct, as it's followed by the + * message data. + */ + struct opal_prd_msg_queue_item { +- struct list_head list; +- struct opal_prd_msg_header msg; ++ struct list_head list; ++ struct opal_prd_msg msg; + }; + + static struct device_node *prd_node; +@@ -156,7 +163,7 @@ static ssize_t opal_prd_read(struct file + int rc; + + /* we need at least a header's worth of data */ +- if (count < sizeof(item->msg)) ++ if (count < sizeof(item->msg.header)) + return -EINVAL; + + if (*ppos) +@@ -186,7 +193,7 @@ static ssize_t opal_prd_read(struct file + return -EINTR; + } + +- size = be16_to_cpu(item->msg.size); ++ size = be16_to_cpu(item->msg.header.size); + if (size > count) { + err = -EINVAL; + goto err_requeue; +@@ -352,7 +359,7 @@ static int opal_prd_msg_notifier(struct + if (!item) + return -ENOMEM; + +- memcpy(&item->msg, msg->params, msg_size); ++ memcpy(&item->msg.data, msg->params, msg_size); + + spin_lock_irqsave(&opal_prd_msg_queue_lock, flags); + list_add_tail(&item->list, &opal_prd_msg_queue); diff --git a/queue-6.5/series b/queue-6.5/series index dca5066a96d..7e4b78d9cf0 100644 --- a/queue-6.5/series +++ b/queue-6.5/series @@ -489,3 +489,5 @@ drm-amd-display-fix-dsc-not-enabled-on-direct-mst-sink.patch drm-amd-display-fix-a-null-pointer-dereference-in-amdgpu_dm_i2c_xfer.patch drm-amd-display-enable-fast-plane-updates-on-dcn3.2-and-above.patch drm-amd-display-change-the-dmcub-mailbox-memory-location-from-fb-to-inbox.patch +powerpc-powernv-fix-fortify-source-warnings-in-opal-prd.c.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..128dc27ac90 --- /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 | 43 ++++++++++++++++++++++++------------- + kernel/trace/trace_events_filter.c | 3 ++ + 5 files changed, 53 insertions(+), 15 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,38 @@ static void remove_subsystem(struct trac + } + } + +-static void remove_event_file_dir(struct trace_event_file *file) ++void event_file_get(struct trace_event_file *file) + { +- struct dentry *dir = file->dir; +- struct dentry *child; ++ atomic_inc(&file->ref); ++} + +- 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); ++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; ++ } + +- tracefs_remove(dir); ++ 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; ++ ++ 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 +1394,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 +1432,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 +1706,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 +2822,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); -- 2.47.3