diff options
Diffstat (limited to 'trunk/src/dso.c')
-rw-r--r-- | trunk/src/dso.c | 122 |
1 files changed, 94 insertions, 28 deletions
diff --git a/trunk/src/dso.c b/trunk/src/dso.c index 86e9534..2325427 100644 --- a/trunk/src/dso.c +++ b/trunk/src/dso.c @@ -117,6 +117,8 @@ read_dynamic (DSO *dso) dso->info_DT_MIPS_GOTSYM = dyn.d_un.d_val; else if (dyn.d_tag == DT_MIPS_SYMTABNO) dso->info_DT_MIPS_SYMTABNO = dyn.d_un.d_val; + else if (dyn.d_tag == DT_MIPS_PLTGOT) + dso->info_DT_MIPS_PLTGOT = dyn.d_un.d_val; } } if (ndx < maxndx) @@ -223,6 +225,15 @@ check_dso (DSO *dso) || (dso->shdr[i].sh_type != SHT_NOBITS && dso->shdr[i].sh_size != 0)) last = i; } + +#ifndef DSO_READONLY + if (dso_has_bad_textrel (dso)) + { + error (0, 0, "%s has text relocations", dso->filename); + return 1; + } +#endif + return 0; } @@ -231,7 +242,7 @@ open_dso (const char *name) { int fd; - fd = open (name, O_RDONLY); + fd = wrap_open (name, O_RDONLY); if (fd == -1) { error (0, errno, "cannot open \"%s\"", name); @@ -273,8 +284,10 @@ fdopen_dso (int fd, const char *name) GElf_Addr last_off; int i, j, k, last, *sections, *invsections; DSO *dso = NULL; +#ifndef DSO_READONLY struct PLArch *plarch; extern struct PLArch __start_pl_arch[], __stop_pl_arch[]; +#endif /* DSO_READONLY */ elf = elf_begin (fd, ELF_C_READ, NULL); if (elf == NULL) @@ -402,6 +415,7 @@ fdopen_dso (int fd, const char *name) invsections[sections[i]] = i; } +#ifndef DSO_READONLY if (j) { dso->move = init_section_move (dso); @@ -410,6 +424,7 @@ fdopen_dso (int fd, const char *name) memcpy (dso->move->old_to_new, invsections, dso->ehdr.e_shnum * sizeof (int)); memcpy (dso->move->new_to_old, sections, dso->ehdr.e_shnum * sizeof (int)); } +#endif /* DSO_READONLY */ last_off = 0; for (i = 1; i < ehdr.e_shnum; ++i) @@ -468,6 +483,7 @@ fdopen_dso (int fd, const char *name) } dso->ehdr.e_shstrndx = invsections[dso->ehdr.e_shstrndx]; +#ifndef DSO_READONLY for (plarch = __start_pl_arch; plarch < __stop_pl_arch; plarch++) if (plarch->class == ehdr.e_ident[EI_CLASS] && (plarch->machine == ehdr.e_machine @@ -483,6 +499,9 @@ fdopen_dso (int fd, const char *name) } dso->arch = plarch; +#else + dso->arch = NULL; +#endif /* DSO_READONLY */ dso->base = ~(GElf_Addr) 0; dso->align = 0; @@ -517,11 +536,12 @@ fdopen_dso (int fd, const char *name) const char *soname; soname = get_data (dso, dso->info[DT_STRTAB] + dso->info[DT_SONAME], - NULL); + NULL, NULL); if (soname && soname[0] != '\0') dso->soname = (const char *) strdup (soname); } +#ifndef DSO_READONLY if (dso->arch->machine == EM_ALPHA || dso->arch->machine == EM_MIPS) for (i = 1; i < ehdr.e_shnum; ++i) @@ -538,6 +558,7 @@ fdopen_dso (int fd, const char *name) break; } } +#endif /* DSO_READONLY */ return dso; @@ -553,10 +574,14 @@ error_out: if (elf) elf_end (elf); if (fd != -1) - close (fd); + { + fsync (fd); + close (fd); + } return NULL; } +#ifndef DSO_READONLY static int adjust_symtab_section_indices (DSO *dso, int n, int old_shnum, int *old_to_new) { @@ -767,15 +792,15 @@ reopen_dso (DSO *dso, struct section_move *move, const char *temp_base) temp_base = dso->filename; sprintf (filename, "%s.#prelink#.XXXXXX", temp_base); - fd = mkstemp (filename); + fd = wrap_mkstemp (filename); if (fd == -1) { strcpy (filename, "/tmp/#prelink#.XXXXXX"); - fd = mkstemp (filename); + fd = wrap_mkstemp (filename); if (fd == -1) { strcpy (filename, "/dev/shm/#prelink#.XXXXXX"); - fd = mkstemp (filename); + fd = wrap_mkstemp (filename); } if (fd == -1) { @@ -1017,7 +1042,8 @@ error_out: elf_end (elf); if (fd != -1) { - unlink (filename); + wrap_unlink (filename); + fsync (fd); close (fd); } return 1; @@ -1032,7 +1058,9 @@ adjust_symbol_p (DSO *dso, GElf_Sym *sym) { if (sym->st_shndx == SHN_ABS && sym->st_value != 0 - && GELF_ST_TYPE (sym->st_info) <= STT_FUNC) + && (GELF_ST_TYPE (sym->st_info) <= STT_FUNC + || (dso->ehdr.e_machine == EM_ARM + && GELF_ST_TYPE (sym->st_info) == STT_ARM_TFUNC))) /* This is problematic. How do we find out if we should relocate this? Assume we should. */ return 1; @@ -1080,6 +1108,7 @@ adjust_symtab (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust) elf_flagscn (scn, ELF_C_SET, ELF_F_DIRTY); return 0; } +#endif /* DSO_READONLY */ int dso_is_rdwr (DSO *dso) @@ -1087,6 +1116,7 @@ dso_is_rdwr (DSO *dso) return dso->elfro != NULL; } +#ifndef DSO_READONLY GElf_Addr adjust_old_to_new (DSO *dso, GElf_Addr addr) { @@ -1189,6 +1219,7 @@ adjust_dynamic (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust) read_dynamic (dso); return 0; } +#endif /* DSO_READONLY */ int addr_to_sec (DSO *dso, GElf_Addr addr) @@ -1210,6 +1241,7 @@ addr_to_sec (DSO *dso, GElf_Addr addr) return -1; } +#ifndef DSO_READONLY static int adjust_rel (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust) { @@ -1383,6 +1415,7 @@ adjust_dso (DSO *dso, GElf_Addr start, GElf_Addr adjust) switch (dso->shdr[i].sh_type) { case SHT_PROGBITS: + case SHT_MIPS_DWARF: name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[i].sh_name); if (strcmp (name, ".stab") == 0 && adjust_stabs (dso, i, start, adjust)) @@ -1406,12 +1439,15 @@ adjust_dso (DSO *dso, GElf_Addr start, GElf_Addr adjust) return 1; break; case SHT_REL: - if (adjust_rel (dso, i, start, adjust)) - return 1; + /* Don't adjust reloc sections for debug info. */ + if (dso->shdr[i].sh_flags & SHF_ALLOC) + if (adjust_rel (dso, i, start, adjust)) + return 1; break; case SHT_RELA: - if (adjust_rela (dso, i, start, adjust)) - return 1; + if (dso->shdr[i].sh_flags & SHF_ALLOC) + if (adjust_rela (dso, i, start, adjust)) + return 1; break; } if ((dso->arch->machine == EM_ALPHA @@ -1610,6 +1646,7 @@ relocate_dso (DSO *dso, GElf_Addr base) return adjust_dso (dso, 0, base - dso->base); } +#endif /* DSO_READONLY */ static int close_dso_1 (DSO *dso) @@ -1632,10 +1669,12 @@ close_dso_1 (DSO *dso) } elf_end (dso->elf); + fsync (dso->fd); close (dso->fd); if (dso->elfro) { elf_end (dso->elfro); + fsync (dso->fdro); close (dso->fdro); } if (dso->filename != dso->soname) @@ -1655,11 +1694,12 @@ close_dso (DSO *dso) int rdwr = dso_is_rdwr (dso); if (rdwr && dso->temp_filename != NULL) - unlink (dso->temp_filename); + wrap_unlink (dso->temp_filename); close_dso_1 (dso); return 0; } +#ifndef DSO_READONLY int prepare_write_dso (DSO *dso) { @@ -1699,7 +1739,7 @@ write_dso (DSO *dso) static int copy_xattrs (const char *temp_name, const char *name, int ignore_errors) { - ssize_t sz = listxattr (name, NULL, 0), valsz = 0; + ssize_t sz = wrap_listxattr (name, NULL, 0), valsz = 0; char *list = NULL, *end, *p, *val = NULL, *newval; if (sz < 0) @@ -1711,7 +1751,7 @@ copy_xattrs (const char *temp_name, const char *name, int ignore_errors) list = malloc (sz + 1); if (list == NULL) goto read_err; - sz = listxattr (name, list, sz); + sz = wrap_listxattr (name, list, sz); if (sz < 0) goto read_err; end = list + sz; @@ -1721,12 +1761,12 @@ copy_xattrs (const char *temp_name, const char *name, int ignore_errors) continue; else { - sz = getxattr (name, p, val, valsz); + sz = wrap_getxattr (name, p, val, valsz); if (sz < 0) { if (errno != ERANGE) goto read_err; - sz = getxattr (name, p, NULL, 0); + sz = wrap_getxattr (name, p, NULL, 0); if (sz < 0) goto read_err; } @@ -1739,11 +1779,11 @@ copy_xattrs (const char *temp_name, const char *name, int ignore_errors) if (newval == NULL) goto read_err; val = newval; - sz = getxattr (name, p, val, valsz); + sz = wrap_getxattr (name, p, val, valsz); if (sz < 0) goto read_err; } - if (setxattr (temp_name, p, val, sz, 0) < 0) + if (wrap_setxattr (temp_name, p, val, sz, 0) < 0) { if (errno == ENOSYS || errno == ENOTSUP) continue; @@ -1754,7 +1794,7 @@ copy_xattrs (const char *temp_name, const char *name, int ignore_errors) newval = malloc (sz); if (newval == NULL - || (newsz = getxattr (temp_name, p, newval, sz)) != sz + || (newsz = wrap_getxattr (temp_name, p, newval, sz)) != sz || memcmp (val, newval, sz) != 0) { error (0, err, "Could not set extended attributes for %s", @@ -1811,7 +1851,7 @@ set_security_context (const char *temp_name, const char *name, } freecon (scontext); } -#endif +#endif /* USE_SELINUX */ return copy_xattrs (temp_name, name, ignore_errors); } @@ -1826,7 +1866,7 @@ copy_fd_to_file (int fdin, const char *name, struct stat64 *st) if (strcmp (name, "-") == 0) fdout = 1; else - fdout = open (name, O_WRONLY | O_CREAT, 0600); + fdout = wrap_open (name, O_WRONLY | O_CREAT, 0600); if (fdout != -1 && fstat64 (fdin, &stt) >= 0 && send_file (fdout, fdin, &off, stt.st_size) == stt.st_size) @@ -1838,7 +1878,7 @@ copy_fd_to_file (int fdin, const char *name, struct stat64 *st) set_security_context (name, name, 1); u.actime = time (NULL); u.modtime = st->st_mtime; - utime (name, &u); + wrap_utime (name, &u); close (fdout); } return 0; @@ -1902,33 +1942,33 @@ update_dso (DSO *dso, const char *orig_name) close_dso_1 (dso); u.actime = time (NULL); u.modtime = st.st_mtime; - utime (name2, &u); + wrap_utime (name2, &u); if (set_security_context (name2, orig_name ? orig_name : name1, orig_name != NULL)) { if (fdin != -1) close (fdin); - unlink (name2); + wrap_unlink (name2); return 1; } if ((orig_name != NULL && strcmp (name1, "-") == 0) - || rename (name2, name1)) + || wrap_rename (name2, name1)) { if (fdin != -1) { int err = copy_fd_to_file (fdin, name1, &st); close (fdin); - unlink (name2); + wrap_unlink (name2); if (err == 0) return 0; error (0, err, "Could not rename nor copy temporary to %s", name1); return 1; } - unlink (name2); + wrap_unlink (name2); error (0, errno, "Could not rename temporary to %s", name1); return 1; } @@ -1940,3 +1980,29 @@ update_dso (DSO *dso, const char *orig_name) return 0; } + +int allow_bad_textrel; + +int +dso_has_bad_textrel (DSO *dso) +{ + if (allow_bad_textrel) + return 0; + + switch (dso->arch->machine) + { + case EM_IA_64: + case EM_PPC: + case EM_PPC64: + case EM_X86_64: + case EM_ALPHA: + case EM_S390: + case EM_MIPS: + case EM_ARM: + return dynamic_info_is_set (dso, DT_TEXTREL); + + default: + return 0; + } +} +#endif /* DSO_READONLY */ |