[LTP] [PATCH v9 1/3] syscalls/modify_ldt: Add lapi/ldt.h

Martin Doucha mdoucha@suse.cz
Wed May 7 13:08:28 CEST 2025


Hi,
the error handling in safe_modify_ldt() is incorrect on x86_64. The 
return value is intentionally cast to unsigned int in kernel which means 
that glibc will interpret error codes as large positive values and 
return them as is. See the workaround that this patch removed from 
cve-2015-3290.c below.

On 29. 04. 25 12:44, Ricardo B. Marlière via ltp wrote:
> From: Ricardo B. Marlière <rbm@suse.com>
> 
> Add a wrapper to modify_ldt and a fallback definition to struct user_desc,
> which are needed in a few tests and should be reused.
> 
> Reviewed-by: Cyril Hrubis <chrubis@suse.cz>
> Reviewed-by: Andrea Cervesato <andrea.cervesato@suse.com>
> Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
> ---
>   include/lapi/ldt.h                      | 59 +++++++++++++++++++++++++++++++++
>   testcases/cve/cve-2015-3290.c           | 26 ++-------------
>   testcases/cve/cve-2017-17053.c          |  6 ++--
>   testcases/kernel/syscalls/fork/fork05.c |  5 ++-
>   4 files changed, 65 insertions(+), 31 deletions(-)
> 
> diff --git a/include/lapi/ldt.h b/include/lapi/ldt.h
> new file mode 100644
> index 0000000000000000000000000000000000000000..6b5a2d59cb41bfc24eb5ac26c3d47d49fb8ff78f
> --- /dev/null
> +++ b/include/lapi/ldt.h
> @@ -0,0 +1,59 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright (c) 2025 SUSE LLC Ricardo B. Marlière <rbm@suse.com>
> + */
> +
> +#ifndef LAPI_LDT_H__
> +#define LAPI_LDT_H__
> +
> +#include "config.h"
> +#include "lapi/syscalls.h"
> +
> +#ifdef HAVE_ASM_LDT_H
> +#include <asm/ldt.h>
> +#else
> +struct user_desc {
> +	unsigned int entry_number;
> +	unsigned int base_addr;
> +	unsigned int limit;
> +	unsigned int seg_32bit : 1;
> +	unsigned int contents : 2;
> +	unsigned int read_exec_only : 1;
> +	unsigned int limit_in_pages : 1;
> +	unsigned int seg_not_present : 1;
> +	unsigned int useable : 1;
> +#ifdef __x86_64__
> +	unsigned int lm : 1;
> +#endif /* __x86_64__ */
> +};
> +#endif /* HAVE_ASM_LDT_H */
> +
> +static inline int modify_ldt(int func, const struct user_desc *ptr,
> +			     unsigned long bytecount)
> +{
> +	return tst_syscall(__NR_modify_ldt, func, ptr, bytecount);
> +}
> +
> +static inline int safe_modify_ldt(const char *file, const int lineno, int func,
> +				  const struct user_desc *ptr,
> +				  unsigned long bytecount)
> +{
> +	int rval;
> +
> +	rval = modify_ldt(func, ptr, bytecount);
> +	if (rval == -1) {
> +		tst_brk_(file, lineno, TBROK | TERRNO,
> +			 "modify_ldt(%d, %p, %lu)", func, ptr, bytecount);
> +	} else if (rval) {
> +		tst_brk_(file, lineno, TBROK | TERRNO,
> +			 "modify_ltd(%d, %p, %lu) invalid retval %i", func, ptr,
> +			 bytecount, rval);
> +	}
> +
> +	return rval;
> +}
> +
> +#define SAFE_MODIFY_LDT(func, ptr, bytecount) \
> +	safe_modify_ldt(__FILE__, __LINE__, (func), (ptr), (bytecount))
> +
> +#endif /* LAPI_LDT_H__ */
> diff --git a/testcases/cve/cve-2015-3290.c b/testcases/cve/cve-2015-3290.c
> index 63e5d92c91b830cd8066a6a6c329461b72731f32..8ec1d53bbb5a9f3e7761d39855d34f593e118a28 100644
> --- a/testcases/cve/cve-2015-3290.c
> +++ b/testcases/cve/cve-2015-3290.c
> @@ -123,16 +123,14 @@ perhaps unsurprisingly.)
>   #include <stdlib.h>
>   #include <stdio.h>
>   #include <inttypes.h>
> -#include <asm/ldt.h>
>   #include <unistd.h>
> -#include <sys/syscall.h>
>   #include <setjmp.h>
>   #include <signal.h>
>   #include <string.h>
>   #include <sys/wait.h>
>   #include <linux/perf_event.h>
>   
> -#include "lapi/syscalls.h"
> +#include "lapi/ldt.h"
>   #include "tst_safe_pthread.h"
>   
>   /* Abstractions for some 32-bit vs 64-bit differences. */
> @@ -199,27 +197,7 @@ static void set_ldt(void)
>   		.useable	 = 0
>   	};
>   
> -	TEST(tst_syscall(__NR_modify_ldt, 1, &data_desc, sizeof(data_desc)));
> -
> -	/*
> -	 * 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 (TST_RET > 0 && ((int)TST_RET) < 0) {
> -		tst_res(TINFO,
> -			"WARNING: Libc mishandled modify_ldt() return value");
> -		TST_ERR = -(int)TST_RET;
> -		TST_RET = -1;
> -	}

This workaround ^^^

> -
> -	if (TST_RET == -1 && TST_ERR == EINVAL) {
> -		tst_brk(TCONF | TTERRNO,
> -			"modify_ldt: 16-bit data segments are probably disabled");
> -	} else if (TST_RET != 0) {
> -		tst_brk(TBROK | TTERRNO, "modify_ldt");
> -	}
> +	SAFE_MODIFY_LDT(1, &data_desc, sizeof(data_desc));
>   }
>   
>   static void try_corrupt_stack(unsigned short *orig_ss)
> diff --git a/testcases/cve/cve-2017-17053.c b/testcases/cve/cve-2017-17053.c
> index fe7b6d694d6ffbbce863abc1672e03ae5f419df1..ec7a534a6c0104e6688f204d763c31ed7a048201 100644
> --- a/testcases/cve/cve-2017-17053.c
> +++ b/testcases/cve/cve-2017-17053.c
> @@ -17,16 +17,14 @@
>   #include "tst_test.h"
>   
>   #ifdef HAVE_ASM_LDT_H
> -#include <asm/ldt.h>
>   #include <pthread.h>
>   #include <signal.h>
>   #include <stdlib.h>
> -#include <sys/syscall.h>
>   #include <sys/wait.h>
>   #include <unistd.h>
>   #include <stdio.h>
>   
> -#include "lapi/syscalls.h"
> +#include "lapi/ldt.h"
>   
>   #define EXEC_USEC   5000000
>   
> @@ -109,7 +107,7 @@ void run_test(void)
>   	struct user_desc desc = { .entry_number = 8191 };
>   
>   	install_sighandler();
> -	syscall(__NR_modify_ldt, 1, &desc, sizeof(desc));
> +	SAFE_MODIFY_LDT(1, &desc, sizeof(desc));
>   
>   	for (;;) {
>   		if (shm->do_exit)
> diff --git a/testcases/kernel/syscalls/fork/fork05.c b/testcases/kernel/syscalls/fork/fork05.c
> index 22edefc3686978fbb9453dffabfcbccb7ea6bb12..9aa12e16201dec8f3d2a4c99df83c4e5e25ef857 100644
> --- a/testcases/kernel/syscalls/fork/fork05.c
> +++ b/testcases/kernel/syscalls/fork/fork05.c
> @@ -55,8 +55,7 @@
>   
>   #if defined(__i386__)
>   
> -#include "lapi/syscalls.h"
> -#include <asm/ldt.h>
> +#include "lapi/ldt.h"
>   
>   static void run(void)
>   {
> @@ -76,7 +75,7 @@ static void run(void)
>   	ldt0.seg_not_present = 0;
>   	ldt0.useable = 1;
>   
> -	tst_syscall(__NR_modify_ldt, 1, &ldt0, sizeof(ldt0));
> +	SAFE_MODIFY_LDT(1, &ldt0, sizeof(ldt0));
>   
>   	asm volatile ("movw %w0, %%fs"::"q" (7));
>   	asm volatile ("movl %%fs:0, %0":"=r" (lo));
> 


-- 
Martin Doucha   mdoucha@suse.cz
SW Quality Engineer
SUSE LINUX, s.r.o.
CORSO IIa
Krizikova 148/34
186 00 Prague 8
Czech Republic


More information about the ltp mailing list