Date: Sun, 10 Dec 2000 10:36:05 -0800 From: Jake Burkholder <jburkhol@home.com> To: Alfred Perlstein <bright@wintelcom.net> Cc: hackers@FreeBSD.ORG Subject: Re: Patching live kernels Message-ID: <20001210183605.5DD3FBA7D@io.yi.org> In-Reply-To: Message from Alfred Perlstein <bright@wintelcom.net> of "Sun, 10 Dec 2000 04:42:32 PST." <20001210044232.D16205@fw.wintelcom.net>
next in thread | previous in thread | raw e-mail | index | archive | help
This is a multipart MIME message. --==_Exmh_-6582008560 Content-Type: text/plain; charset=us-ascii > Ok, sometimes we find a bug in a particular release where what's > needed is a function replaced with fixed code. > > I'm wondering if it's possible to: > > 1) look at the kernel symbol table for a particular function in a > particular object file (static functions would be even better?) > 2) replace the first instruction in the function with a jmp to > our newly loaded code > 3) have our newly loaded code be "anonymous" meaning no symbols > from it enter the kernel symbol namespace (i want to be able to > re-patch a patched kernel) > > Is it possible? > > Are there any takers? :) io# kldload ./syscall.ko Dec 10 10:09:14 io /boot/kernel/kernel: syscall loaded at 210 io# ./call Dec 10 10:09:26 io /boot/kernel/kernel: bad code... (kgdb) x/6i bad_code 0xc01235a0 <bad_code>: push %ebp 0xc01235a1 <bad_code+1>: mov %esp,%ebp 0xc01235a3 <bad_code+3>: push $0xc02cc6d0 0xc01235a8 <bad_code+8>: call 0xc0198a30 <printf> 0xc01235ad <bad_code+13>: leave 0xc01235ae <bad_code+14>: ret (kgdb) x/s 0xc02cc6d0 0xc02cc6d0 <__umoddi3+672>: "bad code...\n" io# kldload ./kpatch.ko io# ./kpatch -f bad_code -t good_code Dec 10 10:11:24 io /boot/kernel/kernel: patching from: 0xc01235a0 to: 0xc0fbd4c4 (kgdb) x/i bad_code 0xc01235a0 <bad_code>: jmp 0xc0fbd4c4 (kgdb) x/6i 0xc0fbd4c4 0xc0fbd4c4: push %ebp 0xc0fbd4c5: mov %esp,%ebp 0xc0fbd4c7: push $0xc0fbd528 0xc0fbd4cc: call 0xc0198a30 <printf> 0xc0fbd4d1: leave 0xc0fbd4d2: ret (kgdb) x/s 0xc0fbd528 0xc0fbd528: "good code!!\n" io# ./call Dec 10 10:13:17 io /boot/kernel/kernel: good code!! I'm not sure if static functions are in the kernel symbol table, but you should be able to get the address with nm and pass it to kpatch instead of the name, ./kpatch -f 0x... -t good_code; this is untested. Whatever symbols are in your module will still be in the kernel symbol table, removing them is more involved but not impossible, all the magic is in kern/kern_linker.c. Just rename whatever function you are loading, repatch, and then unload the old module. If you can ensure that nothing will call the loaded code while you're repatching you should be able to unload first to avoid the renaming. Use with extreme caution. Release, pff, you don't fool me :) Jake --==_Exmh_-6582008560 Content-Type: text/plain ; name="Makefile"; charset=us-ascii Content-Description: Makefile Content-Disposition: attachment; filename="Makefile" # Makefile for building the sample syscall module SRCS = kpatch-sys.c KMOD = kpatch KO = ${KMOD}.ko KLDMOD = t kpatch: cc -o kpatch kpatch.c CLEANFILES+= kpatch .include <bsd.kmod.mk> CFLAGS= -D_KERNEL -Wall -Wredundant-decls -Wnested-externs -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith -Winline -Wcast-qual -fformat-extensions -DKLD_MODULE -nostdinc -I- -I. -I@ -I@/../include -mpreferred-stack-boundary=2 --==_Exmh_-6582008560 Content-Type: text/plain ; name="kpatch.c"; charset=us-ascii Content-Description: kpatch.c Content-Disposition: attachment; filename="kpatch.c" #include <sys/param.h> #include <sys/linker.h> #include <sys/module.h> #include <sys/syscall.h> #include <err.h> #include <errno.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sysexits.h> #include <unistd.h> extern char *optarg; extern int optind; static void usage(void); int main(int ac, char **av) { struct kld_sym_lookup from; struct kld_sym_lookup to; struct module_stat stat; int kfid; int mfid; int c; bzero(&from, sizeof from); bzero(&stat, sizeof stat); bzero(&to, sizeof to); from.version = sizeof from; stat.version = sizeof stat; to.version = sizeof to; while ((c = getopt(ac, av, "f:t:")) != -1) switch (c) { case 'f': if (bcmp(optarg, "0x", 2) == 0) from.symvalue = strtol(optarg, NULL, 16); else from.symname = optarg; break; case 't': if (bcmp(optarg, "0x", 2) == 0) to.symvalue = strtol(optarg, NULL, 16); else to.symname = optarg; break; case '?': default: usage(); } if (from.symvalue == 0) { kfid = kldfind("kernel"); kldsym(kfid, KLDSYM_LOOKUP, &from); } if (to.symvalue == 0) { for (mfid = 0; (mfid = kldnext(mfid)) != 0;) if (to.symvalue == 0 && kldsym(mfid, KLDSYM_LOOKUP, &to) == 0) break; } printf("from: 0x%lx to: 0x%lx\n", from.symvalue, to.symvalue); modstat(modfind("kpatch"), &stat); return syscall(stat.data.intval, from.symvalue, to.symvalue); } static void usage(void) { fprintf(stderr, "usage: kpatch -f <from> -t <to>\n"); exit(EX_USAGE); } --==_Exmh_-6582008560 Content-Type: text/plain ; name="kpatch-sys.c"; charset=us-ascii Content-Description: kpatch-sys.c Content-Disposition: attachment; filename="kpatch-sys.c" #include <sys/types.h> #include <sys/param.h> #include <sys/proc.h> #include <sys/module.h> #include <sys/sysent.h> #include <sys/kernel.h> #include <sys/systm.h> extern char do_jmp[]; extern char do_jmp_end[]; asm( " .globl do_jmp ; " "do_jmp: " " jmp . + 1 << 16 ; " " .globl do_jmp_end ; " "do_jmp_end: " ); struct kpatch_args { char * from; char * to; }; static int kpatch(struct proc *p, struct kpatch_args *uap) { printf("patching from: %p to: %p\n", uap->from, uap->to); bcopy(do_jmp, uap->from, do_jmp_end - do_jmp); uap->from++; *(int *)uap->from = uap->to - uap->from - 4; return 0; } static struct sysent kpatch_sysent = { 2, (sy_call_t *)kpatch }; static int offset = NO_SYSCALL; static int kpatch_load(struct module *module, int cmd, void *arg) { int error = 0; switch (cmd) { case MOD_LOAD: printf("kpatch loaded at %d\n", offset); break; case MOD_UNLOAD: printf("kpatch unloaded from %d\n", offset); break; default: error = EINVAL; break; } return error; } SYSCALL_MODULE(kpatch, &offset, &kpatch_sysent, kpatch_load, NULL); --==_Exmh_-6582008560-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-hackers" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20001210183605.5DD3FBA7D>