x86: Fix memory leak of init_vdso_vars()
PATCH 1/1 x86: Fix memory leak of init_vdso_vars()
Fix memory leak of init_vdso_vars().
--- arch/x86/vdso/vma.c | 14 ++++++++++---- 1 files changed, 10 insertions(+), 4 deletions(-)
arch/x86/vdso/vma.c +10 -4
@@ -44,19 +44,19 @@ static int __init init_vdso_vars(void) vdso_size = npages <<PAGE_SHIFT ; vdso_pages =kmalloc (sizeof (struct page *) * npages,GFP_KERNEL );if (!vdso_pages) - goto oom; + goto oom1;for (i =0 ; i < npages; i++) {struct page *p; p =alloc_page (GFP_KERNEL );if (!p) - goto oom; + goto oom2; vdso_pages[i] = p;copy_page (page_address (p), vdso_start + i*PAGE_SIZE ); } vbase =vmap (vdso_pages, npages,0 ,PAGE_KERNEL );if (!vbase) - goto oom; + goto oom2;if (memcmp (vbase,"\177ELF" ,4 )) {printk ("VDSO: I'm broken; not ELF\n" );
@@ -70,7 +70,13 @@ static int __init init_vdso_vars(void)vunmap (vbase);return 0 ; - oom: +oom2: + i--; +for (; i >=0 ; i--) +__free_page (vdso_pages[i]); +__free_page (vdso_pages); + +oom1:printk ("Cannot allocate vdso\n" ); vdso_enabled =0 ;return -ENOMEM ;
Signature · 1 line
1.7.4.1
Quoted 3 lines · wzt
Fix memory leak of
init_vdso_vars().Signed-off-by Zhitong Wang <[email protected]>
The patch looks correct but it could be cleaned up a bit IMO. See bellow.
Quoted 10 lines
--- arch/x86/vdso/vma.c | 14 ++++++++++---- 1 files changed, 10 insertions(+), 4 deletions(-)arch/x86/vdso/vma.c +0
-0
arch/x86/vdso/vma.c static int __init init_vdso_vars(void) · line 47
Quoted 5 lines
arch/x86/vdso/vma.c +1
-1@@ -44,19 +44,19 @@ static int __init init_vdso_vars(void) vdso_size = npages <<PAGE_SHIFT ; vdso_pages =kmalloc (sizeof (struct page *) * npages,GFP_KERNEL );if (!vdso_pages) - goto oom; + goto oom1;
I wouldn't rename the label. It just makes the patch bigger for no good reason. The new naming is not anyhow useful.
arch/x86/vdso/vma.c static int __init init_vdso_vars(void) · line 52
Quoted 6 lines
arch/x86/vdso/vma.c +1
-1for (i =0 ; i < npages; i++) {struct page *p; p =alloc_page (GFP_KERNEL );if (!p) - goto oom; + goto oom2;
Waht about goto oom_free_pages instead?
Quoted 12 lines
arch/x86/vdso/vma.c +1
-1vdso_pages[i] = p;copy_page (page_address (p), vdso_start + i*PAGE_SIZE ); } vbase =vmap (vdso_pages, npages,0 ,PAGE_KERNEL );if (!vbase) - goto oom; + goto oom2;if (memcmp (vbase,"\177ELF" ,4 )) {printk ("VDSO: I'm broken; not ELF\n" );
arch/x86/vdso/vma.c static int __init init_vdso_vars(void) · line 76
Quoted 8 lines
arch/x86/vdso/vma.c +4
-1@@ -70,7 +70,13 @@ static int __init init_vdso_vars(void)vunmap (vbase);return 0 ; - oom: +oom2: + i--; +for (; i >=0 ; i--) +__free_page (vdso_pages[i]);
Why not
for (; i > 0; i--) __free_page(vdso_pages[i-1]);
Quoted 6 lines
arch/x86/vdso/vma.c +3
-0+__free_page (vdso_pages); + +oom1:printk ("Cannot allocate vdso\n" ); vdso_enabled =0 ;return -ENOMEM ;
Signature · 6 lines
Michal Hocko SUSE Labs SUSE LINUX s.r.o. Lihovarska 1060/12 190 00 Praha 9 Czech Republic
Quoted 6 lines · Michal Hocko
Quoted 3 lines · wzt
Fix memory leak of
init_vdso_vars().Signed-off-by Zhitong Wang<[email protected]>The patch looks correct but it could be cleaned up a bit IMO. See bellow.
When you run out of memory at early system boot (this is early system boot only) the system is toast anyways. There's no way to recover.
I would just add a few GFP_PANICs and then drop the error paths.
-Andi
maybe, we can just panic() when kmalloc failed instead of add a new GFP_PANIC.
new patch will coming soon.
Quoted 9 lines · Andi Kleen
When you run out of memory at early system boot (this is early system boot only) the system is toast anyways. There's no way to recover.
I would just add a few
GFP_PANICsand then drop the error paths.-Andi
Quoted 11 lines · wzt wzt
maybe, we can just
panic()when kmalloc failed instead of add a newGFP_PANIC.new patch will coming soon.
Quoted 5 lines · Andi Kleen
When you run out of memory at early system boot (this is early system boot only) the system is toast anyways. There's no way to recover.
I would just add a few
GFP_PANICsand then drop the error paths.
That's a very sloppy way of doing it: should anyone ever want to reuse this function *not* in an init path (which is a future possibility with the vdso) it will have a nasty panic() embedded in it ...
Thanks,
Ingo
PATCH 1/1 x86: Fix memory leak of init_vdso_vars()
In reply to wztFrom: Zhitong Wang <[email protected]>
If init_vdso_vars ran out of memory (not very likely), then it would leak a few pages as well.
Also rename init_vdso_vars to just init_vdso, since initializing vvars is just about the only thing this function doesn't do.
--- arch/x86/vdso/vma.c | 13 +++++++++---- 1 files changed, 9 insertions(+), 4 deletions(-)
arch/x86/vdso/vma.c +9 -4
@@ -54,7 +54,7 @@ found:apply_alternatives (alt_data, alt_data + alt_sec->sh_size); } -static int __init init_vdso_vars (void ) +static int __init init_vdso (void ) {int npages = (vdso_end - vdso_start +PAGE_SIZE -1 ) /PAGE_SIZE ;int i;
@@ -69,19 +69,24 @@ static int __init init_vdso_vars(void)struct page *p; p =alloc_page (GFP_KERNEL );if (!p) - goto oom; + goto oom_free; vdso_pages[i] = p;copy_page (page_address (p), vdso_start + i*PAGE_SIZE ); }return 0 ; - oom: +oom_free: +for (i--; i >=0 ; i--) +__free_page (vdso_pages[i]); +__free_page (vdso_pages); + +oom:printk ("Cannot allocate vdso\n" ); vdso_enabled =0 ;return -ENOMEM ; } -subsys_initcall (init_vdso_vars); +subsys_initcall (init_vdso);struct linux_binprm ;
Signature · 1 line
1.7.6
Quoted 7 lines · Andy Lutomirski
From: Zhitong Wang <[email protected]>
If
init_vdso_varsran out of memory (not very likely), then it would leak a few pages as well.Also rename
init_vdso_varsto justinit_vdso, since initializing vvars is just about the only thing this function doesn't do.
Just add a GFP_PANIC, there's no way to recover from this. Your system will not work without a vdso.
-Andi
Quoted 11 lines · Andi Kleen
Quoted 7 lines · Andy Lutomirski
From: Zhitong Wang <[email protected]>
If
init_vdso_varsran out of memory (not very likely), then it would leak a few pages as well.Also rename
init_vdso_varsto justinit_vdso, since initializing vvars is just about the only thing this function doesn't do.Just add a
GFP_PANIC, there's no way to recover from this. Your system will not work without a vdso.
Ingo objected to this before, although I'm not convinved. Calling init_vdso_vars more than once will cause major problems (like double-patching of alternatives). If there's too little memory for it to work, then presumably there's also too little memory to start init.
(Also, I bet that no one ever audited whether the ELF loader works
right if the vDSO failed to load.)
Ingo?
--Andy
Quoted 3 lines
-Andi
Quoted 19 lines · Andrew Lutomirski
Quoted 11 lines · Andi Kleen
Quoted 7 lines · Andy Lutomirski
From: Zhitong Wang <[email protected]>
If
init_vdso_varsran out of memory (not very likely), then it would leak a few pages as well.Also rename
init_vdso_varsto justinit_vdso, since initializing vvars is just about the only thing this function doesn't do.Just add a
GFP_PANIC, there's no way to recover from this. Your system will not work without a vdso.Ingo objected to this before, although I'm not convinved. Calling
init_vdso_varsmore than once will cause major problems (like double-patching of alternatives). If there's too little memory for it to work, then presumably there's also too little memory to start init.
Quoted 4 lines
(Also, I bet that no one ever audited whether the ELF loader works
right if the vDSO failed to load.)Ingo?
This assumes that the system actually needs an ELF loader - if a static binary is booted via a init= boot parameter it might not be needed.
Memory failure injection code will also cause this to panic early during bootup spuriously.
Really, we should cleanly tear down what we built up and fail cleanly as well, no need to be sloppy since we already have the patch. That some other code down the boot chain might be sloppy is no excuse to be sloppy here.
Would be nice to stick a WARN_ON() into the oom branch though, as it's clearly an anomalous condition.
(btw., there's no GFP_PANIC, we never had any such flag for the page allocator.)
Thanks,
Ingo
Quoted 22 lines · Ingo Molnar
Quoted 19 lines · Andrew Lutomirski
Quoted 11 lines · Andi Kleen
Quoted 7 lines · Andy Lutomirski
From: Zhitong Wang <[email protected]>
If
init_vdso_varsran out of memory (not very likely), then it would leak a few pages as well.Also rename
init_vdso_varsto justinit_vdso, since initializing vvars is just about the only thing this function doesn't do.Just add a
GFP_PANIC, there's no way to recover from this. Your system will not work without a vdso.Ingo objected to this before, although I'm not convinved. Calling
init_vdso_varsmore than once will cause major problems (like double-patching of alternatives). If there's too little memory for it to work, then presumably there's also too little memory to start init.
Quoted 8 lines
Quoted 4 lines
(Also, I bet that no one ever audited whether the ELF loader works right if the vDSO failed to load.)
Ingo?
This assumes that the system actually needs an ELF loader - if a static binary is booted via a init= boot parameter it might not be needed.
I actually meant the kernel's loaded. But I just looked and it appears correct.
But I think this whole thing is silly, because I can't see any good reason that the vdso needs to allocate memory in the first place. I'll send a patch.
--Andy
Quoted 32 lines · Andrew Lutomirski
Quoted 22 lines · Ingo Molnar
Quoted 19 lines · Andrew Lutomirski
Quoted 11 lines · Andi Kleen
Quoted 7 lines · Andy Lutomirski
From: Zhitong Wang <[email protected]>
If
init_vdso_varsran out of memory (not very likely), then it would leak a few pages as well.Also rename
init_vdso_varsto justinit_vdso, since initializing vvars is just about the only thing this function doesn't do.Just add a
GFP_PANIC, there's no way to recover from this. Your system will not work without a vdso.Ingo objected to this before, although I'm not convinved. Calling
init_vdso_varsmore than once will cause major problems (like double-patching of alternatives). If there's too little memory for it to work, then presumably there's also too little memory to start init.Quoted 8 lines
Quoted 4 lines
(Also, I bet that no one ever audited whether the ELF loader works right if the vDSO failed to load.)
Ingo?
This assumes that the system actually needs an ELF loader - if a static binary is booted via a init= boot parameter it might not be needed.
Quoted 5 lines
I actually meant the kernel's loaded. But I just looked and it appears correct.
But I think this whole thing is silly, because I can't see any good reason that the vdso needs to allocate memory in the first place. I'll send a patch.
that's the perfect solution indeed :)
Thanks,
Ingo
PATCH 1/1 x86-64: Do not allocate memory for the vDSO
In reply to Andrew LutomirskiWe can map the vDSO straight from kernel data, saving a few page allocations. As an added bonus, the deleted code contained a memory leak.
--- arch/x86/vdso/vdso.S | 15 +++++++++++++-- arch/x86/vdso/vma.c | 25 ++++++------------------- 2 files changed, 19 insertions(+), 21 deletions(-)
arch/x86/vdso/vdso.S +13 -2
@@ -1,10 +1,21 @@ +#include <asm/page_types.h> +#include <linux/linkage.h> #include <linux/init.h> -__INITDATA +__PAGE_ALIGNED_DATA .globl vdso_start, vdso_end + .align PAGE_SIZE vdso_start: .incbin "arch/x86/vdso/vdso.so" vdso_end: -__FINIT +.previous + + .globl vdso_pages + .bss + .align 8 + .type vdso_pages, @object +vdso_pages: + .zero (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE * 8 + .size vdso_pages, .-vdso_pages
arch/x86/vdso/vma.c +6 -19
@@ -14,13 +14,14 @@#include <asm/vgtod.h> #include <asm/proto.h> #include <asm/vdso.h> +#include <asm/page.h> unsigned int __read_mostly vdso_enabled =1 ;extern char vdso_start[], vdso_end[];extern unsigned short vdso_sync_cpuid; -static struct page **vdso_pages; +extern struct page *vdso_pages[];static unsigned vdso_size;static void patch_vdso (void *vdso,size_t len)
@@ -51,7 +52,7 @@ found:apply_alternatives (alt_data, alt_data + alt_sec->sh_size); } -static int __init init_vdso_vars (void ) +static int __init init_vdso (void ) {int npages = (vdso_end - vdso_start +PAGE_SIZE -1 ) /PAGE_SIZE ;int i;
@@ -59,26 +60,12 @@ static int __init init_vdso_vars(void)patch_vdso (vdso_start, vdso_end - vdso_start); vdso_size = npages <<PAGE_SHIFT ; - vdso_pages =kmalloc (sizeof (struct page *) * npages,GFP_KERNEL ); -if (!vdso_pages) - goto oom; -for (i =0 ; i < npages; i++) { -struct page *p; - p =alloc_page (GFP_KERNEL ); -if (!p) - goto oom; - vdso_pages[i] = p; -copy_page (page_address (p), vdso_start + i*PAGE_SIZE ); - } +for (i =0 ; i < npages; i++) + vdso_pages[i] =virt_to_page (vdso_start + i*PAGE_SIZE );return 0 ; - - oom: -printk ("Cannot allocate vdso\n" ); - vdso_enabled =0 ; -return -ENOMEM ; } -subsys_initcall (init_vdso_vars); +subsys_initcall (init_vdso);struct linux_binprm ;
Signature · 1 line
1.7.6
[tip:x86/vdso] x86-64, vdso: Do not allocate memory for the vDSO
Commit-ID: aafade242ff24fac3aabf61c7861dfa44a3c2445 Gitweb: http://git.kernel.org/tip/aafade242ff24fac3aabf61c7861dfa44a3c2445 Author: Andy Lutomirski <[email protected]> AuthorDate: Thu, 21 Jul 2011 15:47:10 -0400 Committer: H. Peter Anvin <[email protected]> CommitDate: Thu, 21 Jul 2011 13:41:53 -0700
x86-64, vdso: Do not allocate memory for the vDSO
We can map the vDSO straight from kernel data, saving a few page allocations. As an added bonus, the deleted code contained a memory leak.
--- arch/x86/vdso/vdso.S | 15 +++++++++++++-- arch/x86/vdso/vma.c | 25 ++++++------------------- 2 files changed, 19 insertions(+), 21 deletions(-)
arch/x86/vdso/vdso.S +13 -2
@@ -1,10 +1,21 @@ +#include <asm/page_types.h> +#include <linux/linkage.h> #include <linux/init.h> -__INITDATA +__PAGE_ALIGNED_DATA .globl vdso_start, vdso_end + .align PAGE_SIZE vdso_start: .incbin "arch/x86/vdso/vdso.so" vdso_end: -__FINIT +.previous + + .globl vdso_pages + .bss + .align 8 + .type vdso_pages, @object +vdso_pages: + .zero (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE * 8 + .size vdso_pages, .-vdso_pages
arch/x86/vdso/vma.c +6 -19
@@ -14,13 +14,14 @@#include <asm/vgtod.h> #include <asm/proto.h> #include <asm/vdso.h> +#include <asm/page.h> unsigned int __read_mostly vdso_enabled =1 ;extern char vdso_start[], vdso_end[];extern unsigned short vdso_sync_cpuid; -static struct page **vdso_pages; +extern struct page *vdso_pages[];static unsigned vdso_size;static void __init patch_vdso (void *vdso,size_t len)
@@ -54,7 +55,7 @@ found:apply_alternatives (alt_data, alt_data + alt_sec->sh_size); } -static int __init init_vdso_vars (void ) +static int __init init_vdso (void ) {int npages = (vdso_end - vdso_start +PAGE_SIZE -1 ) /PAGE_SIZE ;int i;
@@ -62,26 +63,12 @@ static int __init init_vdso_vars(void)patch_vdso (vdso_start, vdso_end - vdso_start); vdso_size = npages <<PAGE_SHIFT ; - vdso_pages =kmalloc (sizeof (struct page *) * npages,GFP_KERNEL ); -if (!vdso_pages) - goto oom; -for (i =0 ; i < npages; i++) { -struct page *p; - p =alloc_page (GFP_KERNEL ); -if (!p) - goto oom; - vdso_pages[i] = p; -copy_page (page_address (p), vdso_start + i*PAGE_SIZE ); - } +for (i =0 ; i < npages; i++) + vdso_pages[i] =virt_to_page (vdso_start + i*PAGE_SIZE );return 0 ; - - oom: -printk ("Cannot allocate vdso\n" ); - vdso_enabled =0 ; -return -ENOMEM ; } -subsys_initcall (init_vdso_vars); +subsys_initcall (init_vdso);struct linux_binprm ;