Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 21 Sep 2019 19:49:01 +0300
From:      Konstantin Belousov <kostikbel@gmail.com>
To:        Ryan Stone <rysto32@gmail.com>
Cc:        FreeBSD Current <freebsd-current@freebsd.org>
Subject:   Re: Direct exec of /usr/bin/ld fails with "mmap of entire address space failed: Cannot allocate memory"
Message-ID:  <20190921164901.GO2559@kib.kiev.ua>
In-Reply-To: <CAFMmRNxzdbYNFdtqN8BDCHehiFYRMqrwuEVMZceZdZY7mese2Q@mail.gmail.com>
References:  <CAFMmRNxzdbYNFdtqN8BDCHehiFYRMqrwuEVMZceZdZY7mese2Q@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Sat, Sep 21, 2019 at 12:19:19PM -0400, Ryan Stone wrote:
> If I try direct exec ld via rtld, I get the following failure:
> 
> # /libexec/ld-elf.so.1 /usr/bin/ld
> ld-elf.so.1: /usr/bin/ld: mmap of entire address space failed: Cannot
> allocate memory
> 
> Is there some sysctl limit I need to bump up to get around this?  I
> presume that the binary is just too large given that I can direct exec
> smaller binaries like /bin/cat.
No, this is not due to a limit, rather it is some unfortunate consequence
of layout and default choices.

Non-PIE binaries must be loaded at the fixed address. PIE binaries,
which rtld pretends to be, are not. The loading address for PIE in
non-ASLR mode is fixed per-arch, and it is not too far away from the
default linking address of non-PIE.

As result, it is possible for sufficiently large non-PIE binary to
extend into already allocated range from rtld. We use MAP_FIXED |
MAP_EXCL to avoid destroying existing mappings in linker, which fails
when pre-allocating the space for whole future mappings of the object.

I believe this is what happens in your case.
I think that we finally should make the fixed PIE loading address a tunable.
(patch was not tested)

diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
index 305e49c2e22..4678d7465b8 100644
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -135,6 +135,11 @@ SYSCTL_INT(_kern_elf32, OID_AUTO, read_exec, CTLFLAG_RW, &i386_read_exec, 0,
     "enable execution from readable segments");
 #endif
 
+static u_long __elfN(pie_base) = ET_DYN_LOAD_ADDR;
+SYSCTL_ULONG(__CONCAT(_kern_elf, __ELF_WORD_SIZE), OID_AUTO, pie_base,
+    CTLFLAG_RWTUN, &__elfN(pie_base), 0,
+    "PIE load base without randomization");
+
 SYSCTL_NODE(__CONCAT(_kern_elf, __ELF_WORD_SIZE), OID_AUTO, aslr, CTLFLAG_RW, 0,
     "");
 #define	ASLR_NODE_OID	__CONCAT(__CONCAT(_kern_elf, __ELF_WORD_SIZE), _aslr)
@@ -1146,13 +1151,13 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
 		if (baddr == 0) {
 			if ((sv->sv_flags & SV_ASLR) == 0 ||
 			    (fctl0 & NT_FREEBSD_FCTL_ASLR_DISABLE) != 0)
-				et_dyn_addr = ET_DYN_LOAD_ADDR;
+				et_dyn_addr = __elfN(pie_base);
 			else if ((__elfN(pie_aslr_enabled) &&
 			    (imgp->proc->p_flag2 & P2_ASLR_DISABLE) == 0) ||
 			    (imgp->proc->p_flag2 & P2_ASLR_ENABLE) != 0)
 				et_dyn_addr = ET_DYN_ADDR_RAND;
 			else
-				et_dyn_addr = ET_DYN_LOAD_ADDR;
+				et_dyn_addr = __elfN(pie_base);
 		}
 	}
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20190921164901.GO2559>