* i386 / sysenter safety test case
@ 2005-03-09 0:23 Zachary Amsden
0 siblings, 0 replies; only message in thread
From: Zachary Amsden @ 2005-03-09 0:23 UTC (permalink / raw)
To: linux-kernel, ltp-list
[-- Attachment #1: Type: text/plain, Size: 1046 bytes --]
Code inspection of entry.S on i386 showed a potential problem - load
through segment without verifying "flatness" on the sysenter path.
Turns out this code is safe, but only by a thread ..
ENTRY(sysenter_entry)
movl TSS_sysenter_esp0(%esp),%esp
sysenter_past_esp:
sti
pushl $(__USER_DS)
pushl %ebp
pushfl
pushl $(__USER_CS)
pushl $SYSENTER_RETURN
/*
* Load the potential sixth argument from user stack.
* Careful about security.
*/
cmpl $__PAGE_OFFSET-3,%ebp
jae syscall_fault
1: movl (%ebp),%ebp
If it weren't for the fact that %ebp relative addresses default to using
the SS segment, we could have loaded through a user segment here to read
arbitrary memory (sysenter does nothing to DS segment). Perhaps this
was considered before, but because of the implications, I thought this
might be worth annotating in the source. Also provided a test case.
Obviously only works on sysenter capable processors. Tested on 2.6.8.
Zach Amsden
zach@vmware.com
[-- Attachment #2: sysenter.S --]
[-- Type: text/plain, Size: 804 bytes --]
#include <sys/syscall.h>
.text
.global sysenter_call
.global sysenter_call_2
/* void sysenter_call(pid_t pid, int signo, short ds, void *addr) */
sysenter_call:
push %ebx
push %edi
push %ebp
push %ds
movl %esp, %edi
movl 20(%esp), %ebx /* pid */
movl 24(%esp), %ecx /* signo */
movl 28(%esp), %ds /* exploit DS */
movl 32(%esp), %ebp
movl %ebp, %esp
push $sysenter_return
push %ecx
push %edx
subl $16, %ebp
push $0xbaadf00d
movl $SYS_kill, %eax
sysenter
/* vsyscall page will ret to us here */
sysenter_return:
mov %edi, %esp
pop %ds
pop %ebp
pop %edi
pop %ebx
ret
sysenter_call_2:
push %ebx
push %ebp
movl 20(%esp), %ebx /* pid */
movl 24(%esp), %ecx /* signo */
movl 28(%esp), %ebp
movl $SYS_kill, %eax
sysenter
.data
test: .long 0
[-- Attachment #3: sysenter.c --]
[-- Type: text/plain, Size: 1506 bytes --]
/*
* Copyright (c) 2005, Zachary Amsden (zach@vmware.com)
* This is licensed under the GPL.
*/
#include <stdio.h>
#include <signal.h>
#include <asm/ldt.h>
#include <asm/segment.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/mman.h>
#define __KERNEL__
#include <asm/page.h>
extern void sysenter_call(pid_t pid, int signo, short ds, void *addr);
extern void sysenter_call_2(pid_t pid, int signo, void *addr);
void catch_sig(int signo, struct sigcontext ctx)
{
__asm__ __volatile__("mov %0, %%ds" : : "r" (__USER_DS));
printf("interrupted %%ebp = 0x%x\n", ctx.ebp);
if (ctx.ebp == 0xbaadf00d)
printf("phew\n");
}
void main(void)
{
struct user_desc desc;
short ds;
unsigned long addr;
unsigned *stack;
unsigned long offset;
stack = (unsigned *)mmap(0, 4096, PROT_EXEC|PROT_READ|PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
stack = &stack[1024];
addr = 0xf0000; /* Try to read BIOS */
offset = __PAGE_OFFSET-(unsigned)stack+addr+16;
signal(SIGUSR1, catch_sig);
desc.entry_number = 0;
desc.base_addr = offset;
desc.limit = 0xffffff;
desc.seg_32bit = 1;
desc.contents = MODIFY_LDT_CONTENTS_DATA;
desc.read_exec_only = 0;
desc.limit_in_pages = 1;
desc.seg_not_present = 0;
desc.useable = 1;
if (modify_ldt(1, &desc, sizeof(desc)) != 0) {
perror("modify_ldt");
}
ds = 0x7; /* TI | RPL 3 */
sysenter_call(getpid(), SIGUSR1, ds, stack);
sysenter_call_2(getpid(), SIGSTOP, __PAGE_OFFSET+4096);
printf("not reached - core should show %%eax == -EFAULT\n");
}
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2005-03-09 0:29 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-03-09 0:23 i386 / sysenter safety test case Zachary Amsden
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.