Skip to content

Commit

Permalink
rtld: Add compartments for sub-object compartments described by PT_CO…
Browse files Browse the repository at this point in the history
…MPARTMENT

- Recognize the new c18n string table via DT_C18NSTRTAB* and save
  bounded pointers in each Obj_Entry.

- Define a new Compart_Entry type to hold information about a
  sub-object compartment including its compartment ID, virtual address
  bounds, and name.  The name for sub-object is "<obj
  name>:<compartment name>".

  Currently the default compartment for an object does not have a
  suffix.  Possibly it should.

- This requires reworking compartment assignment to be more explicitly
  timed (always after digest_dynamic) rather than a side effect of
  object_add_name.  Since we now always have DT_SONAME if it is
  present, save a pointer to DT_SONAME in Obj_Entry and prefer it for
  the library name for a compartment (instead of using the first name
  added).
  • Loading branch information
bsdjhb committed Dec 11, 2024
1 parent 341a20c commit d7a2fff
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 6 deletions.
8 changes: 8 additions & 0 deletions libexec/rtld-elf/map_object.c
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,14 @@ obj_free(Obj_Entry *obj)
if (obj->path)
free(obj->path);
#ifdef __CHERI_PURE_CAPABILITY__
#ifdef CHERI_LIB_C18N
if (obj->comparts) {
for (unsigned long i = 0; i < obj->ncomparts; i++) {
free(obj->comparts[i].compart_name);
}
free(obj->comparts);
}
#endif
if (obj->pcc_caps)
free(obj->pcc_caps);
#endif
Expand Down
130 changes: 124 additions & 6 deletions libexec/rtld-elf/rtld.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ static void rtld_fill_dl_phdr_info(const Obj_Entry *obj,
static uint32_t gnu_hash(const char *);
static bool matched_symbol(SymLook *, const Obj_Entry *, Sym_Match_Result *,
const unsigned long);
#ifdef CHERI_LIB_C18N
static bool c18n_add_obj(Obj_Entry *, const char *);
#endif

void r_debug_state(struct r_debug *, struct link_map *) __noinline __exported;
void _r_debug_postinit(struct link_map *) __noinline __exported;
Expand Down Expand Up @@ -959,7 +962,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
/*
* Manually register the main object after the policy is loaded.
*/
object_add_name(obj_main, obj_main->path);
(void)c18n_add_obj(obj_main, obj_main->path);
}
#endif

Expand Down Expand Up @@ -1651,6 +1654,14 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath,
obj->sigtab = (const struct func_sig *)
(obj->relocbase + dynp->d_un.d_ptr);
break;

case DT_C18NSTRTAB:
obj->c18nstrtab = (const char *)(obj->relocbase + dynp->d_un.d_ptr);
break;

case DT_C18NSTRTABSZ:
obj->c18nstrsize = dynp->d_un.d_val;
break;
#endif

case DT_STRTAB:
Expand Down Expand Up @@ -1950,8 +1961,12 @@ digest_dynamic2(Obj_Entry *obj, const Elf_Dyn *dyn_rpath,
obj->rpath = (const char *)obj->strtab + dyn_rpath->d_un.d_val;
obj->rpath = origin_subst(obj, obj->rpath);
}
if (dyn_soname != NULL)
if (dyn_soname != NULL) {
#ifdef CHERI_LIB_C18N
obj->soname = obj->strtab + dyn_soname->d_un.d_val;
#endif
object_add_name(obj, obj->strtab + dyn_soname->d_un.d_val);
}
#ifdef __CHERI_PURE_CAPABILITY__
// Set tight bounds on the individual members now (for the ones that
// we iterate over) instead of inheriting the relocbase bounds to avoid
Expand All @@ -1963,6 +1978,9 @@ digest_dynamic2(Obj_Entry *obj, const Elf_Dyn *dyn_rpath,
set_bounds_if_nonnull(plt->rel, plt->relsize);
set_bounds_if_nonnull(plt->rela, plt->relasize);
}
#ifdef CHERI_LIB_C18N
set_bounds_if_nonnull(obj->c18nstrtab, obj->c18nstrsize);
#endif
set_bounds_if_nonnull(obj->strtab, obj->strsize);
set_bounds_if_nonnull(obj->phdr, obj->phsize);

Expand Down Expand Up @@ -3301,6 +3319,10 @@ do_load_object(int fd, const char *name, char *path, struct stat *sbp,
obj->path = path;
if (!digest_dynamic(obj, 0))
goto errp;
#ifdef CHERI_LIB_C18N
if (!c18n_add_obj(obj, name))
goto errp;
#endif
dbg("%s valid_hash_sysv %d valid_hash_gnu %d dynsymcount %d", obj->path,
obj->valid_hash_sysv, obj->valid_hash_gnu, obj->dynsymcount);
if (obj->z_pie && (flags & RTLD_LO_TRACE) == 0) {
Expand Down Expand Up @@ -6260,6 +6282,106 @@ _rtld_free_tls(void *tcb, size_t tcbsize, size_t tcbalign)
lock_release(rtld_bind_lock, &lockstate);
}

#ifdef CHERI_LIB_C18N
static bool
validate_c18nstrtab(const Obj_Entry *obj)
{
const Elf_Phdr *ph;

if (obj->c18nstrtab != NULL) {
if (obj->c18nstrsize == 0)
return (false);
if (obj->c18nstrtab[obj->c18nstrsize - 1] != '\0')
return (false);
}

for (ph = obj->phdr; (const char *)ph < (const char *)obj->phdr +
obj->phsize; ph++) {
switch (ph->p_type) {
case PT_COMPARTMENT:
if (obj->c18nstrtab == NULL ||
ph->p_paddr >= obj->c18nstrsize)
return (false);
break;
}
}
return (true);
}

static void
c18n_setup_compartments(Obj_Entry *obj, const char *name)
{
Compart_Entry *compart;
const Elf_Phdr *ph;
size_t len;

assert(obj->compart_id == 0);
obj->compart_id = compart_id_allocate(name);

for (ph = obj->phdr; (const char *)ph < (const char *)obj->phdr +
obj->phsize; ph++) {
switch (ph->p_type) {
case PT_COMPARTMENT:
obj->ncomparts++;
break;
}
}

if (obj->ncomparts == 0)
return;

obj->comparts = xcalloc(obj->ncomparts, sizeof(*obj->comparts));
compart = obj->comparts;
for (ph = obj->phdr; (const char *)ph < (const char *)obj->phdr +
obj->phsize; ph++) {
switch (ph->p_type) {
case PT_COMPARTMENT:
compart->obj = obj;
compart->name = obj->c18nstrtab + ph->p_paddr;
compart->start = (ptraddr_t)obj->relocbase +
ph->p_vaddr;
compart->end = compart->start + ph->p_memsz;

len = strlen(name) + 1 + strlen(compart->name) + 1;
compart->compart_name = malloc(len);
rtld_snprintf(compart->compart_name, len, "%s:%s",
name, compart->name);
compart->compart_id =
compart_id_allocate(compart->compart_name);
compart++;
break;
}
}
}

static bool
c18n_add_obj(Obj_Entry *obj, const char *name)
{
if (!C18N_ENABLED)
return (true);

if (!validate_c18nstrtab(obj))
return (false);

/* Prefer DT_SONAME as the compartment base name if present. */
if (obj->soname != NULL)
name = obj->soname;

/* Try to find a name if none provided. */
if (name == NULL) {
if (!STAILQ_EMPTY(&obj->names))
name = STAILQ_FIRST(&obj->names)->name;
else if (obj->path != NULL)
name = obj->path;
else
return (false);
}

c18n_setup_compartments(obj, name);
return (true);
}
#endif

static void
object_add_name(Obj_Entry *obj, const char *name)
{
Expand All @@ -6272,10 +6394,6 @@ object_add_name(Obj_Entry *obj, const char *name)
if (entry != NULL) {
strcpy(entry->name, name);
STAILQ_INSERT_TAIL(&obj->names, entry, link);
#ifdef CHERI_LIB_C18N
if (C18N_ENABLED && obj->compart_id == 0)
obj->compart_id = compart_id_allocate(entry->name);
#endif
}
}

Expand Down
19 changes: 19 additions & 0 deletions libexec/rtld-elf/rtld.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,18 @@ typedef struct Struct_Plt_Entry {
MD_PLT_ENTRY;
} Plt_Entry;

#ifdef CHERI_LIB_C18N
typedef struct Struct_Compart_Entry {
struct Struct_Obj_Entry *obj;

const char *name;
Elf_Addr start;
Elf_Addr end;
char *compart_name;
uint16_t compart_id;
} Compart_Entry;
#endif

#define VER_INFO_HIDDEN 0x01

/*
Expand Down Expand Up @@ -250,6 +262,12 @@ typedef struct Struct_Obj_Entry {
const Elf_Sym *symtab; /* Symbol table */
const char *strtab; /* String table */
unsigned long strsize; /* Size in bytes of string table */
#ifdef CHERI_LIB_C18N
Compart_Entry *comparts;
unsigned long ncomparts;
const char *c18nstrtab; /* Compartment string table */
unsigned long c18nstrsize; /* Size in bytes of compartment string table */
#endif
#ifdef RTLD_HAS_CAPRELOCS
caddr_t cap_relocs; /* start of the __cap_relocs section */
size_t cap_relocs_size; /* size of the __cap_relocs section */
Expand Down Expand Up @@ -287,6 +305,7 @@ typedef struct Struct_Obj_Entry {
int vernum; /* Number of entries in vertab */

#ifdef CHERI_LIB_C18N
const char *soname;
uint16_t compart_id;
const struct func_sig *sigtab;
#endif
Expand Down

0 comments on commit d7a2fff

Please sign in to comment.