[Bug 1821677] Re: dl_open segment fault in ubuntu18.10 glibc2.28
Sunil Pandey
1821677 at bugs.launchpad.net
Fri Mar 29 05:23:23 UTC 2019
This regression caused by following patch. It is mostly arm code but
also affecting x86. If I remove this patch segfault will go away.
$ cat unsubmitted-ldso-abi-check.diff
---
elf/dl-load.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 219 insertions(+)
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1438,6 +1438,209 @@
_dl_debug_printf_c ("\t\t(%s)\n", what);
}
+#ifdef __arm__
+/* Read an unsigned leb128 value from P, store the value in VAL, return
+ P incremented past the value. We assume that a word is large enough to
+ hold any value so encoded; if it is smaller than a pointer on some target,
+ pointers should not be leb128 encoded on that target. */
+static unsigned char *
+read_uleb128 (unsigned char *p, unsigned long *val)
+{
+ unsigned int shift = 0;
+ unsigned char byte;
+ unsigned long result;
+
+ result = 0;
+ do
+ {
+ byte = *p++;
+ result |= (byte & 0x7f) << shift;
+ shift += 7;
+ }
+ while (byte & 0x80);
+
+ *val = result;
+ return p;
+}
+
+
+#define ATTR_TAG_FILE 1
+#define ABI_VFP_args 28
+#define VFP_ARGS_IN_VFP_REGS 1
+
+/* Check consistency of ABI in the ARM attributes. Search through the
+ section headers looking for the ARM attributes section, then
+ check the VFP_ARGS attribute. */
+static int
+check_arm_attributes_hfabi(int fd, ElfW(Ehdr) *ehdr, bool *is_hf)
+{
+ unsigned int i;
+ ElfW(Shdr) *shdrs;
+ int sh_size = ehdr->e_shentsize * ehdr->e_shnum;
+
+ /* Load in the section headers so we can look for the attributes
+ * section */
+ shdrs = alloca(sh_size);
+ __lseek (fd, ehdr->e_shoff, SEEK_SET);
+ if ((size_t) __libc_read (fd, (void *) shdrs, sh_size) != sh_size)
+ return -1;
+
+ for (i = 0; i < ehdr->e_shnum; i++)
+ {
+ if (SHT_ARM_ATTRIBUTES == shdrs[i].sh_type)
+ {
+ /* We've found a likely section. Load the contents and
+ * check the tags */
+ unsigned char *contents = alloca(shdrs[i].sh_size);
+ unsigned char *p = contents;
+ unsigned char * end;
+
+ __lseek (fd, shdrs[i].sh_offset, SEEK_SET);
+ if ((size_t) __libc_read (fd, (void *) contents, shdrs[i].sh_size) != shdrs[i].sh_size)
+ return -1;
+
+ /* Sanity-check the attribute section details. Make sure
+ * that it's the "aeabi" section, that's all we care
+ * about. */
+ if (*p == 'A')
+ {
+ unsigned long len = shdrs[i].sh_size - 1;
+ unsigned long namelen;
+ p++;
+
+ while (len > 0)
+ {
+ unsigned long section_len = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
+ if (section_len > len)
+ {
+ _dl_debug_printf_c (" invalid section len %lu, max remaining %lu\n", section_len, len);
+ section_len = len;
+ }
+
+ p += 4;
+ len -= section_len;
+ section_len -= 4;
+
+ if (0 != strcmp((char *)p, "aeabi"))
+ {
+ _dl_debug_printf_c (" ignoring unknown attr section %s\n", p);
+ p += section_len;
+ continue;
+ }
+ namelen = strlen((char *)p) + 1;
+ p += namelen;
+ section_len -= namelen;
+
+ /* We're in a valid section. Walk through this
+ * section looking for the tag we care about
+ * (ABI_VFP_args) */
+ while (section_len > 0)
+ {
+ unsigned long val = 0;
+ unsigned long tag;
+ unsigned long size;
+
+ end = p;
+ tag = (*p++);
+
+ size = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
+ if (size > section_len)
+ {
+ _dl_debug_printf_c (" invalid subsection length %lu, max allowed %lu\n", size, section_len);
+ size = section_len;
+ }
+ p += 4;
+
+ section_len -= size;
+ end += size;
+ if (ATTR_TAG_FILE != tag)
+ {
+ /* ignore, we don't care */
+ _dl_debug_printf_c (" ignoring unknown subsection with type %lu length %lu\n", tag, size);
+ p = end;
+ continue;
+ }
+ while (p < end)
+ {
+ p = read_uleb128 (p, &tag);
+ /* Handle the different types of tag. */
+ if ( (tag == 4) || (tag == 5) || (tag == 67) )
+ {
+ /* Special cases for string values */
+ namelen = strlen((char *)p) + 1;
+ p += namelen;
+ }
+ else
+ {
+ p = read_uleb128 (p, &val);
+ }
+ if ( (tag == ABI_VFP_args) && (val == VFP_ARGS_IN_VFP_REGS) )
+ {
+ *is_hf = 1;
+ return 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/* ARM-specific checks. If we're built using the HF ABI, then fail any
+ attempts to use the SF ABI (and vice versa). Then, check for
+ consistency of ABI in terms of passing VFP args. */
+static int
+arm_specific_checks(int fd, const char *name, ElfW(Ehdr) *ehdr)
+{
+ static int all_hf = -1; /* unset */
+ bool is_hf = false;
+ int ret;
+
+ ret = check_arm_attributes_hfabi(fd, ehdr, &is_hf);
+ if (ret != 0)
+ return ret;
+
+#ifdef __ARM_PCS_VFP
+ if (!is_hf)
+ return EINVAL;
+#else
+ if (is_hf)
+ return EINVAL;
+#endif
+
+ if (all_hf == -1)
+ {
+ if (is_hf)
+ all_hf = 1;
+ else
+ all_hf = 0;
+ }
+ else if (all_hf == 1 && !is_hf)
+ return EINVAL;
+ else if (all_hf == 0 && is_hf)
+ return EINVAL;
+ return 0;
+}
+#endif
+
+
+/* Run any architecture-specific checks that might be needed for the
+ current architecture. */
+static int
+arch_specific_checks(int fd, const char *name, ElfW(Ehdr) *ehdr)
+{
+#ifdef __arm__
+ return arm_specific_checks(fd, name, ehdr);
+#endif
+
+ return 0;
+}
+
+
/* Open a file and verify it is an ELF file for this architecture. We
ignore only ELF files for other architectures. Non-ELF files and
ELF files with different header information cause fatal errors since
@@ -1676,6 +1879,7 @@
/* Check .note.ABI-tag if present. */
for (ph = phdr; ph < &phdr[ehdr->e_phnum]; ++ph)
+ {
if (ph->p_type == PT_NOTE && ph->p_filesz >= 32 && ph->p_align >= 4)
{
ElfW(Addr) size = ph->p_filesz;
@@ -1751,6 +1955,21 @@
}
free (abi_note_malloced);
}
+ if (-1 != fd)
+ {
+ int error = arch_specific_checks(fd, name, ehdr);
+ if (EINVAL == error)
+ {
+ goto close_and_out;
+ }
+ if (0 != error)
+ {
+ errstring = N_("Unable to run arch-specific checks\n");
+ goto call_lose;
+ }
+ }
+
+ }
return fd;
}
--
You received this bug notification because you are a member of Ubuntu
Foundations Bugs, which is subscribed to glibc in Ubuntu.
https://bugs.launchpad.net/bugs/1821677
Title:
dl_open segment fault in ubuntu18.10 glibc2.28
Status in glibc package in Ubuntu:
New
Bug description:
With following testcase:
~/work/glibc$ cat foo.c
#include <dlfcn.h>
#include <stdio.h>
int main(int argc, char **argv) {
if (argc < 1) return 1;
printf("Trying to open %s\n", argv[1]);
void *liball = dlopen(argv[1], RTLD_NOW);
if(liball == NULL) {
printf("\nERROR: %s", dlerror());
return -1;
}
if(dlclose(liball)==0) {printf("\n all ok\n");}
return 0;
}
compile with
~/work/glibc$ gcc -O0 -g foo.c -ldl
then get segment fault:
~/work/glibc$ ./a.out intel64_lin/libsvml.so
Trying to open intel64_lin/libsvml.so
Segmentation fault (core dumped)
coredump as:
(gdb) bt
#0 __GI___libc_free (mem=0x7ffff7d49010) at malloc.c:3085
#1 0x00007ffff7fdb6b6 in open_verify (
name=0x555555559670 "/home/lilicui/intel64_lin/libsvml.so",
fbp=fbp at entry=0x7fffffffd530, loader=<optimized out>,
mode=mode at entry=-1879048190,
found_other_class=found_other_class at entry=0x7fffffffd51f, free_name=true,
whatcode=0, fd=3) at dl-load.c:1977
#2 0x00007ffff7fdc926 in _dl_map_object (loader=loader at entry=0x7ffff7ffe190,
name=name at entry=0x7fffffffe1b7 "/home/lilicui/intel64_lin/libsvml.so",
type=type at entry=2, trace_mode=trace_mode at entry=0,
mode=mode at entry=-1879048190, nsid=<optimized out>) at dl-load.c:2401
#3 0x00007ffff7fe79c4 in dl_open_worker (a=a at entry=0x7fffffffdaa0)
at dl-open.c:228
#4 0x00007ffff7f1b48f in __GI__dl_catch_exception (exception=<optimized out>,
operate=<optimized out>, args=<optimized out>) at dl-error-skeleton.c:196
#5 0x00007ffff7fe72c6 in _dl_open (
file=0x7fffffffe1b7 "/home/lilicui/intel64_lin/libsvml.so",
mode=-2147483646, caller_dlopen=0x5555555551cb <main+86>,
nsid=<optimized out>, argc=2, argv=0x7fffffffde08, env=0x7fffffffde20)
at dl-open.c:599
#6 0x00007ffff7faa256 in dlopen_doit (a=a at entry=0x7fffffffdcc0) at dlopen.c:66
#7 0x00007ffff7f1b48f in __GI__dl_catch_exception (
exception=exception at entry=0x7fffffffdc60, operate=<optimized out>,
--Type <RET> for more, q to quit, c to continue without paging--
args=<optimized out>) at dl-error-skeleton.c:196
#8 0x00007ffff7f1b51f in __GI__dl_catch_error (
objname=0x7ffff7fae0f0 <last_result+16>,
errstring=0x7ffff7fae0f8 <last_result+24>,
mallocedp=0x7ffff7fae0e8 <last_result+8>, operate=<optimized out>,
args=<optimized out>) at dl-error-skeleton.c:215
#9 0x00007ffff7faaa25 in _dlerror_run (
operate=operate at entry=0x7ffff7faa200 <dlopen_doit>,
args=args at entry=0x7fffffffdcc0) at dlerror.c:163
#10 0x00007ffff7faa2e6 in __dlopen (file=<optimized out>, mode=<optimized out>)
at dlopen.c:87
#11 0x00005555555551cb in main (argc=2, argv=0x7fffffffde08) at foo.c:7
intel64_lin/libsvml.so is icc19.0(aleady released) runtime library, refer to attachment.
Ubuntu version:
~/work/glibc$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 18.10
Release: 18.10
Codename: cosmic
Glibc version:
~/work/glibc$ ldd --version
ldd (Ubuntu GLIBC 2.28-0ubuntu1) 2.28
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.
It works fine with Glibc_2.28 upstream, and Glibc_2.28 on Fedora 29,
but failed with Glibc 2.28 in Ubuntu 18.10
I found ubuntu18.10 was backporting its own patches, would that affect
such testcase?
To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/glibc/+bug/1821677/+subscriptions
More information about the foundations-bugs
mailing list