diff mbox series

ldt.h: Add workaround for x86_64

Message ID 20250507-fixes-modify_ldt-v1-1-70a2694cfddc@suse.com
State Needs Review / ACK
Headers show
Series ldt.h: Add workaround for x86_64 | expand

Checks

Context Check Description
ltpci/debian_stable_s390x-linux-gnu-gcc_s390x success success
ltpci/debian_stable_aarch64-linux-gnu-gcc_arm64 success success
ltpci/debian_stable_powerpc64le-linux-gnu-gcc_ppc64el success success
ltpci/debian_stable_gcc success success
ltpci/ubuntu_bionic_gcc success success
ltpci/debian_stable_gcc success success
ltpci/quay-io-centos-centos_stream9_gcc success success
ltpci/ubuntu_jammy_gcc success success
ltpci/opensuse-leap_latest_gcc success success
ltpci/debian_testing_clang success success
ltpci/debian_testing_gcc success success
ltpci/debian_oldstable_clang success success
ltpci/opensuse-archive_42-2_gcc success success
ltpci/alpine_latest_gcc success success
ltpci/fedora_latest_clang success success
ltpci/debian_oldstable_gcc success success

Commit Message

Ricardo B. Marlière May 7, 2025, 11:37 p.m. UTC
From: Ricardo B. Marlière <rbm@suse.com>

The commit be0aaca2f742 ("syscalls/modify_ldt: Add lapi/ldt.h") left behind
an important factor of modify_ldt(): the kernel intentionally casts the
return value to unsigned int. This was handled in
testcases/cve/cve-2015-3290.c but was removed. Add it back to the relevant
file.

Reported-by: Martin Doucha <mdoucha@suse.cz>
Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
---
 include/lapi/ldt.h            | 22 +++++++++++++++++++++-
 testcases/cve/cve-2015-3290.c |  6 +++++-
 2 files changed, 26 insertions(+), 2 deletions(-)


---
base-commit: b070a5692e035ec12c3d3c7a7e9e97c270fd4d7d
change-id: 20250507-fixes-modify_ldt-ebcfdd2a7d30

Best regards,

Comments

Martin Doucha May 12, 2025, 8:53 a.m. UTC | #1
Hi,
one issue below.

On 08. 05. 25 1:37, Ricardo B. Marlière wrote:
> From: Ricardo B. Marlière <rbm@suse.com>
> 
> The commit be0aaca2f742 ("syscalls/modify_ldt: Add lapi/ldt.h") left behind
> an important factor of modify_ldt(): the kernel intentionally casts the
> return value to unsigned int. This was handled in
> testcases/cve/cve-2015-3290.c but was removed. Add it back to the relevant
> file.
> 
> Reported-by: Martin Doucha <mdoucha@suse.cz>
> Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
> ---
>   include/lapi/ldt.h            | 22 +++++++++++++++++++++-
>   testcases/cve/cve-2015-3290.c |  6 +++++-
>   2 files changed, 26 insertions(+), 2 deletions(-)
> 
> diff --git a/include/lapi/ldt.h b/include/lapi/ldt.h
> index 6b5a2d59cb41bfc24eb5ac26c3d47d49fb8ff78f..173321dd9ac34ba87eff0eee960635f30d878991 100644
> --- a/include/lapi/ldt.h
> +++ b/include/lapi/ldt.h
> @@ -31,7 +31,27 @@ struct user_desc {
>   static inline int modify_ldt(int func, const struct user_desc *ptr,
>   			     unsigned long bytecount)
>   {
> -	return tst_syscall(__NR_modify_ldt, func, ptr, bytecount);
> +	long rval;
> +
> +	errno = 0;
> +	rval = tst_syscall(__NR_modify_ldt, func, ptr, bytecount);
> +
> +#ifdef __x86_64__
> +	/*
> +	 * The kernel intentionally casts modify_ldt() return value
> +	 * to unsigned int to prevent sign extension to 64 bits. This may
> +	 * result in syscall() returning the value as is instead of setting
> +	 * errno and returning -1.
> +	 */
> +	if (rval > 0 && (int)rval < 0) {
> +		tst_res(TINFO,
> +			"WARNING: Libc mishandled modify_ldt() return value");
> +		errno = -(int)errno;
> +		rval = -1;
> +	}
> +#endif /* __x86_64__ */
> +
> +	return rval;
>   }
>   
>   static inline int safe_modify_ldt(const char *file, const int lineno, int func,
> diff --git a/testcases/cve/cve-2015-3290.c b/testcases/cve/cve-2015-3290.c
> index 8ec1d53bbb5a9f3e7761d39855d34f593e118a28..6aa064bab30a039d268b2e9f17258564eda8067c 100644
> --- a/testcases/cve/cve-2015-3290.c
> +++ b/testcases/cve/cve-2015-3290.c
> @@ -197,7 +197,11 @@ static void set_ldt(void)
>   		.useable	 = 0
>   	};
>   
> -	SAFE_MODIFY_LDT(1, &data_desc, sizeof(data_desc));
> +	TEST(modify_ldt(1, &data_desc, sizeof(data_desc)));
> +	if (TST_RET == -1 && TST_ERR == EINVAL) {
> +		tst_brk(TCONF | TTERRNO,
> +			"modify_ldt: 16-bit data segments are probably disabled");
> +	}

This part is correct, but any other non-zero return value is an error 
that should trigger TBROK. See the old test code before refactoring.

>   }
>   
>   static void try_corrupt_stack(unsigned short *orig_ss)
> 
> ---
> base-commit: b070a5692e035ec12c3d3c7a7e9e97c270fd4d7d
> change-id: 20250507-fixes-modify_ldt-ebcfdd2a7d30
> 
> Best regards,
diff mbox series

Patch

diff --git a/include/lapi/ldt.h b/include/lapi/ldt.h
index 6b5a2d59cb41bfc24eb5ac26c3d47d49fb8ff78f..173321dd9ac34ba87eff0eee960635f30d878991 100644
--- a/include/lapi/ldt.h
+++ b/include/lapi/ldt.h
@@ -31,7 +31,27 @@  struct user_desc {
 static inline int modify_ldt(int func, const struct user_desc *ptr,
 			     unsigned long bytecount)
 {
-	return tst_syscall(__NR_modify_ldt, func, ptr, bytecount);
+	long rval;
+
+	errno = 0;
+	rval = tst_syscall(__NR_modify_ldt, func, ptr, bytecount);
+
+#ifdef __x86_64__
+	/*
+	 * The kernel intentionally casts modify_ldt() return value
+	 * to unsigned int to prevent sign extension to 64 bits. This may
+	 * result in syscall() returning the value as is instead of setting
+	 * errno and returning -1.
+	 */
+	if (rval > 0 && (int)rval < 0) {
+		tst_res(TINFO,
+			"WARNING: Libc mishandled modify_ldt() return value");
+		errno = -(int)errno;
+		rval = -1;
+	}
+#endif /* __x86_64__ */
+
+	return rval;
 }
 
 static inline int safe_modify_ldt(const char *file, const int lineno, int func,
diff --git a/testcases/cve/cve-2015-3290.c b/testcases/cve/cve-2015-3290.c
index 8ec1d53bbb5a9f3e7761d39855d34f593e118a28..6aa064bab30a039d268b2e9f17258564eda8067c 100644
--- a/testcases/cve/cve-2015-3290.c
+++ b/testcases/cve/cve-2015-3290.c
@@ -197,7 +197,11 @@  static void set_ldt(void)
 		.useable	 = 0
 	};
 
-	SAFE_MODIFY_LDT(1, &data_desc, sizeof(data_desc));
+	TEST(modify_ldt(1, &data_desc, sizeof(data_desc)));
+	if (TST_RET == -1 && TST_ERR == EINVAL) {
+		tst_brk(TCONF | TTERRNO,
+			"modify_ldt: 16-bit data segments are probably disabled");
+	}
 }
 
 static void try_corrupt_stack(unsigned short *orig_ss)