Live Patching Function on 2.6.11.7
Subsystems (6)
PATCH 1/1 Live Patching Function on 2.6.11.7
The patch was over 50k, so I separate it to each architecture and in line..
This patch add function called "Live patching" which is defined on OSDL's carrier grade linux requiremnt definition to linux 2.6.11.7 kernel. The live patching allows process to patch on-line (without restarting process) on i386 and x86_64 architectures, by overwriting jump assembly code on entry point of functions which you want to fix, to patched functions.
The live patching function is very common on high-availability system such as carrier system, and this patch realize it also on linux. (Patch & process restart time is very critical on such high-availability system, live patch allows you to milliseconds order process stopping time to apply new patch.)
The basis is below:
1. Live patch command loads the patch modules to target process's memory area,
2. Live patch command resolve patch symbol.
3. Live patch command overwrite jump code to the entry point of function which you want to fix, to the patch module's symbol.
Kernel patch and user mode tools are required, and both of them are available at http://pannus.sourceforge.net
Please take a look and give us comments!
This patch add following system calls and function.
o mmap3: maps patch to target process's memory area with security check.
o accesspvm: access(read/write) target process's memory area.
o init_pend: initialization of live patch sequence on target process.
o rt_handlereturn: run initialize root of each patch (same as signal handler).
o check_init: check that the initialization is finished or not.
o munmap3: unmap patch from target process's memory area.
Signature · 6 lines
Takashi Ikebe NTT Network Service Systems Laboratories 9-11, Midori-Cho 3-Chome Musashino-Shi, Tokyo 180-8585 Japan Tel : +81 422 59 4246, Fax : +81 422 60 4012 e-mail : [email protected]
arch/i386/kernel/Makefile +1 -1
@@ -7,7 +7,7 @@ extra-y := head.o init_task.o vmlinux.ld obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_i386.o \ pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \ - doublefault.o quirks.o + doublefault.o quirks.o accesspvm.o exechandle.o obj-y += cpu/ obj-y += timers/
arch/i386/kernel/accesspvm.c +128 -0
128 lines not on this page · raw message
arch/i386/kernel/asm-offsets.c +1 -0
@@ -52,6 +52,7 @@ void foo(void)OFFSET (TI_preempt_count, thread_info, preempt_count);OFFSET (TI_addr_limit, thread_info, addr_limit);OFFSET (TI_restart_block, thread_info, restart_block); +OFFSET (TI_inipending, thread_info, inipending);BLANK ();OFFSET (EXEC_DOMAIN_handler, exec_domain, handler);
arch/i386/kernel/entry.S +39 -0
@@ -172,8 +172,15 @@ ENTRY(resume_userspace) andl $_TIF_WORK_MASK, %ecx # is there any work to be done on # int/exception return? jne work_pending + cmpl $0,TI_inipending(%ebp) #for live patching fook. + jne resume_init jmp restore_all +resume_init: + movl $0,TI_inipending(%ebp) + call do_init + jmp resume_userspace + #ifdef CONFIG_PREEMPT ENTRY(resume_kernel) cli
@@ -263,6 +270,9 @@ restore_all: # perform work that needs to be done immediately before resumption ALIGN work_pending: + cmpl $0,TI_inipending(%ebp) + jne work_init +work_pending2: testb $_TIF_NEED_RESCHED, %cl jz work_notifysig work_resched:
@@ -297,6 +307,29 @@ work_notifysig_v86: call do_notify_resume jmp restore_all + # perform live patching + ALIGN +work_init: + testl $VM_MASK, EFLAGS(%esp) + movl %esp, %eax + jne work_init_v86 + + movl $0,TI_inipending(%ebp) + xorl %edx, %edx + call do_init + jmp work_pending2 + + ALIGN +work_init_v86: + movl $0,TI_inipending(%ebp) + pushl %ecx # save ti_flags for do_notify_resume + call save_v86_state # %eax contains pt_regs pointer + popl %ecx + movl %eax, %esp + xorl %edx, %edx + call do_init_v86 + jmp work_pending2 + # perform syscall exit tracing ALIGN syscall_trace_entry:
@@ -862,5 +895,11 @@ ENTRY(sys_call_table) .long sys_add_key .long sys_request_key .long sys_keyctl + .long sys_mmap3 + .long sys_accesspvm /* 290 */ + .long sys_init_pend + .long sys_rt_handlereturn + .long sys_check_init + .long sys_munmap3 syscall_table_size=(.-sys_call_table)
arch/i386/kernel/exechandle.c +611 -0
611 lines not on this page · raw message
arch/i386/kernel/sys_i386.c +66 -3
106 lines not on this page · raw message
arch/i386/mm/mmap.c +2 -0
@@ -62,10 +62,12 @@ void arch_pick_mmap_layout(struct mm_str current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY) { mm->mmap_base = TASK_UNMAPPED_BASE; mm->get_unmapped_area = arch_get_unmapped_area; + mm->get_unmapped_area2 = arch_get_unmapped_area2; mm->unmap_area = arch_unmap_area; } else { mm->mmap_base =mmap_base (mm); mm->get_unmapped_area = arch_get_unmapped_area_topdown; + mm->get_unmapped_area2 = arch_get_unmapped_area_topdown2; mm->unmap_area = arch_unmap_area_topdown; } }
include/asm-i386/exechandle.h +21 -0
@@ -0,0 +1,21 @@ +#ifndef _ASM_X86_64_EXECHANDLE_H +#define _ASM_X86_64_EXECHANDLE_H + +#include <asm/types.h> +#include <asm/signal.h> + + +struct initaction +{ +void (*inithandler)(int ); +void (*restorer)(void ); +}; + +struct k_initaction +{ +struct initaction ia; +}; + +void do_init (struct pt_regs *regs,sigset_t *oldset); + +#endif
include/asm-i386/thread_info.h +3 -0
@@ -44,6 +44,9 @@ struct thread_info {of nested (IRQ) stacks */ __u8 supervisor_stack[0 ]; + +__u32 inipending;/* Pending flags for live patch */ + __u32 inifinish; /* Finish flags for live patch */ };#else /* !__ASSEMBLY__ */
include/asm-i386/unistd.h +7 -1
@@ -294,8 +294,14 @@#define __NR_add_key 286#define __NR_request_key 287#define __NR_keyctl 288 +#define __NR_mmap3 289 +#define __NR_accesspvm (__NR_mmap3+1) +#define __NR_init_pend (__NR_mmap3+2) +#define __NR_rt_handlereturn (__NR_mmap3+3) +#define __NR_check_init (__NR_mmap3+4) +#define __NR_munmap3 (__NR_mmap3+5) -#define NR_syscalls 289 +#define NR_syscalls 294/* * user-visible error numbers are in the range -1 - -128: see
include/linux/capability.h +4 -0
@@ -288,6 +288,10 @@ typedef __u32 kernel_cap_t;#define CAP_AUDIT_CONTROL 30 +/* Allow use of memory access system calls for Live Patching */ + +#define CAP_SYS_PANNUS 31 +#ifdef __KERNEL__/* * Bounding set
include/linux/mm.h +7 -0
@@ -614,6 +614,7 @@ extern int install_page(struct mm_structextern int install_file_pte (struct mm_struct *mm,struct vm_area_struct *vma,unsigned long addr,unsigned long pgoff,pgprot_t prot);extern int handle_mm_fault (struct mm_struct *mm,struct vm_area_struct *vma,unsigned long address,int write_access);extern int make_pages_present (unsigned long addr,unsigned long end); +extern int make_pages_present2 (unsigned long addr,unsigned long end,struct task_struct *tsk);extern int access_process_vm (struct task_struct *tsk,unsigned long addr,void *buf,int len,int write);void install_arg_page (struct vm_area_struct *,struct page *,unsigned long );
@@ -730,10 +731,16 @@ extern void exit_mmap(struct mm_struct *extern unsigned long get_unmapped_area (struct file *,unsigned long ,unsigned long ,unsigned long ,unsigned long ); +extern unsigned long get_unmapped_area2 (struct file *,unsigned long ,unsigned long ,unsigned long ,unsigned long ,struct task_struct *); +extern unsigned long do_mmap_pgoff (struct file *file,unsigned long addr,unsigned long len,unsigned long prot,unsigned long flag,unsigned long pgoff); +extern unsigned long do_mmap_pgoff2 (struct file *file,unsigned long addr, +unsigned long len,unsigned long prot, +unsigned long flag,unsigned long pgoff,struct task_struct *); +static inline unsigned long do_mmap (struct file *file,unsigned long addr,unsigned long len,unsigned long prot,unsigned long flag,unsigned long offset)
include/linux/mman.h +13 -0
@@ -64,4 +64,17 @@ calc_vm_flag_bits(unsigned long flags) _calc_vm_trans(flags, MAP_LOCKED, VM_LOCKED ); } +/* +* Struct of argument to pass the mmap3 system call. +*/ +typedef struct _mmap3_arg_struct { +unsigned long addr;/* address where file is loaded */ +unsigned long len;/* length of data to be maped */ +unsigned long prot;/* permission of the memory where the file is mapped */ +unsigned long flags;/* flag of mapped memory */ +unsigned long fd;/* file descriptor of data to be mapped */ +unsigned long pgoff;/* page offset of data to be mapped */ +unsigned long pid;/* process ID */ +}mmap3_arg_struct_t ; +#endif /* _LINUX_MMAN_H */
include/linux/sched.h +18 -0
@@ -21,6 +21,7 @@#include <asm/ptrace.h> #include <asm/mmu.h> #include <asm/cputime.h> +#include <asm/exechandle.h> #include <linux/smp.h> #include <linux/sem.h>
@@ -197,9 +198,19 @@ extern unsigned long arch_get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);extern unsigned long +arch_get_unmapped_area2 (struct file *,unsigned long ,unsigned long , +unsigned long ,unsigned long ,struct task_struct *); + +extern unsigned long arch_get_unmapped_area_topdown (struct file *filp,unsigned long addr,unsigned long len,unsigned long pgoff,unsigned long flags); + +extern unsigned long +arch_get_unmapped_area_topdown2 (struct file *filp,unsigned long addr, +unsigned long len,unsigned long pgoff, +unsigned long flags,struct task_struct *); +extern void arch_unmap_area (struct vm_area_struct *area);extern void arch_unmap_area_topdown (struct vm_area_struct *area);
@@ -211,6 +222,11 @@ struct mm_struct {unsigned long (*get_unmapped_area) (struct file *filp,unsigned long addr,unsigned long len,unsigned long pgoff,unsigned long flags); +unsigned long (*get_unmapped_area2) (struct file *filp, +unsigned long addr,unsigned long len, +unsigned long pgoff,unsigned long flags, +struct task_struct * tsk); +void (*unmap_area) (struct vm_area_struct *area);unsigned long mmap_base;/* base of mmap area */ unsigned long free_area_cache;/* first hole */
@@ -685,6 +701,7 @@ struct task_struct {struct mempolicy *mempolicy;short il_next;#endif +struct k_initaction k_ia;/*Inialization info for live patch */ };static inline pid_t process_group (struct task_struct *tsk)
@@ -1173,6 +1190,7 @@ static inline void arch_pick_mmap_layout { mm->mmap_base =TASK_UNMAPPED_BASE ; mm->get_unmapped_area = arch_get_unmapped_area; + mm->get_unmapped_area2 = arch_get_unmapped_area2; mm->unmap_area = arch_unmap_area; }#endif
kernel/fork.c +7 -0
@@ -2,6 +2,7 @@* linux/kernel/fork.c * * Copyright (C) 1991, 1992 Linus Torvalds +* Copyright (C) 2004-2005 NTT Corporation */ /*
@@ -412,6 +413,12 @@ void mm_release(struct task_struct *tsk,u32 __user * tidptr = tsk->clear_child_tid; tsk->clear_child_tid =NULL ; +/* initialize flag and information for live patch */ + tsk->thread_info->inipending=0 ; + tsk->thread_info->inifinish=0 ; + tsk->k_ia.ia.inithandler=NULL ; + tsk->k_ia.ia.restorer=NULL ; +/* * We don't check the error code - if userspace has * not set up a proper pointer then tough luck.
mm/memory.c +21 -0
@@ -2209,6 +2209,27 @@ int make_pages_present(unsigned long addreturn ret == len ?0 :-1 ; } +int make_pages_present2 (unsigned long addr,unsigned long end,struct task_struct *tsk) +{ +int ret, len, write; +struct vm_area_struct * vma; + + vma =find_vma (tsk->mm, addr); +if (!vma) +return -1 ; + write = (vma->vm_flags &VM_WRITE ) !=0 ; +if (addr >= end) +BUG (); +if (end > vma->vm_end) +BUG (); + len = (end+PAGE_SIZE -1 )/PAGE_SIZE -addr/PAGE_SIZE ; + ret =get_user_pages (tsk, tsk->mm, addr, + len, write,0 ,NULL ,NULL ); +if (ret <0 ) +return ret; +return ret == len ?0 :-1 ; +} +/* * Map a vmalloc()-space virtual address to the physical page. */
mm/mmap.c +407 -0
437 lines not on this page · raw message
Quoted 4 lines · Takashi Ikebe
The patch was over 50k, so I separate it to each architecture and in line..
This patch add function called "Live patching" which is defined on OSDL's carrier grade linux requiremnt definition to linux 2.6.11.7 kernel.
Traditionally beeing in OSDL specs was a very good reason not to merge patches.
Can you please come up with real arguments instead of this requirements bullshit. Also I hope OSDL would invest their money in more useful things than CGL, why has this idiocy still not stopped?