Re: strange behavior with sigreturn() to 32bit

From: stsp
Date: Mon Dec 12 2022 - 23:26:47 EST


Hi,

13.12.2022 05:24, Thomas Gleixner пишет:
Your observation that running this under GDB changes the behaviour of
the error is completely correct because BX/SI are subject to context. So
depending where the combo points to it results in random behaviour.

So nothing strange to see here, really. You got what you asked for:
Thanks for checking, so some problems
were not valid ones, but lets remove the
mov to eax from the test.

Without gdb:
err=0 trapno=d ax=0 ip=100000003

With gdb:
err=18a trapno=d ax=0 ip=403003

Without high RIP poison:
err=18a trapno=d ax=0 ip=3
This case is perfectly valid now, thanks.

Without high RIP poison and with gdb:
err=18a trapno=d ax=0 ip=403003

So under gdb we still see the wrong RIP
value and high RIP part breaks things
only without gdb (gdb "fixes" it).

Attaching the new diff that doesn't do
the mov to eax, so should be correct now.diff --git a/tools/testing/selftests/x86/sigreturn.c b/tools/testing/selftests/x86/sigreturn.c
index 5d7961a5f7f6..60532fd824e4 100644
--- a/tools/testing/selftests/x86/sigreturn.c
+++ b/tools/testing/selftests/x86/sigreturn.c
@@ -101,9 +101,13 @@ asm (".pushsection .text\n\t"
"mov %ss,%ecx\n\t"
"int3\n\t"
".size int3, . - int3\n\t"
+ ".type int31, @function\n\t"
+ "int31:\n\t"
+ "int $0x31\n\t"
".align 4096, 0xcc\n\t"
".popsection");
extern char int3[4096];
+extern char int31[];

/*
* At startup, we prepapre:
@@ -296,6 +300,7 @@ static volatile sig_atomic_t sig_corrupt_final_ss;
# define REG_IP REG_RIP
# define REG_SP REG_RSP
# define REG_CX REG_RCX
+# define REG_AX REG_RAX

struct selectors {
unsigned short cs, gs, fs, ss;
@@ -316,6 +321,7 @@ static unsigned short *csptr(ucontext_t *ctx)
# define REG_IP REG_EIP
# define REG_SP REG_ESP
# define REG_CX REG_ECX
+# define REG_AX REG_EAX

static greg_t *ssptr(ucontext_t *ctx)
{
@@ -444,9 +450,12 @@ static void sigusr1(int sig, siginfo_t *info, void *ctx_void)
*ssptr(ctx) = sig_ss;

ctx->uc_mcontext.gregs[REG_IP] =
- sig_cs == code16_sel ? 0 : (unsigned long)&int3;
+ sig_cs == code16_sel ? ((unsigned long)&int31 -
+ (unsigned long)&int3) | 0x100000000 :
+ (unsigned long)&int3;
ctx->uc_mcontext.gregs[REG_SP] = (unsigned long)0x8badf00d5aadc0deULL;
ctx->uc_mcontext.gregs[REG_CX] = 0;
+ ctx->uc_mcontext.gregs[REG_AX] = 0;

#ifdef __i386__
/*
@@ -515,6 +524,20 @@ static void sigtrap(int sig, siginfo_t *info, void *ctx_void)
sig_trapped = sig;
}

+static void sigsegv(int sig, siginfo_t *info, void *ctx_void)
+{
+ ucontext_t *ctx = (ucontext_t*)ctx_void;
+
+ validate_signal_ss(sig, ctx);
+
+ sig_err = ctx->uc_mcontext.gregs[REG_ERR];
+ sig_trapno = ctx->uc_mcontext.gregs[REG_TRAPNO];
+ printf("err=%x trapno=%x ax=%x ip=%llx\n", sig_err, sig_trapno,
+ (unsigned)ctx->uc_mcontext.gregs[REG_AX],
+ (unsigned long long)ctx->uc_mcontext.gregs[REG_IP]);
+ _exit(0);
+}
+
#ifdef __x86_64__
/* Tests recovery if !UC_STRICT_RESTORE_SS */
static void sigusr2(int sig, siginfo_t *info, void *ctx_void)
@@ -777,6 +800,7 @@ int main()

sethandler(SIGUSR1, sigusr1, 0);
sethandler(SIGTRAP, sigtrap, SA_ONSTACK);
+ sethandler(SIGSEGV, sigsegv, SA_ONSTACK);

/* Easy cases: return to a 32-bit SS in each possible CS bitness. */
total_nerrs += test_valid_sigreturn(64, false, -1);