Skip to content

Commit

Permalink
libdrgn: linux_kernel: fallback section iterator
Browse files Browse the repository at this point in the history
The files within /sys/module/*/sections seem to normally be 400
permissions, only accessible by root. Normally for live use, this is not
a problem because we are running as root. However, if we're running as
non-root, then we may get EACCES on these files.

To handle this, fall back to using the non-live approach if we get an
EACCES. Even if we do get the error, we can continue to use the
/sys/module/*/notes files to maintain a partial speedup.

Signed-off-by: Stephen Brennan <[email protected]>
  • Loading branch information
brenns10 committed Aug 22, 2023
1 parent 5656098 commit c552ee0
Showing 1 changed file with 48 additions and 26 deletions.
74 changes: 48 additions & 26 deletions libdrgn/linux_kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ struct kernel_module_iterator {
/* Address of `struct list_head modules`. */
uint64_t head;
bool use_sys_module;
bool use_sys_module_sections;
};

static void kernel_module_iterator_deinit(struct kernel_module_iterator *it)
Expand All @@ -435,6 +436,7 @@ kernel_module_iterator_init(struct kernel_module_iterator *it,
it->build_id_buf = NULL;
it->build_id_buf_capacity = 0;
it->use_sys_module = use_sys_module;
it->use_sys_module_sections = use_sys_module;
err = drgn_program_find_type(prog, "struct module", NULL,
&it->module_type);
if (err)
Expand Down Expand Up @@ -825,14 +827,40 @@ struct kernel_module_section_iterator {
};

static struct drgn_error *
kernel_module_section_iterator_init(struct kernel_module_section_iterator *it,
struct kernel_module_iterator *kmod_it)
kernel_module_section_iterator_init_no_sys_module(struct kernel_module_section_iterator *it,
struct kernel_module_iterator *kmod_it)
{
struct drgn_error *err;

it->sections_dir = NULL;
it->i = 0;
it->name = NULL;
/* it->nsections = mod->sect_attrs->nsections */
err = drgn_object_member(&kmod_it->tmp1, &kmod_it->mod,
"sect_attrs");
if (err)
return err;
err = drgn_object_member_dereference(&kmod_it->tmp2,
&kmod_it->tmp1,
"nsections");
if (err)
return err;
err = drgn_object_read_unsigned(&kmod_it->tmp2,
&it->nsections);
if (err)
return err;
/* kmod_it->tmp1 = mod->sect_attrs->attrs */
return drgn_object_member_dereference(&kmod_it->tmp1,
&kmod_it->tmp1, "attrs");
}

static struct drgn_error *
kernel_module_section_iterator_init(struct kernel_module_section_iterator *it,
struct kernel_module_iterator *kmod_it)
{
it->kmod_it = kmod_it;
it->yielded_percpu = false;
if (kmod_it->use_sys_module) {
if (kmod_it->use_sys_module_sections) {
char *path;
if (asprintf(&path, "/sys/module/%s/sections",
kmod_it->name) == -1)
Expand All @@ -846,26 +874,7 @@ kernel_module_section_iterator_init(struct kernel_module_section_iterator *it,
}
return NULL;
} else {
it->sections_dir = NULL;
it->i = 0;
it->name = NULL;
/* it->nsections = mod->sect_attrs->nsections */
err = drgn_object_member(&kmod_it->tmp1, &kmod_it->mod,
"sect_attrs");
if (err)
return err;
err = drgn_object_member_dereference(&kmod_it->tmp2,
&kmod_it->tmp1,
"nsections");
if (err)
return err;
err = drgn_object_read_unsigned(&kmod_it->tmp2,
&it->nsections);
if (err)
return err;
/* kmod_it->tmp1 = mod->sect_attrs->attrs */
return drgn_object_member_dereference(&kmod_it->tmp1,
&kmod_it->tmp1, "attrs");
return kernel_module_section_iterator_init_no_sys_module(it, kmod_it);
}
}

Expand Down Expand Up @@ -971,8 +980,18 @@ kernel_module_section_iterator_next(struct kernel_module_section_iterator *it,
}

if (it->sections_dir) {
return kernel_module_section_iterator_next_live(it, name_ret,
address_ret);
err = kernel_module_section_iterator_next_live(it, name_ret,
address_ret);
if (err && err->code == DRGN_ERROR_OS && err->errnum == EACCES) {
closedir(it->sections_dir);
drgn_error_destroy(err);
it->kmod_it->use_sys_module_sections = false;
err = kernel_module_section_iterator_init_no_sys_module(it, it->kmod_it);
if (err)
return err;
} else {
return err;
}
}

if (it->i >= it->nsections)
Expand Down Expand Up @@ -1570,8 +1589,11 @@ report_kernel_modules(struct drgn_debug_info_load_state *load,
/*
* If we're debugging the running kernel, we can use
* /sys/module/$module/notes and /sys/module/$module/sections instead of
* getting the equivalent information from the core dump. But this is
* getting the equivalent information from the core dump. This fast path
* can be disabled via an environment variable for testing.
* can be disabled via an environment variable for testing. It may also
* be disabled if we encounter permission issues using
* /sys/module/$module/sections.
*/
bool use_sys_module = false;
if (prog->flags & DRGN_PROGRAM_IS_LIVE) {
Expand Down

0 comments on commit c552ee0

Please sign in to comment.