Tuesday, 2 March 2021

Kprobe Example

Kprobe can be used in latest kernels when the jprobe is discontinued. I am updating the blog with latest 5.19 linux kernel.

In the pre-handler the arguments need to be fetched using the registers. The arguments are passed in following sequence for x86 :
first 6 arguments in rdi, rsi, rdx, rcx, r8, r9

So if we are trying to probe a function "submit_bio" which has signature : 
void submit_bio(struct bio *bio)

Then we can take fetch the first argument using rdi register. It can be done like : 
bio_ptr = (struct bio *)regs->di;
 


/*kprobe_example.c*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/sched.h>
#include <linux/blk_types.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>

static char symbol[KSYM_NAME_LEN] = "submit_bio";
module_param_string(symbol, symbol, KSYM_NAME_LEN, 0644);

/* For each probe you need to allocate a kprobe structure */
static struct kprobe kp = {
        .symbol_name    = symbol,
};

/* For each probe you need to allocate a kprobe structure */
static struct kprobe kp;

/* kprobe pre_handler: called just before the probed instruction is executed */
int handler_pre(struct kprobe *p, struct pt_regs *regs)
{
    static int x = 0;
    struct bio *bio_ptr = NULL;
    if (x%10 == 0)
    {
        // first 6 arguments in rdi, rsi, rdx, rcx, r8, r9
        printk("MY pre_handler:rdi=0x%08lx, rsi=0x%08lx, rdx=0x%08lx\n",
            regs->di, regs->si, regs->dx);
        bio_ptr = (struct bio *)regs->di;
        if (bio_ptr && bio_ptr->bi_bdev && bio_ptr->bi_bdev->bd_disk ) {
            printk("disk_name = %s\n", bio_ptr->bi_bdev->bd_disk->disk_name);
            printk("disk_ptr = %p\n",bio_ptr->bi_bdev->bd_disk);
        }
         printk("MY pre_handler: p->addr=0x%p, eip=%lx, eflags=0x%lx\n",
                p->addr, regs->ip, regs->flags);
        dump_stack();
   }
    x++;
    return 0;
}

/* kprobe post_handler: called after the probed instruction is executed */
void handler_post(struct kprobe *p, struct pt_regs *regs, unsigned long flags)
{
        static int y = 0;
        if (y%1000 == 0) {
                printk("MY post_handler: p->addr=0x%p, eflags=0x%lx\n", p->addr, regs->flags);
        }
        y++;
}


int init_module(void)
{
        int ret;
        kp.pre_handler = handler_pre;
        kp.post_handler = handler_post;
        if ((ret = register_kprobe(&kp) < 0)) {
                printk("register_kprobe failed, returned %d\n", ret);
                return -1;
        }
        printk("kprobe registered\n");
        return 0;
}

void cleanup_module(void)
{
        unregister_kprobe(&kp);
        printk("kprobe unregistered\n");
}
MODULE_LICENSE("GPL");

Makefile for this module :
obj-m = kprobe_example.o
all:
        make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
clean:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

When ran this program gives the output : 
Sep  7 14:05:01  kernel: [530764.156938] MY pre_handler:rdi=0xffff95ae0cbdd000, rsi=0xfffff7480af750c0, rdx=0x00000000
Sep  7 14:05:01  kernel: [530764.156942] disk_name = sdb
Sep  7 14:05:01  kernel: [530764.156945] disk_ptr = 00000000241100e9
Sep  7 14:05:01  kernel: [530764.156948] MY pre_handler: p->addr=0x000000004b03cd92, eip=ffffffff9bff6001, eflags=0x246
Sep  7 14:05:01  kernel: [530764.156952] CPU: 8 PID: 33831 Comm: sync Tainted: P        W  OE     5.15.0-47-generic #51-Ubuntu
Sep  7 14:05:01  kernel: [530764.156956] Hardware name: VMware, Inc. VMware7,1/440BX Desktop Reference Platform, BIOS VMW71.00V.17369862.B64.2012240522 12/24/2020
Sep  7 14:05:01  kernel: [530764.156960] Call Trace:
Sep  7 14:05:01  kernel: [530764.156963]  <TASK>
Sep  7 14:05:01  kernel: [530764.156966]  show_stack+0x52/0x5c
Sep  7 14:05:01  kernel: [530764.156975]  dump_stack_lvl+0x4a/0x63
Sep  7 14:05:01  kernel: [530764.156982]  dump_stack+0x10/0x16
Sep  7 14:05:01  kernel: [530764.156988]  handler_pre.cold+0x90/0xac [kprobe_example]
Sep  7 14:05:01  kernel: [530764.156996]  kprobe_ftrace_handler+0xf3/0x1c0
Sep  7 14:05:01  kernel: [530764.157001]  ? submit_bio+0x5/0x130
Sep  7 14:05:01  kernel: [530764.157009]  ? submit_bio_noacct+0x120/0x120
Sep  7 14:05:01  kernel: [530764.157015]  ftrace_ops_list_func+0x181/0x1c0
Sep  7 14:05:01  kernel: [530764.157021]  ? submit_bh_wbc+0x18d/0x1c0
Sep  7 14:05:01  kernel: [530764.157029]  ? submit_bh_wbc+0x185/0x1c0
Sep  7 14:05:01  kernel: [530764.157040]  ftrace_regs_call+0x5/0x57
Sep  7 14:05:01  kernel: [530764.157046] RIP: 0010:submit_bio+0x1/0x130
Sep  7 14:05:01  kernel: [530764.157052] Code: 0c 00 00 00 00 00 00 e9 4b ff ff ff 48 c7 44 24 08 00 00 00 00 eb c7 48 89 38 e9 70 ff ff ff e8 f5 67 7a 00 0f 1f 44 00 00 e8 <1b> 54 a9 ff 55 48 89 e5 41 54 49 89 fc 48 83 ec 18 65 48 8b 04 25
Sep  7 14:05:01  kernel: [530764.157056] RSP: 0018:ffffa6b8c124ba98 EFLAGS: 00000246 ORIG_RAX: 0000000000000000
Sep  7 14:05:01  kernel: [530764.157062] RAX: ffff95ae03e6b000 RBX: ffff95ae07206750 RCX: 0000000000000000
Sep  7 14:05:01  kernel: [530764.157065] RDX: 0000000000000000 RSI: fffff7480af750c0 RDI: ffff95ae0cbdd000
Sep  7 14:05:01  kernel: [530764.157069] RBP: ffffa6b8c124bad0 R08: 0000000000000000 R09: 0000000000003801
Sep  7 14:05:01  kernel: [530764.157072] R10: ffff95ae0cbdd000 R11: 00000000000bffff R12: ffff95ae0cbdd000
Sep  7 14:05:01  kernel: [530764.157076] R13: 0000000000000001 R14: ffffa6b8c124bdf0 R15: 0000000000003800
Sep  7 14:05:01  kernel: [530764.157091]  ? submit_bio+0x5/0x130
Sep  7 14:05:01  kernel: [530764.157097]  ? submit_bh_wbc+0x18d/0x1c0
Sep  7 14:05:01  kernel: [530764.157104]  ? submit_bio+0x5/0x130
Sep  7 14:05:01  kernel: [530764.157109]  ? submit_bh_wbc+0x18d/0x1c0
Sep  7 14:05:01  kernel: [530764.157119]  __block_write_full_page+0x227/0x4a0
Sep  7 14:05:01  kernel: [530764.157126]  ? block_invalidatepage+0x160/0x160
Sep  7 14:05:01  kernel: [530764.157135]  ? blkdev_llseek+0x70/0x70
Sep  7 14:05:01  kernel: [530764.157141]  block_write_full_page+0x6f/0xa0
Sep  7 14:05:01  kernel: [530764.157149]  blkdev_writepage+0x18/0x20
Sep  7 14:05:01  kernel: [530764.157156]  __writepage+0x1b/0x70
Sep  7 14:05:01  kernel: [530764.157164]  write_cache_pages+0x1a6/0x460
Sep  7 14:05:01  kernel: [530764.157172]  ? __set_page_dirty_no_writeback+0x50/0x50
Sep  7 14:05:01  kernel: [530764.157183]  ? __set_page_dirty_no_writeback+0x50/0x50
Sep  7 14:05:01  kernel: [530764.157191]  ? write_cache_pages+0x5/0x460
Sep  7 14:05:01  kernel: [530764.157202]  generic_writepages+0x58/0x90
Sep  7 14:05:01  kernel: [530764.157211]  ? generic_writepages+0x5/0x90
Sep  7 14:05:01  kernel: [530764.157219]  blkdev_writepages+0xe/0x20
Sep  7 14:05:01  kernel: [530764.157226]  do_writepages+0xd7/0x200
Sep  7 14:05:01  kernel: [530764.157235]  ? do_writepages+0x5/0x200
Sep  7 14:05:01  kernel: [530764.157240]  ? rcu_read_unlock_strict+0x5/0x10
Sep  7 14:05:01  kernel: [530764.157248]  ? wbc_attach_and_unlock_inode+0xc2/0x150
Sep  7 14:05:01  kernel: [530764.157257]  filemap_fdatawrite_wbc+0x89/0xe0
Sep  7 14:05:01  kernel: [530764.157262]  ? filemap_fdatawrite_wbc+0x5/0xe0
Sep  7 14:05:01  kernel: [530764.157269]  filemap_fdatawrite+0x50/0x70
Sep  7 14:05:01  kernel: [530764.157281]  sync_bdevs+0x154/0x160
Sep  7 14:05:01  kernel: [530764.157291]  ksys_sync+0x69/0xa0
Sep  7 14:05:01  kernel: [530764.157297]  __do_sys_sync+0xe/0x20
Sep  7 14:05:01  kernel: [530764.157302]  do_syscall_64+0x59/0xc0









No comments:

Post a Comment