lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20250528102655.1455423-1-jremus@linux.ibm.com>
Date: Wed, 28 May 2025 12:26:55 +0200
From: Jens Remus <jremus@...ux.ibm.com>
To: rostedt@...dmis.org
Cc: aahringo@...hat.com, acme@...nel.org, adrian.hunter@...el.com,
        akpm@...ux-foundation.org, alexander.shishkin@...ux.intel.com,
        andrii.nakryiko@...il.com, beaub@...ux.microsoft.com,
        blakejones@...gle.com, broonie@...nel.org, fweimer@...hat.com,
        indu.bhagat@...cle.com, irogers@...gle.com, jemarch@....org,
        jolsa@...nel.org, jordalgo@...a.com, jpoimboe@...nel.org,
        jremus@...ux.ibm.com, linux-kernel@...r.kernel.org,
        linux-perf-users@...r.kernel.org, linux-toolchains@...r.kernel.org,
        linux-trace-kernel@...r.kernel.org, luto@...nel.org,
        mark.rutland@....com, mathieu.desnoyers@...icios.com,
        mhiramat@...nel.org, mingo@...nel.org, namhyung@...nel.org,
        peterz@...radead.org, sam@...too.org, wnliu@...gle.com, x86@...nel.org,
        hca@...ux.ibm.com
Subject: [PATCH] fixup! unwind_user/sframe: Add support for reading .sframe contents

---

Notes (jremus):
    Link: https://lore.kernel.org/all/b35ca3a3-8de5-4d32-8d30-d4e562f6b0de@linux.ibm.com/
    
    The struct sframe_fre field ip_off must be u32, as the SFrame FRE start
    address (sfre_start_address) is unsigned 8-bit, 16-bit, or 32-bit:
    https://sourceware.org/binutils/docs/sframe-spec.html#SFrame-Frame-Row-Entries
    
    When searching for a FRE of a FDE for an IP, the IP offset from function
    start address (ip_off = ip - (sec->sframe_start + fde->start_addr)) is
    always positive, as the search for a FDE for the same IP returned a
    FDE with:  sec->sframe_start + fde->start_addr <= ip
    This enables comparison against the unsigned FDE ip_off.
    
    This fixup includes a proposed fix from Josh (with minor modification
    due to duplicate macro names) to correctly perform sign extension when
    reading (un-)signed SFrame FDE/FRE fields:
    https://lore.kernel.org/all/20250207210614.nks6bxad4jhdulwg@jpoimboe/

 kernel/unwind/sframe.c | 38 +++++++++++++++++++++++++++-----------
 1 file changed, 27 insertions(+), 11 deletions(-)

diff --git a/kernel/unwind/sframe.c b/kernel/unwind/sframe.c
index 3f7cc9bc27eb..8804ac59edfa 100644
--- a/kernel/unwind/sframe.c
+++ b/kernel/unwind/sframe.c
@@ -19,7 +19,7 @@
 
 struct sframe_fre {
 	unsigned int	size;
-	s32		ip_off;
+	u32		ip_off;
 	s32		cfa_off;
 	s32		ra_off;
 	s32		fp_off;
@@ -129,33 +129,48 @@ static __always_inline int __find_fde(struct sframe_section *sec,
 	return -EFAULT;
 }
 
-#define __UNSAFE_GET_USER_INC(to, from, type, label)			\
+#define ____UNSAFE_GET_USER_INC(to, from, type, label)			\
 ({									\
 	type __to;							\
 	unsafe_get_user(__to, (type __user *)from, label);		\
 	from += sizeof(__to);						\
-	to = (typeof(to))__to;							\
+	to = __to;							\
 })
 
-#define UNSAFE_GET_USER_INC(to, from, size, label)			\
+#define __UNSAFE_GET_USER_INC(to, from, size, label, u_or_s)		\
 ({									\
 	switch (size) {							\
 	case 1:								\
-		__UNSAFE_GET_USER_INC(to, from, u8, label);		\
+		____UNSAFE_GET_USER_INC(to, from, u_or_s##8, label);	\
 		break;							\
 	case 2:								\
-		__UNSAFE_GET_USER_INC(to, from, u16, label);		\
+		____UNSAFE_GET_USER_INC(to, from, u_or_s##16, label);	\
 		break;							\
 	case 4:								\
-		__UNSAFE_GET_USER_INC(to, from, u32, label);		\
+		____UNSAFE_GET_USER_INC(to, from, u_or_s##32, label);	\
 		break;							\
 	default:							\
-		dbg_sec_uaccess("%d: bad UNSAFE_GET_USER_INC size %u\n",\
+		dbg_sec_uaccess("%d: bad unsafe_get_user() size %u\n",	\
 				__LINE__, size);			\
 		return -EFAULT;						\
 	}								\
 })
 
+#define UNSAFE_GET_USER_UNSIGNED_INC(to, from, size, label)		\
+	__UNSAFE_GET_USER_INC(to, from, size, label, u)
+
+#define UNSAFE_GET_USER_SIGNED_INC(to, from, size, label)		\
+	__UNSAFE_GET_USER_INC(to, from, size, label, s)
+
+#define UNSAFE_GET_USER_INC(to, from, size, label)				\
+	_Generic(to,								\
+		 u8:	UNSAFE_GET_USER_UNSIGNED_INC(to, from, size, label),	\
+		 u16:	UNSAFE_GET_USER_UNSIGNED_INC(to, from, size, label),	\
+		 u32:	UNSAFE_GET_USER_UNSIGNED_INC(to, from, size, label),	\
+		 s8:	UNSAFE_GET_USER_SIGNED_INC(to, from, size, label),	\
+		 s16:	UNSAFE_GET_USER_SIGNED_INC(to, from, size, label),	\
+		 s32:	UNSAFE_GET_USER_SIGNED_INC(to, from, size, label))
+
 static __always_inline int __read_fre(struct sframe_section *sec,
 				      struct sframe_fde *fde,
 				      unsigned long fre_addr,
@@ -164,7 +179,8 @@ static __always_inline int __read_fre(struct sframe_section *sec,
 	unsigned char fde_type = SFRAME_FUNC_FDE_TYPE(fde->info);
 	unsigned char fre_type = SFRAME_FUNC_FRE_TYPE(fde->info);
 	unsigned char offset_count, offset_size;
-	s32 ip_off, cfa_off, ra_off, fp_off;
+	u32 ip_off;
+	s32 cfa_off, ra_off, fp_off;
 	unsigned long cur = fre_addr;
 	unsigned char addr_size;
 	u8 info;
@@ -248,9 +264,9 @@ static __always_inline int __find_fre(struct sframe_section *sec,
 	unsigned long fre_addr;
 	bool which = false;
 	unsigned int i;
-	s32 ip_off;
+	u32 ip_off;
 
-	ip_off = (s32)(ip - sec->sframe_start) - fde->start_addr;
+	ip_off = ip - (sec->sframe_start + fde->start_addr);
 
 	if (fde_type == SFRAME_FDE_TYPE_PCMASK)
 		ip_off %= fde->rep_size;
-- 
2.45.2


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ