Skip to contentSkip to conversation

Live Patching Function on 2.6.11.7

PATCH In review Takashi Ikebe 2 participants 2 messages Apr 18, 2005

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

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
diff -urpN linux-2.6.11.7-vanilla/arch/i386/kernel/Makefile linux-2.6.11.7-pannus-i386/arch/i386/kernel/Makefile
@@ -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
diff -urpN linux-2.6.11.7-vanilla/arch/i386/kernel/asm-offsets.c linux-2.6.11.7-pannus-i386/arch/i386/kernel/asm-offsets.c
@@ -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
diff -urpN linux-2.6.11.7-vanilla/arch/i386/kernel/entry.S linux-2.6.11.7-pannus-i386/arch/i386/kernel/entry.S
@@ -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
diff -urpN linux-2.6.11.7-vanilla/arch/i386/mm/mmap.c linux-2.6.11.7-pannus-i386/arch/i386/mm/mmap.c
@@ -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
diff -urpN linux-2.6.11.7-vanilla/include/asm-i386/exechandle.h linux-2.6.11.7-pannus-i386/include/asm-i386/exechandle.h
@@ -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
diff -urpN linux-2.6.11.7-vanilla/include/asm-i386/thread_info.h linux-2.6.11.7-pannus-i386/include/asm-i386/thread_info.h
@@ -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
diff -urpN linux-2.6.11.7-vanilla/include/asm-i386/unistd.h linux-2.6.11.7-pannus-i386/include/asm-i386/unistd.h
@@ -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
diff -urpN linux-2.6.11.7-vanilla/include/linux/capability.h linux-2.6.11.7-pannus-i386/include/linux/capability.h
@@ -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
diff -urpN linux-2.6.11.7-vanilla/include/linux/mm.h linux-2.6.11.7-pannus-i386/include/linux/mm.h
@@ -614,6 +614,7 @@ extern int install_page(struct mm_struct
 extern 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
diff -urpN linux-2.6.11.7-vanilla/include/linux/mman.h linux-2.6.11.7-pannus-i386/include/linux/mman.h
@@ -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
diff -urpN linux-2.6.11.7-vanilla/include/linux/sched.h linux-2.6.11.7-pannus-i386/include/linux/sched.h
@@ -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
diff -urpN linux-2.6.11.7-vanilla/kernel/fork.c linux-2.6.11.7-pannus-i386/kernel/fork.c
@@ -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
diff -urpN linux-2.6.11.7-vanilla/mm/memory.c linux-2.6.11.7-pannus-i386/mm/memory.c
@@ -2209,6 +2209,27 @@ int make_pages_present(unsigned long add
 	return 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

#1 lore raw
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?