Implement LD_BIND_NOT knob for rtld.

From the manpage:
When set to a nonempty string, prevents modifications of the PLT slots
when doing bindings.  As result, each call of the PLT-resolved
function is resolved.  In combination with debug output, this provides
complete account of all bind actions at runtime.

Same feature exists on Linux and Solaris.

Sponsored by:	The FreeBSD Foundation
MFC after:	2 weeks
This commit is contained in:
Konstantin Belousov 2017-03-15 21:11:57 +00:00
parent d10e4cd0c0
commit e35ddbe448
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=315331
21 changed files with 86 additions and 65 deletions

View File

@ -298,10 +298,9 @@ reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj,
assert(ELF_R_TYPE(rel->r_info) == R_AARCH64_JUMP_SLOT); assert(ELF_R_TYPE(rel->r_info) == R_AARCH64_JUMP_SLOT);
if (*where != target) if (*where != target && !ld_bind_not)
*where = target; *where = target;
return (target);
return target;
} }
void void

View File

@ -47,9 +47,8 @@ struct Struct_Obj_Entry;
}) })
Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target, Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *obj,
const struct Struct_Obj_Entry *obj, const Elf_Rel *rel);
const Elf_Rel *rel);
#define make_function_pointer(def, defobj) \ #define make_function_pointer(def, defobj) \
((defobj)->relocbase + (def)->st_value) ((defobj)->relocbase + (def)->st_value)

View File

@ -387,6 +387,20 @@ reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
return 0; return 0;
} }
/* Fixup the jump slot at "where" to transfer control to "target". */
Elf_Addr
reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
const struct Struct_Obj_Entry *obj, const struct Struct_Obj_Entry *refobj,
const Elf_Rel *rel)
{
#ifdef dbg
dbg("reloc_jmpslot: *%p = %p", where, (void *)target);
#endif
if (!ld_bind_not)
*where = target;
return (target);
}
int int
reloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate) reloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate)
{ {

View File

@ -38,21 +38,11 @@ struct Struct_Obj_Entry;
Elf_Dyn *rtld_dynamic_addr(void); Elf_Dyn *rtld_dynamic_addr(void);
#define rtld_dynamic(obj) rtld_dynamic_addr() #define rtld_dynamic(obj) rtld_dynamic_addr()
/* Fixup the jump slot at "where" to transfer control to "target". */ Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
static inline Elf_Addr const struct Struct_Obj_Entry *obj, const struct Struct_Obj_Entry *refobj,
reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Elf_Rel *rel);
const struct Struct_Obj_Entry *obj,
const struct Struct_Obj_Entry *refobj, const Elf_Rel *rel)
{
#ifdef dbg
dbg("reloc_jmpslot: *%p = %p", (void *)(where),
(void *)(target));
#endif
(*(Elf_Addr *)(where) = (Elf_Addr)(target));
return target;
}
#define make_function_pointer(def, defobj) \ #define make_function_pointer(def, defobj) \
((defobj)->relocbase + (def)->st_value) ((defobj)->relocbase + (def)->st_value)
#define call_initfini_pointer(obj, target) \ #define call_initfini_pointer(obj, target) \

View File

@ -468,15 +468,14 @@ reloc_gnu_ifunc(Obj_Entry *obj, int flags,
Elf_Addr Elf_Addr
reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj, reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj,
const Obj_Entry *obj, const Elf_Rel *rel) const Obj_Entry *obj, const Elf_Rel *rel)
{ {
assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT); assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
if (*where != target) if (*where != target && !ld_bind_not)
*where = target; *where = target;
return (target);
return target;
} }
void void

View File

@ -38,9 +38,8 @@ struct Struct_Obj_Entry;
#define rtld_dynamic(obj) (&_DYNAMIC) #define rtld_dynamic(obj) (&_DYNAMIC)
Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target, Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *obj,
const struct Struct_Obj_Entry *obj, const Elf_Rel *rel);
const Elf_Rel *rel);
#define make_function_pointer(def, defobj) \ #define make_function_pointer(def, defobj) \
((defobj)->relocbase + (def)->st_value) ((defobj)->relocbase + (def)->st_value)

View File

@ -344,6 +344,20 @@ reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
return 0; return 0;
} }
/* Fixup the jump slot at "where" to transfer control to "target". */
Elf_Addr
reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
const struct Struct_Obj_Entry *obj, const struct Struct_Obj_Entry *refobj,
const Elf_Rel *rel)
{
#ifdef dbg
dbg("reloc_jmpslot: *%p = %p", where, (void *)target);
#endif
if (!ld_bind_not)
*where = target;
return (target);
}
int int
reloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate) reloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate)
{ {

View File

@ -38,21 +38,11 @@ struct Struct_Obj_Entry;
#define rtld_dynamic(obj) \ #define rtld_dynamic(obj) \
((const Elf_Dyn *)((obj)->relocbase + (Elf_Addr)&_DYNAMIC)) ((const Elf_Dyn *)((obj)->relocbase + (Elf_Addr)&_DYNAMIC))
/* Fixup the jump slot at "where" to transfer control to "target". */ Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
static inline Elf_Addr const struct Struct_Obj_Entry *obj, const struct Struct_Obj_Entry *refobj,
reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Elf_Rel *rel);
const struct Struct_Obj_Entry *obj,
const struct Struct_Obj_Entry *refobj, const Elf_Rel *rel)
{
#ifdef dbg
dbg("reloc_jmpslot: *%p = %p", (void *)(where),
(void *)(target));
#endif
(*(Elf_Addr *)(where) = (Elf_Addr)(target));
return target;
}
#define make_function_pointer(def, defobj) \ #define make_function_pointer(def, defobj) \
((defobj)->relocbase + (def)->st_value) ((defobj)->relocbase + (def)->st_value)
#define call_initfini_pointer(obj, target) \ #define call_initfini_pointer(obj, target) \

View File

@ -274,7 +274,8 @@ _mips_rtld_bind(Obj_Entry *obj, Elf_Size reloff)
obj->path, obj->path,
(intmax_t)reloff, defobj->strtab + def->st_name, (intmax_t)reloff, defobj->strtab + def->st_name,
(void *)*where, (void *)target); (void *)*where, (void *)target);
*where = target; if (!ld_bind_not)
*where = target;
lock_release(rtld_bind_lock, &lockstate); lock_release(rtld_bind_lock, &lockstate);
return (Elf_Addr)target; return (Elf_Addr)target;
} }

View File

@ -39,9 +39,8 @@ struct Struct_Obj_Entry;
#define rtld_dynamic(obj) (&_DYNAMIC) #define rtld_dynamic(obj) (&_DYNAMIC)
Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target, Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *obj,
const struct Struct_Obj_Entry *obj, const Elf_Rel *rel);
const Elf_Rel *rel);
#define make_function_pointer(def, defobj) \ #define make_function_pointer(def, defobj) \
((defobj)->relocbase + (def)->st_value) ((defobj)->relocbase + (def)->st_value)

View File

@ -468,7 +468,7 @@ reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
*/ */
Elf_Addr Elf_Addr
reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj, reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj,
const Obj_Entry *obj, const Elf_Rel *rel) const Obj_Entry *obj, const Elf_Rel *rel)
{ {
Elf_Addr offset; Elf_Addr offset;
const Elf_Rela *rela = (const Elf_Rela *) rel; const Elf_Rela *rela = (const Elf_Rela *) rel;
@ -476,6 +476,9 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj,
dbg(" reloc_jmpslot: where=%p, target=%p", dbg(" reloc_jmpslot: where=%p, target=%p",
(void *)wherep, (void *)target); (void *)wherep, (void *)target);
if (ld_bind_not)
goto out;
/* /*
* At the PLT entry pointed at by `wherep', construct * At the PLT entry pointed at by `wherep', construct
* a direct transfer to the now fully resolved function * a direct transfer to the now fully resolved function
@ -519,6 +522,7 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj,
} }
} }
out:
return (target); return (target);
} }

View File

@ -38,9 +38,8 @@ struct Struct_Obj_Entry;
#define rtld_dynamic(obj) (&_DYNAMIC) #define rtld_dynamic(obj) (&_DYNAMIC)
Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target, Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *obj,
const struct Struct_Obj_Entry *obj, const Elf_Rel *rel);
const Elf_Rel *rel);
#define make_function_pointer(def, defobj) \ #define make_function_pointer(def, defobj) \
((defobj)->relocbase + (def)->st_value) ((defobj)->relocbase + (def)->st_value)

View File

@ -433,7 +433,7 @@ reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
*/ */
Elf_Addr Elf_Addr
reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj, reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj,
const Obj_Entry *obj, const Elf_Rel *rel) const Obj_Entry *obj, const Elf_Rel *rel)
{ {
/* /*
@ -447,6 +447,9 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj,
(void *)wherep, (void *)target, *(Elf_Addr *)target, (void *)wherep, (void *)target, *(Elf_Addr *)target,
(Elf_Addr)defobj->relocbase); (Elf_Addr)defobj->relocbase);
if (ld_bind_not)
goto out;
/* /*
* For the trampoline, the second two elements of the function * For the trampoline, the second two elements of the function
* descriptor are unused, so we are fine replacing those at any time * descriptor are unused, so we are fine replacing those at any time
@ -476,11 +479,13 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj,
((struct funcdesc *)(wherep))->toc += ((struct funcdesc *)(wherep))->toc +=
(Elf_Addr)defobj->relocbase; (Elf_Addr)defobj->relocbase;
} }
out:
#else #else
dbg(" reloc_jmpslot: where=%p, target=%p", (void *)wherep, dbg(" reloc_jmpslot: where=%p, target=%p", (void *)wherep,
(void *)target); (void *)target);
*wherep = target; if (!ld_bind_not)
*wherep = target;
#endif #endif
return (target); return (target);

View File

@ -38,9 +38,8 @@ struct Struct_Obj_Entry;
#define rtld_dynamic(obj) (&_DYNAMIC) #define rtld_dynamic(obj) (&_DYNAMIC)
Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target, Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *obj,
const struct Struct_Obj_Entry *obj, const Elf_Rel *rel);
const Elf_Rel *rel);
#define make_function_pointer(def, defobj) \ #define make_function_pointer(def, defobj) \
((defobj)->relocbase + (def)->st_value) ((defobj)->relocbase + (def)->st_value)

View File

@ -226,10 +226,9 @@ reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj,
assert(ELF_R_TYPE(rel->r_info) == R_RISCV_JUMP_SLOT); assert(ELF_R_TYPE(rel->r_info) == R_RISCV_JUMP_SLOT);
if (*where != target) if (*where != target && !ld_bind_not)
*where = target; *where = target;
return (target);
return target;
} }
/* /*

View File

@ -54,9 +54,8 @@ uint64_t set_gp(struct Struct_Obj_Entry *obj);
}) })
Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target, Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *obj,
const struct Struct_Obj_Entry *obj, const Elf_Rel *rel);
const Elf_Rel *rel);
#define make_function_pointer(def, defobj) \ #define make_function_pointer(def, defobj) \
((defobj)->relocbase + (def)->st_value) ((defobj)->relocbase + (def)->st_value)

View File

@ -28,7 +28,7 @@
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd June 20, 2014 .Dd March 16, 2017
.Dt RTLD 1 .Dt RTLD 1
.Os .Os
.Sh NAME .Sh NAME
@ -199,6 +199,12 @@ This is intended for use within
sandboxes, when global namespaces such as the filesystem are unavailable. sandboxes, when global namespaces such as the filesystem are unavailable.
It is consulted just after LD_LIBRARY_PATH. It is consulted just after LD_LIBRARY_PATH.
This variable is unset for set-user-ID and set-group-ID programs. This variable is unset for set-user-ID and set-group-ID programs.
.It Ev LD_BIND_NOT
When set to a nonempty string, prevents modifications of the PLT slots when
doing bindings.
As result, each call of the PLT-resolved function is resolved.
In combination with debug output, this provides complete account of
all bind actions at runtime.
.It Ev LD_BIND_NOW .It Ev LD_BIND_NOW
When set to a nonempty string, causes When set to a nonempty string, causes
.Nm .Nm

View File

@ -178,6 +178,7 @@ static char *libmap_override; /* Maps to use in addition to libmap.conf */
static bool trust; /* False for setuid and setgid programs */ static bool trust; /* False for setuid and setgid programs */
static bool dangerous_ld_env; /* True if environment variables have been static bool dangerous_ld_env; /* True if environment variables have been
used to affect the libraries loaded */ used to affect the libraries loaded */
bool ld_bind_not; /* Disable PLT update */
static char *ld_bind_now; /* Environment variable for immediate binding */ static char *ld_bind_now; /* Environment variable for immediate binding */
static char *ld_debug; /* Environment variable for debugging */ static char *ld_debug; /* Environment variable for debugging */
static char *ld_library_path; /* Environment variable for search path */ static char *ld_library_path; /* Environment variable for search path */
@ -416,6 +417,9 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
md_abi_variant_hook(aux_info); md_abi_variant_hook(aux_info);
ld_bind_now = getenv(_LD("BIND_NOW")); ld_bind_now = getenv(_LD("BIND_NOW"));
if (ld_bind_now == NULL)
ld_bind_not = getenv(_LD("BIND_NOT")) != NULL;
/* /*
* If the process is tainted, then we un-set the dangerous environment * If the process is tainted, then we un-set the dangerous environment
* variables. The process will be marked as tainted until setuid(2) * variables. The process will be marked as tainted until setuid(2)

View File

@ -358,6 +358,7 @@ void *malloc_aligned(size_t size, size_t align);
void free_aligned(void *ptr); void free_aligned(void *ptr);
extern Elf_Addr _GLOBAL_OFFSET_TABLE_[]; extern Elf_Addr _GLOBAL_OFFSET_TABLE_[];
extern Elf_Sym sym_zero; /* For resolving undefined weak refs. */ extern Elf_Sym sym_zero; /* For resolving undefined weak refs. */
extern bool ld_bind_not;
void dump_relocations(Obj_Entry *); void dump_relocations(Obj_Entry *);
void dump_obj_relocations(Obj_Entry *); void dump_obj_relocations(Obj_Entry *);

View File

@ -581,7 +581,9 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *obj,
Elf_Addr offset; Elf_Addr offset;
Elf_Word *where; Elf_Word *where;
if (rela - refobj->pltrela < 32764) { if (ld_bind_not) {
/* Skip any PLT modifications */
} else if (rela - refobj->pltrela < 32764) {
/* /*
* At the PLT entry pointed at by `where', we now construct * At the PLT entry pointed at by `where', we now construct
* a direct transfer to the now fully resolved function * a direct transfer to the now fully resolved function

View File

@ -39,9 +39,8 @@ Elf_Dyn *rtld_dynamic_addr(void);
#define rtld_dynamic(obj) rtld_dynamic_addr() #define rtld_dynamic(obj) rtld_dynamic_addr()
Elf_Addr reloc_jmpslot(Elf_Addr *, Elf_Addr, Elf_Addr reloc_jmpslot(Elf_Addr *, Elf_Addr,
const struct Struct_Obj_Entry *, const struct Struct_Obj_Entry *, const struct Struct_Obj_Entry *,
const struct Struct_Obj_Entry *, const Elf_Rel *);
const Elf_Rel *);
#define make_function_pointer(def, defobj) \ #define make_function_pointer(def, defobj) \
((defobj)->relocbase + (def)->st_value) ((defobj)->relocbase + (def)->st_value)