[PATCH 3.2 042/164] fs/binfmt_elf.c: fix bug in loading of PIE binaries

2015-08-01 Thread Ben Hutchings
3.2.70-rc1 review patch.  If anyone has any objections, please let me know.

--

From: Michael Davidson 

commit a87938b2e246b81b4fb713edb371a9fa3c5c3c86 upstream.

With CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE enabled, and a normal top-down
address allocation strategy, load_elf_binary() will attempt to map a PIE
binary into an address range immediately below mm->mmap_base.

Unfortunately, load_elf_ binary() does not take account of the need to
allocate sufficient space for the entire binary which means that, while
the first PT_LOAD segment is mapped below mm->mmap_base, the subsequent
PT_LOAD segment(s) end up being mapped above mm->mmap_base into the are
that is supposed to be the "gap" between the stack and the binary.

Since the size of the "gap" on x86_64 is only guaranteed to be 128MB this
means that binaries with large data segments > 128MB can end up mapping
part of their data segment over their stack resulting in corruption of the
stack (and the data segment once the binary starts to run).

Any PIE binary with a data segment > 128MB is vulnerable to this although
address randomization means that the actual gap between the stack and the
end of the binary is normally greater than 128MB.  The larger the data
segment of the binary the higher the probability of failure.

Fix this by calculating the total size of the binary in the same way as
load_elf_interp().

Signed-off-by: Michael Davidson 
Cc: Alexander Viro 
Cc: Jiri Kosina 
Cc: Kees Cook 
Signed-off-by: Andrew Morton 
Signed-off-by: Linus Torvalds 
Signed-off-by: Ben Hutchings 
---
 fs/binfmt_elf.c | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -746,6 +746,7 @@ static int load_elf_binary(struct linux_
i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
int elf_prot = 0, elf_flags;
unsigned long k, vaddr;
+   unsigned long total_size = 0;
 
if (elf_ppnt->p_type != PT_LOAD)
continue;
@@ -809,10 +810,16 @@ static int load_elf_binary(struct linux_
 #else
load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
 #endif
+   total_size = total_mapping_size(elf_phdata,
+   loc->elf_ex.e_phnum);
+   if (!total_size) {
+   error = -EINVAL;
+   goto out_free_dentry;
+   }
}
 
error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
-   elf_prot, elf_flags, 0);
+   elf_prot, elf_flags, total_size);
if (BAD_ADDR(error)) {
send_sig(SIGKILL, current, 0);
retval = IS_ERR((void *)error) ?

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 3.2 042/164] fs/binfmt_elf.c: fix bug in loading of PIE binaries

2015-08-01 Thread Ben Hutchings
3.2.70-rc1 review patch.  If anyone has any objections, please let me know.

--

From: Michael Davidson m...@google.com

commit a87938b2e246b81b4fb713edb371a9fa3c5c3c86 upstream.

With CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE enabled, and a normal top-down
address allocation strategy, load_elf_binary() will attempt to map a PIE
binary into an address range immediately below mm-mmap_base.

Unfortunately, load_elf_ binary() does not take account of the need to
allocate sufficient space for the entire binary which means that, while
the first PT_LOAD segment is mapped below mm-mmap_base, the subsequent
PT_LOAD segment(s) end up being mapped above mm-mmap_base into the are
that is supposed to be the gap between the stack and the binary.

Since the size of the gap on x86_64 is only guaranteed to be 128MB this
means that binaries with large data segments  128MB can end up mapping
part of their data segment over their stack resulting in corruption of the
stack (and the data segment once the binary starts to run).

Any PIE binary with a data segment  128MB is vulnerable to this although
address randomization means that the actual gap between the stack and the
end of the binary is normally greater than 128MB.  The larger the data
segment of the binary the higher the probability of failure.

Fix this by calculating the total size of the binary in the same way as
load_elf_interp().

Signed-off-by: Michael Davidson m...@google.com
Cc: Alexander Viro v...@zeniv.linux.org.uk
Cc: Jiri Kosina jkos...@suse.cz
Cc: Kees Cook keesc...@chromium.org
Signed-off-by: Andrew Morton a...@linux-foundation.org
Signed-off-by: Linus Torvalds torva...@linux-foundation.org
Signed-off-by: Ben Hutchings b...@decadent.org.uk
---
 fs/binfmt_elf.c | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -746,6 +746,7 @@ static int load_elf_binary(struct linux_
i  loc-elf_ex.e_phnum; i++, elf_ppnt++) {
int elf_prot = 0, elf_flags;
unsigned long k, vaddr;
+   unsigned long total_size = 0;
 
if (elf_ppnt-p_type != PT_LOAD)
continue;
@@ -809,10 +810,16 @@ static int load_elf_binary(struct linux_
 #else
load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
 #endif
+   total_size = total_mapping_size(elf_phdata,
+   loc-elf_ex.e_phnum);
+   if (!total_size) {
+   error = -EINVAL;
+   goto out_free_dentry;
+   }
}
 
error = elf_map(bprm-file, load_bias + vaddr, elf_ppnt,
-   elf_prot, elf_flags, 0);
+   elf_prot, elf_flags, total_size);
if (BAD_ADDR(error)) {
send_sig(SIGKILL, current, 0);
retval = IS_ERR((void *)error) ?

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/