Potential bug in the dynamic linker?
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 05 Nov 2021 17:25:19 UTC
Let me preface this by saying that I am in no way knowledgeable enough
regarding the FreeBSD dynamic linker to know whether or not this is infact
a bug or intended behaviour.
This program I'm working on, when compiled for FreeBSD, calls fdlopen(3) to
load a dynamic library from memory. This is how I'm doing that more
specifically:
// void* lib_bin, size_t lib_len
int fd = shm_open(SHM_ANON, O_RDWR, 0);
ftruncate(fd, lib_len);
void* lib_mem = mmap(NULL, lib_len, PROT_WRITE, MAP_SHARED, fd, 0);
memcpy(lib_mem, lib_bin, lib_len);
munmap(lib_mem, lib_len);
void* lib = fdlopen(fd, RTLD_LAZY);
close(fd);
Running this on FreeBSD 13 works fine, FreeBSD 14, however, spits out this
error:
Cannot fstatfs "<unknown>"
Digging around, I find, in libexec/rtld-elf/rtld.c:
/*
* but first, make sure that environment variables haven't been
* used to circumvent the noexec flag on a filesystem.
*/
if (dangerous_ld_env) {
if (fstatfs(fd, &fs) != 0) {
_rtld_error("Cannot fstatfs \"%s\"", printable_path(path));
return NULL;
}
if (fs.f_flags & MNT_NOEXEC) {
_rtld_error("Cannot execute objects on %s", fs.f_mntonname);
return NULL;
}
}
And this is the first thing that seems weird to me. Why is it calling
fstatfs(3) before checking if the file descriptor doesn't necessarily refer
to a file which resides on a physical filesystem? It doesn't say so on the
manpage, but, again, digging around, that's what the error returned by
fstatfs(3), EINVAL, supposedly means.
Secondly, why then is dangerous_ld_env even set in the first place? Well,
as of this commit (https://reviews.freebsd.org/D26352):
ld_dynamic_weak = ld_get_env_var(LD_DYNAMIC_WEAK) == NULL;
...
dangerous_ld_env = libmap_disable || libmap_override != NULL ||
ld_library_path != NULL || ld_preload != NULL ||
ld_elf_hints_path != NULL || ld_loadfltr || ld_dynamic_weak;
Should this not be
ld_dynamic_weak = ld_get_env_var(LD_DYNAMIC_WEAK) != NULL;
instead? Or is this actually intended and am I just not understanding the
point of this?