Subject: MIPS shared linker running at virtual address 0!
To: None <tech-kern@netbsd.org>
From: Simon Burge <simonb@wasabisystems.com>
List: tech-kern
Date: 07/29/2005 19:38:05
--mYCpIKhGyMATD0i+
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Folks,
On the MIPS ports we have a problem when the ELF_INTERP_NON_RELOCATABLE
option is enabled (which is enabled by COMPAT_16 option). Now that the
shared linker (ld.elf_so) is relocatable and linked at virtual address
0 instead of the the funny magic address of 0x5ffe0000, if we have
ELF_INTERP_NON_RELOCATABLE enabled then it will actually run at virtual
address 0.
Here's the output of pmap(6) for a kernel with COMPAT_16 enabled:
rhone 1> pmap -p $$
00000000 56K read/exec /libexec/ld.elf_so
0000E000 252K [ anon ]
0004D000 4K read/write /libexec/ld.elf_so
0004E000 4K read/write [ anon ]
00400000 520K read/exec /bin/tcsh
10000000 16K read/write /bin/tcsh
10004000 840K read/write [ anon ]
7DE00000 1036K read/exec /lib/libc.so.12.130
7DF03000 256K /lib/libc.so.12.130
7DF43000 28K read/write /lib/libc.so.12.130
7DF4A000 60K read/write [ anon ]
7DF60000 28K read/exec /lib/libcrypt.so.0.2
7DF67000 252K /lib/libcrypt.so.0.2
7DFA6000 4K read/write /lib/libcrypt.so.0.2
7DFA7000 12K read/write [ anon ]
7DFB0000 12K read/exec /lib/libtermcap.so.0.6
7DFB3000 252K /lib/libtermcap.so.0.6
7DFF2000 4K read/write /lib/libtermcap.so.0.6
7DFF6000 32K read/write [ anon ]
7DFFE000 4K read/exec [ uvm_aobj ]
7DFFF000 30720K [ stack ]
7FDFF000 1924K read/write [ stack ]
7FFE0000 124K read/write [ stack ]
total 4708K
This is bad because it means that a NULL pointer deref will hit a mapped
address and won't segfault!
The rather ugly patched attached checks to see if the interpreter (ie,
shared linker) is linked at a low address, and if so tells later code
to load it at a normal address chosen at the top of the address space
instead of the address of where it was linked at. The shared linkers
that the ELF_INTERP_NON_RELOCATABLE option is used for are all linked
at the magic MIPS address of 0x5ffe0000, and so aren't effected by this
patch.
After this patch, and still with COMPAT_16 enabled, we now see:
rhone 1> pmap -p $$
00400000 520K read/exec /bin/tcsh
10000000 16K read/write /bin/tcsh
10004000 840K read/write [ anon ]
7DDB0000 1036K read/exec /lib/libc.so.12.130
7DEB3000 256K /lib/libc.so.12.130
7DEF3000 28K read/write /lib/libc.so.12.130
7DEFA000 60K read/write [ anon ]
7DF10000 28K read/exec /lib/libcrypt.so.0.2
7DF17000 252K /lib/libcrypt.so.0.2
7DF56000 4K read/write /lib/libcrypt.so.0.2
7DF57000 12K read/write [ anon ]
7DF60000 12K read/exec /lib/libtermcap.so.0.6
7DF63000 252K /lib/libtermcap.so.0.6
7DFA2000 4K read/write /lib/libtermcap.so.0.6
7DFA7000 32K read/write [ anon ]
7DFAF000 4K read/exec [ uvm_aobj ]
7DFB0000 56K read/exec /libexec/ld.elf_so
7DFBE000 252K [ anon ]
7DFFD000 4K read/write /libexec/ld.elf_so
7DFFE000 4K read/write [ anon ]
7DFFF000 30720K [ stack ]
7FDFF000 1924K read/write [ stack ]
7FFE0000 124K read/write [ stack ]
total 4708K
Notice how virtual address 0 is now unmapped, and the shared linker is
high up in the user address space.
No other ports use ELF_INTERP_NON_RELOCATABLE, so this doesn't break
anything else, but this patch is in MI code so I'm posting here for any
comments before committing. I'd like to commit this and get it pulled
up to the 3.0 branch. I'll ignore comments along the lines of "eww,
that's ugly" if no better fix is proposed :-)
Cheers,
Simon.
--
Simon Burge <simonb@wasabisystems.com>
NetBSD Development, Support and Service: http://www.wasabisystems.com/
--mYCpIKhGyMATD0i+
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="exec_elf32.diff"
Index: sys/kern/exec_elf32.c
===================================================================
RCS file: /cvsroot/src/sys/kern/exec_elf32.c,v
retrieving revision 1.106
diff -d -p -u -r1.106 exec_elf32.c
--- sys/kern/exec_elf32.c 17 Jul 2005 23:53:57 -0000 1.106
+++ sys/kern/exec_elf32.c 28 Jul 2005 16:01:39 -0000
@@ -405,6 +405,18 @@ elf_load_file(struct proc *p, struct exe
if ((error = exec_read_from(p, vp, eh.e_phoff, ph, phsize)) != 0)
goto bad;
+#ifdef ELF_INTERP_NON_RELOCATABLE
+ /*
+ * Evil hack: Only MIPS should be non-relocatable, and the
+ * psections should have a high address (typically 0x5ffe0000).
+ * If it's now relocatable, it should be linked at 0 and the
+ * psections should have zeros in the upper part of the address.
+ * Otherwise, force the load at the linked address.
+ */
+ if (*last == ELF_LINK_ADDR && (ph->p_vaddr & 0xffff0000) == 0)
+ *last = ELFDEFNNAME(NO_ADDR);
+#endif
+
/*
* If no position to load the interpreter was set by a probe
* function, pick the same address that a non-fixed mmap(0, ..)
--mYCpIKhGyMATD0i+--