SKAS4
Subsystems (9)
cover SKAS4
Major changes since version 1 -
32-bit compatibility - 32-bit skas4 guests run on skas4 hosts testing of host PTRACE_GETSIGINFO support
A full rolled-up patch is appended to this message.
These patches implement host and guest SKAS4 support for both 32- and 64-bit x86.
I think the new interfaces here are much more acceptable, so I'm going to push this to mainline.
What's new:
two new system calls -
new_mm - creates a new address space and returns a file
descriptor referencing it
switch_mm - moves the calling process to the address space
referenced by the file descriptor passed to it
/proc/<pid>/mm - opening this gives you a file descriptor
referencing the address space occupied by the given pid - this descriptor can be given to switch_mm just as a new_mm descriptor can
siginfo_t extensions - siginfo_t always contained the faulting
address in the SIGSEGV case. However, for it to be useful to UML, it needs the CPU trap number and error code. There already was conditional support for the trap number, which x86 didn't implement. This is enabled, and support for passing out the error code is added.
How this compares to skas3:
Creating a new address space:
skas3 - open /proc/mm
skas4 - new_mm()
Remapping pages within another address space
skas3 - write a structure desribing the change to a /proc/mm
descriptor
skas4 - switch_mm to the address space, run the necessary system
calls directly, switch_mm back to the UML kernel address space
Getting page fault information from a process
skas3 - PTRACE_FAULTINFO
skas4 - PTRACE_GETSIGINFO
This patchset contains 9 patches. Four of them contain the siginfo extension, guest siginfo support, host new_mm/switch_mm support, and guest new_mm/switch_mm support. The rest are preparation patches which shouldn't change anything functionally, but which make the four functional patches smaller and easier to read.
These are against 2.6.24-rc7. Build both host and guest from the same tree. I will be tweaking the interfaces in incompatible ways, so if you play with future versions of this patchset, throw this one out. Definitely don't try to boot a guest built from one version on a host built from another. It will work, but likely you'll get skas0, as there will likely be some interface change which causes the host skas4 checks to fail.
This is very experimental at this point. Don't let it near anything resembling a production system.
Jeff
Signature · 1 line
Work email - jdike at linux dot intel dot com
arch/um/include/as-layout.h +2 -0
@@ -17,6 +17,7 @@#define ASM_STUB_CODE (UML_CONFIG_TOP_ADDR - 2 * UM_KERN_PAGE_SIZE)#define ASM_STUB_DATA (UML_CONFIG_TOP_ADDR - UM_KERN_PAGE_SIZE)#define ASM_STUB_START ASM_STUB_CODE +#define ASM_STUB_END UML_CONFIG_TOP_ADDR/* * This file is included by the assembly stubs, which just want the
@@ -27,6 +28,7 @@#define STUB_CODE ((unsigned long) ASM_STUB_CODE)#define STUB_DATA ((unsigned long) ASM_STUB_DATA)#define STUB_START ((unsigned long) ASM_STUB_START) +#define STUB_END ((unsigned long) ASM_STUB_END)#include "sysdep/ptrace.h"
arch/um/include/os.h +1 -1
@@ -168,7 +168,7 @@ extern int os_fchange_dir(int fd);/* start_up.c */ extern void os_early_checks (void ); -extern int can_do_skas (void ); +extern void can_do_skas (void );extern void os_check_bugs (void );extern void check_host_supports_tls (int *supports_tls,int *tls_min);
arch/um/include/siginfo_segv.h new file +133 -0
133 lines not on this page · raw message
arch/um/include/skas/mm_id.h +1 -1
@@ -7,7 +7,7 @@#define __MM_ID_Hstruct mm_id { -union { +struct {int mm_fd;int pid; } u;
arch/um/include/skas/skas.h +45 -1
63 lines not on this page · raw message
arch/um/include/skas_ptrace.h +3 -1
@@ -7,7 +7,9 @@#define __SKAS_PTRACE_H#define PTRACE_FAULTINFO 52 -#define PTRACE_SWITCH_MM 55 +#ifndef OLD_PTRACE_SWITCH_MM +#define OLD_PTRACE_SWITCH_MM 55 +#endif #include "sysdep/skas_ptrace.h"
arch/um/kernel/ptrace.c +1 -1
@@ -192,7 +192,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) }#endif #ifdef CONFIG_PROC_MM -case PTRACE_SWITCH_MM : { +case OLD_PTRACE_SWITCH_MM : {struct mm_struct *old = child->mm;struct mm_struct *new =proc_mm_get_mm (data);
arch/um/kernel/reboot.c +1 -1
@@ -11,7 +11,7 @@ void (*pm_power_off)(void);static void kill_off_processes (void ) { -if (proc_mm) +if (proc_mm || have_switch_mm)/* * FIXME: need to loop over userspace_pids */
arch/um/kernel/skas/mmu.c +24 -3
@@ -65,6 +65,9 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long proc,return -ENOMEM ; } +extern int copy_context_skas4 (struct mm_id *id); +extern int get_new_mm (void ); +int init_new_context (struct task_struct *task,struct mm_struct *mm) {struct mm_context *from_mm =NULL ;
@@ -101,7 +104,7 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) from_mm = ¤t->mm->context;if (proc_mm) { - ret =new_mm (stack); + ret =make_new_mm (stack);if (ret <0 ) {printk (KERN_ERR "init_new_context_skas - " "new_mm failed, errno = %d\n" , ret);
@@ -109,6 +112,20 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) } to_mm->id.u.mm_fd = ret; } +else if (have_switch_mm) { + to_mm->id.u.mm_fd =get_new_mm (); +if (to_mm->id.u.mm_fd <0 ) { + ret = to_mm->id.u.mm_fd; + goto out_free; + } + + ret =copy_context_skas4 (&to_mm->id); +if (ret <0 ) { +os_close_file (to_mm->id.u.mm_fd); + to_mm->id.u.mm_fd =-1 ; + goto out_free; + } + }else {if (from_mm) to_mm->id.u.pid = copy_context_skas0(stack,
@@ -136,11 +153,15 @@ void destroy_context(struct mm_struct *mm) {struct mm_context *mmu = &mm->context; -if (proc_mm) +if (proc_mm || have_switch_mm)os_close_file (mmu->id.u.mm_fd); -else +else {os_kill_ptraced_process (mmu->id.u.pid,1 ); +if (have_switch_mm) +os_close_file (mmu->id.u.mm_fd); + } +if (!proc_mm || !ptrace_faultinfo) {free_page (mmu->id.stack);pte_lock_deinit (virt_to_page (mmu->last_page_table));
arch/um/kernel/skas/process.c +2 -2
@@ -9,7 +9,7 @@#include "os.h" #include "skas.h" -int new_mm (unsigned long stack) +int make_new_mm (unsigned long stack) {int fd;
@@ -49,7 +49,7 @@ int __init start_uml(void) {stack_protections ((unsigned long ) &cpu0_irqstack);set_sigstack (cpu0_irqstack,THREAD_SIZE ); -if (proc_mm) +if (proc_mm || have_switch_mm) userspace_pid[0 ] =start_userspace (0 );init_new_thread_signals ();
arch/um/kernel/um_arch.c +3 -1
@@ -271,7 +271,9 @@ int __init linux_main(int argc, char **argv)can_do_skas (); -if (proc_mm && ptrace_faultinfo) +if (have_switch_mm) + mode ="SKAS4" ; +else if (proc_mm && ptrace_faultinfo) mode ="SKAS3" ;else mode ="SKAS0" ;
arch/um/os-Linux/skas/mem.c +125 -77
270 lines not on this page · raw message
arch/um/os-Linux/skas/process.c +97 -6
153 lines not on this page · raw message
arch/um/os-Linux/start_up.c +392 -38
531 lines not on this page · raw message
arch/um/sys-i386/ldt.c +1 -1
@@ -436,7 +436,7 @@ long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm)/* * We have a valid from_mm, so we now have to copy the LDT of * from_mm to new_mm, because using proc_mm an new mm with -* an empty/default LDT was created in new_mm() +* an empty/default LDT was created in make_new_mm() */ copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS, .u =
arch/um/sys-i386/stub.S +48 -39
100 lines not on this page · raw message
arch/um/sys-i386/syscalls.c +8 -0
@@ -200,3 +200,11 @@ long sys_sigaction(int sig, const struct old_sigaction __user *act,return ret; } + +extern long do_switch_mm (int fd,int flags,long __user *new, +long __user *save,struct pt_regs *regs); + +long sys_switch_mm (int fd,int flags,long __user *new,long __user *save) +{ +return do_switch_mm (fd, flags, new, save, ¤t->thread.regs); +}
arch/um/sys-x86_64/stub.S +58 -56
125 lines not on this page · raw message
arch/um/sys-x86_64/syscalls.c +9 -1
@@ -30,7 +30,7 @@ long arch_prctl(struct task_struct *task, int code, unsigned long __user *addr) {unsigned long *ptr = addr, tmp;long ret; -int pid = task->mm->context.id.u.pid; +int pid = userspace_pid[0 ];/* * With ARCH_SET_FS (and ARCH_SET_GS is treated similarly to
@@ -112,3 +112,11 @@ void arch_switch_to(struct task_struct *from, struct task_struct *to)arch_prctl (to,ARCH_SET_FS , (void __user *) to->thread.arch.fs); } + +extern long do_switch_mm (int fd,int flags,long __user *new, +long __user *save,struct pt_regs *regs); + +long stub_switch_mm (int fd,int flags,long __user *new,long __user *save) +{ +return do_switch_mm (fd, flags, new, save, ¤t->thread.regs); +}
arch/x86/ia32/ia32_signal.c +2 -0
@@ -65,6 +65,8 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) err |=__put_user (from->_sifields._pad[0 ], &to->_sifields._pad[0 ]);switch (from->si_code >>16 ) {case __SI_FAULT >>16 : + err |=__put_user (from->si_trapno, &to->si_trapno); + err |=__put_user (from->si_error, &to->si_error);break ;case __SI_CHLD >>16 : err |=__put_user (from->si_utime, &to->si_utime);
arch/x86/ia32/ia32entry.S +3 -0
@@ -374,6 +374,7 @@ quiet_ni_syscall: PTREGSCALL stub32_vfork, sys_vfork, %rdi PTREGSCALL stub32_iopl, sys_iopl, %rsi PTREGSCALL stub32_rt_sigsuspend, sys_rt_sigsuspend, %rdx + PTREGSCALL stub32_switch_mm, sys_switch_mm, %r8 ENTRY(ia32_ptregs_common) popq %r11
@@ -726,4 +727,6 @@ ia32_sys_call_table: .quad compat_sys_timerfd .quad sys_eventfd .quad sys32_fallocate + .quad sys_new_mm /* 325 */ + .quad stub32_switch_mm ia32_syscall_end:
arch/x86/ia32/ptrace32.c +3 -2
@@ -38,7 +38,7 @@#define R32 (l,q) \ case offsetof(struct user32, regs.l): stack[offsetof(struct pt_regs, q)/8] = val; break -static int putreg32 (struct task_struct *child,unsigned regno,u32 val) +int putreg32 (struct task_struct *child,unsigned regno,u32 val) {int i;__u64 *stack = (__u64 *)task_pt_regs (child);
@@ -139,7 +139,7 @@ static int putreg32(struct task_struct *child, unsigned regno, u32 val)#define R32 (l,q) \ case offsetof(struct user32, regs.l): *val = stack[offsetof(struct pt_regs, q)/8]; break -static int getreg32 (struct task_struct *child,unsigned regno,u32 *val) +int getreg32 (struct task_struct *child,unsigned regno,u32 *val) {__u64 *stack = (__u64 *)task_pt_regs (child);
@@ -248,6 +248,7 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)case PTRACE_SETOPTIONS :case PTRACE_SET_THREAD_AREA :case PTRACE_GET_THREAD_AREA : +case PTRACE_SWITCH_MM :return sys_ptrace (request, pid, addr, data);default :
arch/x86/kernel/entry_64.S +1 -0
@@ -412,6 +412,7 @@ END(\label) PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend, %rdx PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx PTREGSCALL stub_iopl, sys_iopl, %rsi + PTREGSCALL stub_switch_mm, sys_switch_mm, %r8 ENTRY(ptregscall_common) popq %r11
arch/x86/kernel/ptrace_32.c +3 -3
@@ -83,8 +83,8 @@ static inline int put_stack_long(struct task_struct *task, int offset,return 0 ; } -static int putreg (struct task_struct *child, -unsigned long regno,unsigned long value) +int putreg (struct task_struct *child, +unsigned long regno,unsigned long value) {switch (regno >>2 ) {case GS :
@@ -116,7 +116,7 @@ static int putreg(struct task_struct *child,return 0 ; } -static unsigned long getreg (struct task_struct *child, +unsigned long getreg (struct task_struct *child,unsigned long regno) {unsigned long retval = ~0UL ;
arch/x86/kernel/ptrace_64.c +2 -2
@@ -226,7 +226,7 @@ void ptrace_disable(struct task_struct *child)clear_singlestep (child); } -static int putreg (struct task_struct *child, +int putreg (struct task_struct *child,unsigned long regno,unsigned long value) {unsigned long tmp;
@@ -283,7 +283,7 @@ static int putreg(struct task_struct *child,return 0 ; } -static unsigned long getreg (struct task_struct *child,unsigned long regno) +unsigned long getreg (struct task_struct *child,unsigned long regno) {unsigned long val;switch (regno) {
arch/x86/kernel/sys_i386_32.c +9 -0
@@ -261,3 +261,12 @@ int kernel_execve(const char *filename, char *const argv[], char *const envp[]) : "0" (__NR_execve),"ri" (filename),"c" (argv), "d" (envp) : "memory");return __res; } + +extern long do_switch_mm (int fd,int flags,long __user *new,long __user *save, +struct pt_regs *regs); + +asmlinkage long sys_switch_mm (struct pt_regs regs) +{ +return do_switch_mm (regs.ebx, regs.ecx, (long __user *) regs.edx, + (long __user *) regs.esi, ®s); +}
arch/x86/kernel/sys_x86_64.c +9 -0
@@ -153,3 +153,12 @@ asmlinkage long sys_uname(struct new_utsname __user * name) err |=copy_to_user (&name->machine,"i686" ,5 );return err ? -EFAULT :0 ; } + +extern long do_switch_mm (int fd,int flags,long __user *new, +long __user *save,struct pt_regs *regs); + +asmlinkage long sys_switch_mm (int fd,int flags,long __user *new, +long __user *save,struct pt_regs *regs) +{ +return do_switch_mm (fd, flags, new, save, regs); +}
arch/x86/kernel/syscall_table_32.S +2 -0
@@ -324,3 +324,5 @@ ENTRY(sys_call_table) .long sys_timerfd .long sys_eventfd .long sys_fallocate + .long sys_new_mm + .long sys_switch_mm
arch/x86/mm/fault_32.c +2 -0
@@ -211,6 +211,8 @@ static noinline void force_sig_info_fault(int si_signo, int si_code, info.si_errno =0 ; info.si_code = si_code; info.si_addr = (void __user *)address; + info.si_trapno = tsk->thread.trap_no; + info.si_error = tsk->thread.error_code;force_sig_info (si_signo, &info, tsk); }
arch/x86/mm/fault_64.c +4 -0
@@ -502,6 +502,8 @@ bad_area_nosemaphore: info.si_errno =0 ;/* info.si_code has been set above */ info.si_addr = (void __user *)address; + info.si_trapno = tsk->thread.trap_no; + info.si_error = tsk->thread.error_code;force_sig_info (SIGSEGV , &info, tsk);return ; }
@@ -577,6 +579,8 @@ do_sigbus: info.si_errno =0 ; info.si_code =BUS_ADRERR ; info.si_addr = (void __user *)address; + info.si_trapno = tsk->thread.trap_no; + info.si_error = tsk->thread.error_code;force_sig_info (SIGBUS , &info, tsk);return ; }
fs/proc/base.c +29 -0
@@ -2187,6 +2187,34 @@ static int proc_pid_io_accounting(struct task_struct *task, char *buffer) }#endif +static int proc_pid_mm_open (struct inode *inode,struct file *file) +{ +struct task_struct *task =pid_task (proc_pid (inode),PIDTYPE_PID ); + +if (task ==NULL ) +return -ENOENT ; + +if (task->mm !=NULL ) +atomic_inc (&task->mm->mm_users); + file->private_data = task->mm; +return 0 ; +} + +static int proc_pid_mm_release (struct inode *inode,struct file *file) +{ +struct mm_struct *mm = file->private_data; + +if (mm !=NULL ) +mmput (mm); + +return 0 ; +} + +const struct file_operations proc_pid_mm_operations = { + .open = proc_pid_mm_open, + .release = proc_pid_mm_release, +}; +/* * Thread groups */
@@ -2250,6 +2278,7 @@ static const struct pid_entry tgid_base_stuff[] = {#ifdef CONFIG_TASK_IO_ACCOUNTING INF ("io" ,S_IRUGO , pid_io_accounting), #endif + REG("mm", S_IRUSR | S_IWUSR, pid_mm), }; static int proc_tgid_base_readdir(struct file * filp,
include/asm-generic/siginfo.h +6 -0
@@ -82,6 +82,9 @@ typedef struct siginfo {#ifdef __ARCH_SI_TRAPNOint _trapno;/* TRAP # which caused the signal */ #endif +#ifdef __ARCH_SI_ERROR +int _error;/* CPU error code */ +#endif } _sigfault;/* SIGPOLL */
@@ -112,6 +115,9 @@ typedef struct siginfo {#ifdef __ARCH_SI_TRAPNO#define si_trapno _sifields._sigfault._trapno#endif +#ifdef __ARCH_SI_ERROR +#define si_error _sifields._sigfault._error +#endif #define si_band _sifields._sigpoll._band#define si_fd _sifields._sigpoll._fd
include/asm-um/processor-x86_64.h +1 -0
@@ -37,6 +37,7 @@ static inline void arch_flush_thread(struct arch_thread *thread)static inline void arch_copy_thread (struct arch_thread *from,struct arch_thread *to) { + to->fs = from->fs; }#include "asm/arch/user.h"
include/asm-x86/ia32.h +2 -0
@@ -119,6 +119,8 @@ typedef struct compat_siginfo{/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ struct {unsigned int _addr;/* faulting insn/memory ref. */ +int _trapno;/* TRAP # which caused the signal */ +int _error;/* CPU error code */ } _sigfault;/* SIGPOLL */
include/asm-x86/siginfo.h +3 -0
@@ -5,6 +5,9 @@# define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))#endif +#define __ARCH_SI_TRAPNO +#define __ARCH_SI_ERROR +#include <asm-generic/siginfo.h> #endif
include/asm-x86/unistd_32.h +3 -1
@@ -330,10 +330,12 @@#define __NR_timerfd 322#define __NR_eventfd 323#define __NR_fallocate 324 +#define __NR_new_mm 325 +#define __NR_switch_mm 326#ifdef __KERNEL__ -#define NR_syscalls 325 +#define NR_syscalls 327#define __ARCH_WANT_IPC_PARSE_VERSION#define __ARCH_WANT_OLD_READDIR
include/asm-x86/unistd_64.h +4 -0
@@ -635,6 +635,10 @@ __SYSCALL(__NR_timerfd, sys_timerfd) __SYSCALL(__NR_eventfd, sys_eventfd)#define __NR_fallocate 285 __SYSCALL(__NR_fallocate, sys_fallocate) +#define __NR_new_mm 286 +__SYSCALL(__NR_new_mm, sys_new_mm) +#define __NR_switch_mm 287 +__SYSCALL(__NR_switch_mm, stub_switch_mm)#ifndef __NO_STUBS#define __ARCH_WANT_OLD_READDIR
include/linux/ptrace.h +2 -0
@@ -21,6 +21,8 @@#define PTRACE_SYSCALL 24 +#define PTRACE_SWITCH_MM 33 +/* 0x4200-0x4300 are reserved for architecture-independent additions. */ #define PTRACE_SETOPTIONS 0x4200#define PTRACE_GETEVENTMSG 0x4201
include/linux/sched.h +1 -0
@@ -1665,6 +1665,7 @@ static inline int sas_ss_flags(unsigned long sp)* Routines for handling mm_structs */ extern struct mm_struct *mm_alloc (void ); +extern struct mm_struct *dup_mm (struct task_struct *tsk);/* mmdrop drops the mm and the page tables */ extern void FASTCALL (__mmdrop (struct mm_struct *));
include/linux/signalfd.h +3 -1
@@ -26,6 +26,8 @@ struct signalfd_siginfo {__u64 ssi_utime;__u64 ssi_stime;__u64 ssi_addr; +__u32 ssi_trap_no; +__u32 ssi_error_code;/* * Pad strcture to 128 bytes. Remember to update the
@@ -36,7 +38,7 @@ struct signalfd_siginfo {* comes out of a read(2) and we really don't want to have * a compat on read(2). */ -__u8 __pad[48 ]; +__u8 __pad[40 ]; };
kernel/Makefile +1 -1
@@ -3,7 +3,7 @@ # obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ - exit.o itimer.o time.o softirq.o resource.o \ + exit.o itimer.o time.o softirq.o resource.o mmfs.o \ sysctl.o capability.o ptrace.o timer.o user.o user_namespace.o \ signal.o sys.o kmod.o workqueue.o pid.o \ rcupdate.o extable.o params.o posix-timers.o \
kernel/fork.c +1 -1
@@ -491,7 +491,7 @@ void mm_release(struct task_struct *tsk, struct mm_struct *mm)* Allocate a new mm structure and copy contents from the * mm structure of the passed in task structure. */ -static struct mm_struct *dup_mm (struct task_struct *tsk) +struct mm_struct *dup_mm (struct task_struct *tsk) {struct mm_struct *mm, *oldmm = current->mm;int err;
kernel/mmfs.c new file +446 -0
446 lines not on this page · raw message
kernel/ptrace.c +26 -0
@@ -366,6 +366,29 @@ static int ptrace_setsiginfo(struct task_struct *child, siginfo_t __user * data)return error; } +extern struct mm_struct *fd_to_mm (int fd); + +static int ptrace_switch_mm (struct task_struct *child,int mm_fd) +{ +struct mm_struct *old = child->mm; +struct mm_struct *new =fd_to_mm (mm_fd); + +if (IS_ERR (new)) +return PTR_ERR (new); + +task_lock (child); + +atomic_inc (&new->mm_users); + + child->mm = new; + child->active_mm = new; + +task_unlock (child); +mmput (old); + +return 0 ; +} +int ptrace_request (struct task_struct *child,long request,long addr,long data) {
@@ -390,6 +413,9 @@ int ptrace_request(struct task_struct *child, long request,case PTRACE_DETACH :/* detach a process that was attached. */ ret =ptrace_detach (child, data);break ; +case PTRACE_SWITCH_MM : + ret =ptrace_switch_mm (child, data); +break ;default :break ; }
kernel/signal.c +4 -1
@@ -2088,7 +2088,7 @@ int copy_siginfo_to_user(siginfo_t __user *to, siginfo_t *from)*/ err =__put_user (from->si_signo, &to->si_signo); err |=__put_user (from->si_errno, &to->si_errno); - err |=__put_user ((short )from->si_code, &to->si_code); + err |=__put_user (from->si_code, &to->si_code);switch (from->si_code & __SI_MASK) {case __SI_KILL: err |=__put_user (from->si_pid, &to->si_pid);
@@ -2108,6 +2108,9 @@ int copy_siginfo_to_user(siginfo_t __user *to, siginfo_t *from)#ifdef __ARCH_SI_TRAPNO err |=__put_user (from->si_trapno, &to->si_trapno);#endif +#ifdef __ARCH_SI_ERROR + err |=__put_user (from->si_error, &to->si_error); +#endif break ;case __SI_CHLD: err |=__put_user (from->si_pid, &to->si_pid);
-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
User-mode-linux-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/user-mode-linux-devel