summaryrefslogtreecommitdiffstats
path: root/trunk/src/dso.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/dso.c')
-rw-r--r--trunk/src/dso.c122
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 */