Skip to content

Commit

Permalink
cve-2015-3290: Fix broken 32bit assembly
Browse files Browse the repository at this point in the history
The 32bit corruption assembly has two bugs:
- EBP is missing from asm clobber list which may result in input/output
  parameters getting overwritten by the "puzzle"
- orig_ss is allocated on stack which will result in segfault when
  restoring %ss to the original value

Add EBP to the clobber list and make sure that mov %[orig_ss], %%ss
will not use address relative to %esp.

Signed-off-by: Martin Doucha <[email protected]>
Acked-by: Cyril Hrubis <[email protected]>
  • Loading branch information
mdoucha authored and metan-ucw committed Sep 18, 2024
1 parent 3f63ff5 commit 968e624
Showing 1 changed file with 24 additions and 13 deletions.
37 changes: 24 additions & 13 deletions testcases/cve/cve-2015-3290.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ static void set_ldt(void)
}
}

static void try_corrupt_stack(unsigned short orig_ss)
static void try_corrupt_stack(unsigned short *orig_ss)
{
#ifdef __x86_64__
asm volatile (
Expand All @@ -231,7 +231,8 @@ static void try_corrupt_stack(unsigned short orig_ss)
/*
* Let 'er rip.
*/
"mov %[ss], %%ss \n\t" /* begin corruption */
"mov %[ss], %%edx \n\t"
"mov %%edx, %%ss \n\t" /* begin corruption */
"movl $1000, %%edx \n\t"
"1: decl %%edx \n\t"
"jnz 1b \n\t"
Expand All @@ -250,7 +251,7 @@ static void try_corrupt_stack(unsigned short orig_ss)
* Stop further corruption. We need to check CPL
* first because we need RPL == CPL.
*/
"mov %[orig_ss], %%ss \n\t" /* end corruption */
"mov (%[orig_ss]), %%ss \n\t" /* end corruption */

"subq $128, %%rsp \n\t"
"pushfq \n\t"
Expand All @@ -262,7 +263,7 @@ static void try_corrupt_stack(unsigned short orig_ss)
"3: int3 \n\t"
"4: \n\t"
: [expected_rsp] "=m" (expected_rsp)
: [ss] "r" (0x7), [orig_ss] "m" (orig_ss)
: [ss] "n" (0x7), [orig_ss] "r" (orig_ss)
: "rax", "rcx", "rdx", "rbp", "r11", "flags"
);
#else
Expand All @@ -277,7 +278,8 @@ static void try_corrupt_stack(unsigned short orig_ss)
/*
* Let 'er rip.
*/
"mov %[ss], %%ss \n\t" /* begin corruption */
"mov %[ss], %%edx \n\t"
"mov %%edx, %%ss \n\t" /* begin corruption */
"movl $1000, %%edx \n\t"
"1: .byte 0xff, 0xca \n\t" /* decl %edx */
"jnz 1b \n\t"
Expand All @@ -298,7 +300,7 @@ static void try_corrupt_stack(unsigned short orig_ss)
* Stop further corruption. We need to check CPL
* first because we need RPL == CPL.
*/
"mov %[orig_ss], %%ss \n\t" /* end corruption */
"mov (%[orig_ss]), %%ss \n\t" /* end corruption */

"pushf \n\t"
"testl $(1<<9),(%%esp) \n\t"
Expand All @@ -309,8 +311,8 @@ static void try_corrupt_stack(unsigned short orig_ss)
"3: int3 \n\t"
"4: mov %%esi, %%ebp \n\t"
: [expected_rsp] "=m" (expected_rsp)
: [ss] "r" (0x7), [orig_ss] "m" (orig_ss)
: "eax", "ecx", "edx", "esi", "flags"
: [ss] "n" (0x7), [orig_ss] "r" (orig_ss)
: "eax", "ecx", "edx", "esi", "ebp", "flags"
);
#endif
}
Expand All @@ -328,10 +330,14 @@ static int perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
static int event_mlock_kb;
static int max_sample_rate;

static void *child_thread(void *arg LTP_ATTRIBUTE_UNUSED)
static void *child_thread(void *arg)
{
/*
* orig_ss must not be accessed via address relative to %esp,
* otherwise mov %[orig_ss], %%ss above will always segfault
*/
unsigned short *orig_ss = arg;
long niter = 0;
unsigned short orig_ss;

struct perf_event_attr pe = {
.size = sizeof(struct perf_event_attr),
Expand Down Expand Up @@ -388,7 +394,7 @@ static void *child_thread(void *arg LTP_ATTRIBUTE_UNUSED)
SAFE_CLOSE(fd);
}

asm volatile ("mov %%ss, %0" : "=rm" (orig_ss));
asm volatile ("mov %%ss, (%0)" :: "r" (orig_ss));

for (niter = 0; running && niter < 1000*1000*1000L; niter++) {

Expand All @@ -414,16 +420,20 @@ static void do_child(void)
int i, ncpus;
pthread_t *threads;
long iter, total_iter = 0;
unsigned short *orig_ss;

tst_res(TINFO, "attempting to corrupt nested NMI stack state");

set_ldt();

ncpus = tst_ncpus();
threads = SAFE_MALLOC(sizeof(*threads) * ncpus);
orig_ss = SAFE_MALLOC(sizeof(unsigned short) * ncpus);

for (i = 0; i < ncpus; i++)
SAFE_PTHREAD_CREATE(&threads[i], NULL, child_thread, NULL);
for (i = 0; i < ncpus; i++) {
SAFE_PTHREAD_CREATE(&threads[i], NULL, child_thread,
&orig_ss[i]);
}

sleep(tst_remaining_runtime());
running = 0;
Expand All @@ -432,6 +442,7 @@ static void do_child(void)
SAFE_PTHREAD_JOIN(threads[i], (void **)&iter);
total_iter += iter;
}
free(orig_ss);
free(threads);

tst_res(TPASS, "can't corrupt nested NMI state after %ld iterations",
Expand Down

0 comments on commit 968e624

Please sign in to comment.