Commit 22f0b7f9 authored by Jeff Dike's avatar Jeff Dike Committed by Linus Torvalds

[PATCH] uml: add elf vsyscall support

From: Bodo Stroesser

This is the first patch of a series of four.
These patches allow the use of sysenter-systemcalls in UML
if the host support sysenter.
Some facts have to be noted:
- the sysenter instruction does not save anything, not even the
  return address. Thus the host-kernel builds a stackframe with an
  fixed return address for the backjump to the vsyscall-page. All
  kernels that support sysenter thus must have a vsyscall-page
- The hosts vsyscall-page is visible in all memory-contexts on the
  host, even in those of the processes running on UML. This cannot
  be changed.
So the best way to implement sysenter is to integrate the host's
vsyscall-page into UML, if available.

This patch creates a new source file containing an UML
initialization function. The function scans the Elf-auxiliary vector
that is prepared by the host for relevant information about:
- vsyscall elf-header
- vsyscall entry
- machine type (called "platform", e.g. "i586" or "i686")
- hardware capabilities
These informations are inserted into the Elf-auxiliary-vector that is
generated if an UML process calls "execXX()". If the information from
the auxiliray-vector is not complete, UML uses the previos default
values, with one exception: if the host has no vsyscall-page, UML now
does no longer insert AT_SYSINFO or AT_SYSINFO_EHDR elements. (I think,
that's better than writing dummies)

Since the host's vsyscall-page is always visible to UML processes, this
change is enough to let UML with an i686-compiled glibc use sysenter.

what's missing:
- is_syscall() in SKAS cannot access the code in the vsyscall-page via
  copy_from_user(), thus singlesteppers still could break out. (Note:
  that's not new, if someone jumps willingly to the sysenter-entry in
  the vsyscall-page, he can do that without the patch, too).
- a debugger cannot access the code in the vsyscall-page via
  ptrace( PEEKTEXT, ...)

Risks:
could there by any feature of the host's processor, that is indicated in
the hardware capabilities, but must not be used in UML?
Signed-off-by: default avatarBodo Stroesser <bodo.stroesser@fujitsu-siemens.com>
Signed-off-by: default avatarJeff Dike <jdike@addtoit.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 06256155
...@@ -81,6 +81,8 @@ static void last_ditch_exit(int sig) ...@@ -81,6 +81,8 @@ static void last_ditch_exit(int sig)
extern int uml_exitcode; extern int uml_exitcode;
extern void scan_elf_aux( char **envp);
int main(int argc, char **argv, char **envp) int main(int argc, char **argv, char **envp)
{ {
char **new_argv; char **new_argv;
...@@ -147,6 +149,8 @@ int main(int argc, char **argv, char **envp) ...@@ -147,6 +149,8 @@ int main(int argc, char **argv, char **envp)
set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
scan_elf_aux( envp);
do_uml_initcalls(); do_uml_initcalls();
ret = linux_main(argc, argv); ret = linux_main(argc, argv);
......
...@@ -44,11 +44,6 @@ struct cpuinfo_um boot_cpu_data = { ...@@ -44,11 +44,6 @@ struct cpuinfo_um boot_cpu_data = {
.ipi_pipe = { -1, -1 } .ipi_pipe = { -1, -1 }
}; };
/* Placeholder to make UML link until the vsyscall stuff is actually
* implemented
*/
void *__kernel_vsyscall;
unsigned long thread_saved_pc(struct task_struct *task) unsigned long thread_saved_pc(struct task_struct *task)
{ {
return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas, return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
......
...@@ -3,9 +3,10 @@ ...@@ -3,9 +3,10 @@
# Licensed under the GPL # Licensed under the GPL
# #
obj-y = file.o process.o time.o tty.o user_syms.o drivers/ obj-y = elf_aux.o file.o process.o time.o tty.o user_syms.o drivers/
USER_OBJS := $(foreach file,file.o process.o time.o tty.o,$(obj)/$(file)) USER_OBJS := elf_aux.o file.o process.o time.o tty.o
USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
$(USER_OBJS) : %.o: %.c $(USER_OBJS) : %.o: %.c
$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
/*
* arch/um/kernel/elf_aux.c
*
* Scan the Elf auxiliary vector provided by the host to extract
* information about vsyscall-page, etc.
*
* Copyright (C) 2004 Fujitsu Siemens Computers GmbH
* Author: Bodo Stroesser (bodo.stroesser@fujitsu-siemens.com)
*/
#include <elf.h>
#include <stddef.h>
#include "init.h"
#if ELF_CLASS == ELFCLASS32
typedef Elf32_auxv_t elf_auxv_t;
#else
typedef Elf64_auxv_t elf_auxv_t;
#endif
char * elf_aux_platform;
long elf_aux_hwcap;
long vsyscall_ehdr;
long vsyscall_end;
long __kernel_vsyscall;
__init void scan_elf_aux( char **envp)
{
long page_size = 0;
elf_auxv_t * auxv;
while ( *envp++ != NULL) ;
for ( auxv = (elf_auxv_t *)envp; auxv->a_type != AT_NULL; auxv++) {
switch ( auxv->a_type ) {
case AT_SYSINFO:
__kernel_vsyscall = auxv->a_un.a_val;
break;
case AT_SYSINFO_EHDR:
vsyscall_ehdr = auxv->a_un.a_val;
break;
case AT_HWCAP:
elf_aux_hwcap = auxv->a_un.a_val;
break;
case AT_PLATFORM:
elf_aux_platform = auxv->a_un.a_ptr;
break;
case AT_PAGESZ:
page_size = auxv->a_un.a_val;
break;
}
}
if ( ! __kernel_vsyscall || ! vsyscall_ehdr ||
! elf_aux_hwcap || ! elf_aux_platform ||
! page_size || (vsyscall_ehdr % page_size) ) {
__kernel_vsyscall = 0;
vsyscall_ehdr = 0;
elf_aux_hwcap = 0;
elf_aux_platform = "i586";
}
else {
vsyscall_end = vsyscall_ehdr + page_size;
}
}
...@@ -10,7 +10,8 @@ ...@@ -10,7 +10,8 @@
#include "user.h" #include "user.h"
#define ELF_PLATFORM "i586" extern char * elf_aux_platform;
#define ELF_PLATFORM (elf_aux_platform)
#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) #define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
...@@ -56,15 +57,13 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG]; ...@@ -56,15 +57,13 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
pr_reg[16] = PT_REGS_SS(regs); \ pr_reg[16] = PT_REGS_SS(regs); \
} while(0); } while(0);
#if 0 /* Turn this back on when UML has VSYSCALL working */
#define VSYSCALL_BASE (__fix_to_virt(FIX_VSYSCALL))
#else
#define VSYSCALL_BASE 0
#endif
#define VSYSCALL_EHDR ((const struct elfhdr *) VSYSCALL_BASE) extern long vsyscall_ehdr;
#define VSYSCALL_ENTRY ((unsigned long) &__kernel_vsyscall) extern long vsyscall_end;
extern void *__kernel_vsyscall; extern long __kernel_vsyscall;
#define VSYSCALL_BASE vsyscall_ehdr
#define VSYSCALL_END vsyscall_end
/* /*
* Architecture-neutral AT_ values in 0-17, leave some room * Architecture-neutral AT_ values in 0-17, leave some room
...@@ -75,8 +74,10 @@ extern void *__kernel_vsyscall; ...@@ -75,8 +74,10 @@ extern void *__kernel_vsyscall;
#define ARCH_DLINFO \ #define ARCH_DLINFO \
do { \ do { \
NEW_AUX_ENT(AT_SYSINFO, VSYSCALL_ENTRY); \ if ( vsyscall_ehdr ) { \
NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL_BASE); \ NEW_AUX_ENT(AT_SYSINFO, __kernel_vsyscall); \
NEW_AUX_ENT(AT_SYSINFO_EHDR, vsyscall_ehdr); \
} \
} while (0) } while (0)
/* /*
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
#include "asm/archparam.h" #include "asm/archparam.h"
#define ELF_HWCAP (0) extern long elf_aux_hwcap;
#define ELF_HWCAP (elf_aux_hwcap)
#define SET_PERSONALITY(ex, ibcs2) do ; while(0) #define SET_PERSONALITY(ex, ibcs2) do ; while(0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment