kernel/kprobes: add check to avoid memory leaks
PATCH 1/1 kernel/kprobes: add check to avoid memory leaks
The register_kretprobe(struct kretprobe *rp) creates and initializes a hash list for rp->free_instances when register kretprobe every time. Then malloc memory for it.
The test case:
static struct kretprobe rp;
struct kretprobe *rps[2]={&rp, &rp};
static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
printk(KERN_DEBUG "ret_handler\n");
return 0;
}
static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
printk(KERN_DEBUG "entry_handler\n");
return 0;
}
static int __init kretprobe_init(void)
{
int ret;
rp.kp.addr = (kprobe_opcode_t *)kallsyms_lookup_name("do_fork");
rp.handler=ret_handler;
rp.entry_handler=entry_handler;
rp.maxactive = 3;
ret = register_kretprobes(rps,2);Result:
unreferenced object 0xffff8010b12ad980 (size 64):
comm "insmod", pid 17352, jiffies 4298977824 (age 63065.756s) hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 d8 84 12 fc ff 7f ff ff ................ 74 65 73 74 52 65 67 4b 72 65 74 70 72 6f 62 65 testRegKretprobe backtrace:
[<ffff8000002cd880>] create_object+0x1e0/0x3f0 [<ffff800000fa3d6c>] kmemleak_alloc+0x6c/0xf0 [<ffff8000002ac97c>] __kmalloc+0x23c/0x2e0 [<ffff8000001a6f2c>] register_kretprobe+0x12c/0x350
When call register_kretprobes(struct kretprobe **rps, int num) with the same rps(num>=2).
The first time,call INIT_HLIST_HEAD() and kmalloc() to malloc memory for the hash list,then save into rp->free_instances.
The second time,call INIT_HLIST_HEAD() and kmalloc() then create a new hash list into rp->free_instances and lost the first rp->free_instances. So add check to avoid it.
--- kernel/kprobes.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
kernel/kprobes.c +7 -1
@@ -1890,10 +1890,16 @@ EXPORT_SYMBOL_GPL(register_kretprobe);int register_kretprobes (struct kretprobe **rps,int num) { -int ret =0 , i; +int ret =0 , i, j;if (num <=0 )return -EINVAL ; + +for (i =0 ; i < num-1 ; i++) +for (j = i+1 ; j < num; j++) +if (rps[i] == rps[j]) +return -EINVAL ; +for (i =0 ; i < num; i++) { ret =register_kretprobe (rps[i]);if (ret <0 ) {
--
2.6.2
On 2017/10/25 20:29, Bixuan Cui wrote:
And test again with this patch:
insmod testRegKretprobes_004.ko
[ 163.853281] register_kretprobe failed, returned -22
insmod: can't insert 'testRegKretprobes_004.ko': Operation not permitted
Thanks,
Bixuan Cui
Quoted 83 lines
The
register_kretprobe(struct kretprobe *rp)creates and initializes a hash list forrp->free_instanceswhen register kretprobe every time. Then malloc memory for it.The test case:
static struct kretprobe rp;
struct kretprobe *rps[2]={&rp, &rp};
static intret_handler(struct kretprobe_instance *ri, struct pt_regs *regs){ printk(KERN_DEBUG "ret_handler\n"); return 0; } static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs) { printk(KERN_DEBUG "entry_handler\n"); return 0; } static int __init kretprobe_init(void) { int ret; rp.kp.addr = (kprobe_opcode_t *)kallsyms_lookup_name("do_fork"); rp.handler=ret_handler; rp.entry_handler=entry_handler; rp.maxactive = 3; ret = register_kretprobes(rps,2);Result:
unreferenced object0xffff8010b12ad980(size 64):
comm "insmod", pid 17352, jiffies 4298977824 (age 63065.756s) hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 d8 84 12 fc ff 7f ff ff ................ 74 65 73 74 52 65 67 4b 72 65 74 70 72 6f 62 65 testRegKretprobe backtrace:[<ffff8000002cd880>] create_object+0x1e0/0x3f0 [<ffff800000fa3d6c>] kmemleak_alloc+0x6c/0xf0 [<ffff8000002ac97c>] __kmalloc+0x23c/0x2e0 [<ffff8000001a6f2c>] register_kretprobe+0x12c/0x350When call
register_kretprobes(struct kretprobe **rps, int num)with the same rps(num>=2).
The first time,callINIT_HLIST_HEAD()andkmalloc()to malloc memory for the hash list,then save intorp->free_instances.
The second time,callINIT_HLIST_HEAD()andkmalloc()then create a new hash list intorp->free_instancesand lost the firstrp->free_instances. So add check to avoid it.Reported-and-tested-by kangwen <[email protected]>Signed-off-by Bixuan Cui <[email protected]>--- kernel/kprobes.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)kernel/kprobes.c +7
-2@@ -1890,10 +1890,16 @@ EXPORT_SYMBOL_GPL(register_kretprobe);int register_kretprobes (struct kretprobe **rps,int num) { -int ret =0 , i; +int ret =0 , i, j;if (num <=0 )return -EINVAL ; + +for (i =0 ; i < num-1 ; i++) +for (j = i+1 ; j < num; j++) +if (rps[i] == rps[j]) +return -EINVAL ; +for (i =0 ; i < num; i++) { ret =register_kretprobe (rps[i]);if (ret <0 ) { --2.6.2
.
Masami Hiramatsu
maintainerQuoted 56 lines · On Mon, 30 Oct 2017 09:10:57 +0800 Bixuan Cui <[email protected]> wrote:
On 2017/10/25 20:29, Bixuan Cui wrote:
And test again with this patch:insmod testRegKretprobes_004.ko
[ 163.853281] register_kretprobe failed, returned -22insmod: can't insert 'testRegKretprobes_004.ko': Operation not permitted
Thanks,
Bixuan CuiQuoted 47 lines
The
register_kretprobe(struct kretprobe *rp)creates and initializes a hash list forrp->free_instanceswhen register kretprobe every time. Then malloc memory for it.The test case:
static struct kretprobe rp;
struct kretprobe *rps[2]={&rp, &rp};
static intret_handler(struct kretprobe_instance *ri, struct pt_regs *regs){ printk(KERN_DEBUG "ret_handler\n"); return 0; } static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs) { printk(KERN_DEBUG "entry_handler\n"); return 0; } static int __init kretprobe_init(void) { int ret; rp.kp.addr = (kprobe_opcode_t *)kallsyms_lookup_name("do_fork"); rp.handler=ret_handler; rp.entry_handler=entry_handler; rp.maxactive = 3; ret = register_kretprobes(rps,2);Result:
unreferenced object0xffff8010b12ad980(size 64):
comm "insmod", pid 17352, jiffies 4298977824 (age 63065.756s) hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 d8 84 12 fc ff 7f ff ff ................ 74 65 73 74 52 65 67 4b 72 65 74 70 72 6f 62 65 testRegKretprobe backtrace:[<ffff8000002cd880>] create_object+0x1e0/0x3f0 [<ffff800000fa3d6c>] kmemleak_alloc+0x6c/0xf0 [<ffff8000002ac97c>] __kmalloc+0x23c/0x2e0 [<ffff8000001a6f2c>] register_kretprobe+0x12c/0x350When call
register_kretprobes(struct kretprobe **rps, int num)with the same rps(num>=2).
The first time,callINIT_HLIST_HEAD()andkmalloc()to malloc memory for the hash list,then save intorp->free_instances.
The second time,callINIT_HLIST_HEAD()andkmalloc()then create a new hash list intorp->free_instancesand lost the firstrp->free_instances. So add check to avoid it.
I don't like this kind of check, since this is obviously caller's bug. Why doesn't each caller check this?
Thank you,
Quoted 38 lines
Quoted 36 lines
Reported-and-tested-by kangwen <[email protected]>Signed-off-by Bixuan Cui <[email protected]>--- kernel/kprobes.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)kernel/kprobes.c +7
-2@@ -1890,10 +1890,16 @@ EXPORT_SYMBOL_GPL(register_kretprobe);int register_kretprobes (struct kretprobe **rps,int num) { -int ret =0 , i; +int ret =0 , i, j;if (num <=0 )return -EINVAL ; + +for (i =0 ; i < num-1 ; i++) +for (j = i+1 ; j < num; j++) +if (rps[i] == rps[j]) +return -EINVAL ; +for (i =0 ; i < num; i++) { ret =register_kretprobe (rps[i]);if (ret <0 ) { --2.6.2
.
Signature · 1 line
Masami Hiramatsu <[email protected]>
Quoted 2 lines · Masami Hiramatsu
I don't like this kind of check, since this is obviously caller's bug. Why doesn't each caller check this?
Thank you for your answer.
Thanks,
Bixuan Cui