From 80724d24b467d53aa6b42ebc2416b51f78054921 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 15 Jul 2025 17:43:37 +0200 Subject: [PATCH] 5.15-stable patches added patches: rseq-fix-segfault-on-registration-when-rseq_cs-is-non-zero.patch --- ...egistration-when-rseq_cs-is-non-zero.patch | 156 ++++++++++++++++++ queue-5.15/series | 1 + 2 files changed, 157 insertions(+) create mode 100644 queue-5.15/rseq-fix-segfault-on-registration-when-rseq_cs-is-non-zero.patch diff --git a/queue-5.15/rseq-fix-segfault-on-registration-when-rseq_cs-is-non-zero.patch b/queue-5.15/rseq-fix-segfault-on-registration-when-rseq_cs-is-non-zero.patch new file mode 100644 index 0000000000..4f652b25f4 --- /dev/null +++ b/queue-5.15/rseq-fix-segfault-on-registration-when-rseq_cs-is-non-zero.patch @@ -0,0 +1,156 @@ +From fd881d0a085fc54354414aed990ccf05f282ba53 Mon Sep 17 00:00:00 2001 +From: Michael Jeanson +Date: Thu, 6 Mar 2025 16:12:21 -0500 +Subject: rseq: Fix segfault on registration when rseq_cs is non-zero + +From: Michael Jeanson + +commit fd881d0a085fc54354414aed990ccf05f282ba53 upstream. + +The rseq_cs field is documented as being set to 0 by user-space prior to +registration, however this is not currently enforced by the kernel. This +can result in a segfault on return to user-space if the value stored in +the rseq_cs field doesn't point to a valid struct rseq_cs. + +The correct solution to this would be to fail the rseq registration when +the rseq_cs field is non-zero. However, some older versions of glibc +will reuse the rseq area of previous threads without clearing the +rseq_cs field and will also terminate the process if the rseq +registration fails in a secondary thread. This wasn't caught in testing +because in this case the leftover rseq_cs does point to a valid struct +rseq_cs. + +What we can do is clear the rseq_cs field on registration when it's +non-zero which will prevent segfaults on registration and won't break +the glibc versions that reuse rseq areas on thread creation. + +Signed-off-by: Michael Jeanson +Signed-off-by: Ingo Molnar +Reviewed-by: Mathieu Desnoyers +Cc: Peter Zijlstra +Cc: Linus Torvalds +Link: https://lore.kernel.org/r/20250306211223.109455-1-mjeanson@efficios.com +Signed-off-by: Greg Kroah-Hartman +--- + kernel/rseq.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 48 insertions(+), 12 deletions(-) + +--- a/kernel/rseq.c ++++ b/kernel/rseq.c +@@ -119,6 +119,29 @@ static int rseq_reset_rseq_cpu_id(struct + return 0; + } + ++/* ++ * Get the user-space pointer value stored in the 'rseq_cs' field. ++ */ ++static int rseq_get_rseq_cs_ptr_val(struct rseq __user *rseq, u64 *rseq_cs) ++{ ++ if (!rseq_cs) ++ return -EFAULT; ++ ++#ifdef CONFIG_64BIT ++ if (get_user(*rseq_cs, &rseq->rseq_cs)) ++ return -EFAULT; ++#else ++ if (copy_from_user(rseq_cs, &rseq->rseq_cs, sizeof(*rseq_cs))) ++ return -EFAULT; ++#endif ++ ++ return 0; ++} ++ ++/* ++ * If the rseq_cs field of 'struct rseq' contains a valid pointer to ++ * user-space, copy 'struct rseq_cs' from user-space and validate its fields. ++ */ + static int rseq_get_rseq_cs(struct task_struct *t, struct rseq_cs *rseq_cs) + { + struct rseq_cs __user *urseq_cs; +@@ -127,17 +150,16 @@ static int rseq_get_rseq_cs(struct task_ + u32 sig; + int ret; + +-#ifdef CONFIG_64BIT +- if (get_user(ptr, &t->rseq->rseq_cs)) +- return -EFAULT; +-#else +- if (copy_from_user(&ptr, &t->rseq->rseq_cs, sizeof(ptr))) +- return -EFAULT; +-#endif ++ ret = rseq_get_rseq_cs_ptr_val(t->rseq, &ptr); ++ if (ret) ++ return ret; ++ ++ /* If the rseq_cs pointer is NULL, return a cleared struct rseq_cs. */ + if (!ptr) { + memset(rseq_cs, 0, sizeof(*rseq_cs)); + return 0; + } ++ /* Check that the pointer value fits in the user-space process space. */ + if (ptr >= TASK_SIZE) + return -EINVAL; + urseq_cs = (struct rseq_cs __user *)(unsigned long)ptr; +@@ -206,7 +228,7 @@ static int rseq_need_restart(struct task + return !!(event_mask & ~flags); + } + +-static int clear_rseq_cs(struct task_struct *t) ++static int clear_rseq_cs(struct rseq __user *rseq) + { + /* + * The rseq_cs field is set to NULL on preemption or signal +@@ -217,9 +239,9 @@ static int clear_rseq_cs(struct task_str + * Set rseq_cs to NULL. + */ + #ifdef CONFIG_64BIT +- return put_user(0UL, &t->rseq->rseq_cs); ++ return put_user(0UL, &rseq->rseq_cs); + #else +- if (clear_user(&t->rseq->rseq_cs, sizeof(t->rseq->rseq_cs))) ++ if (clear_user(&rseq->rseq_cs, sizeof(rseq->rseq_cs))) + return -EFAULT; + return 0; + #endif +@@ -251,11 +273,11 @@ static int rseq_ip_fixup(struct pt_regs + * Clear the rseq_cs pointer and return. + */ + if (!in_rseq_cs(ip, &rseq_cs)) +- return clear_rseq_cs(t); ++ return clear_rseq_cs(t->rseq); + ret = rseq_need_restart(t, rseq_cs.flags); + if (ret <= 0) + return ret; +- ret = clear_rseq_cs(t); ++ ret = clear_rseq_cs(t->rseq); + if (ret) + return ret; + trace_rseq_ip_fixup(ip, rseq_cs.start_ip, rseq_cs.post_commit_offset, +@@ -329,6 +351,7 @@ SYSCALL_DEFINE4(rseq, struct rseq __user + int, flags, u32, sig) + { + int ret; ++ u64 rseq_cs; + + if (flags & RSEQ_FLAG_UNREGISTER) { + if (flags & ~RSEQ_FLAG_UNREGISTER) +@@ -374,6 +397,19 @@ SYSCALL_DEFINE4(rseq, struct rseq __user + return -EINVAL; + if (!access_ok(rseq, rseq_len)) + return -EFAULT; ++ ++ /* ++ * If the rseq_cs pointer is non-NULL on registration, clear it to ++ * avoid a potential segfault on return to user-space. The proper thing ++ * to do would have been to fail the registration but this would break ++ * older libcs that reuse the rseq area for new threads without ++ * clearing the fields. ++ */ ++ if (rseq_get_rseq_cs_ptr_val(rseq, &rseq_cs)) ++ return -EFAULT; ++ if (rseq_cs && clear_rseq_cs(rseq)) ++ return -EFAULT; ++ + current->rseq = rseq; + current->rseq_sig = sig; + /* diff --git a/queue-5.15/series b/queue-5.15/series index 98524b9e90..b57c48a75c 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -75,3 +75,4 @@ input-atkbd-do-not-skip-atkbd_deactivate-when-skipping-atkbd_cmd_getid.patch vhost-scsi-protect-vq-log_used-with-vq-mutex.patch x86-mm-disable-hugetlb-page-table-sharing-on-32-bit.patch x86-fix-x86_feature_verw_clear-definition.patch +rseq-fix-segfault-on-registration-when-rseq_cs-is-non-zero.patch -- 2.47.2