Skip to content

Commit

Permalink
jump label: Fix module __init section race
Browse files Browse the repository at this point in the history
Jump label uses is_module_text_address() to ensure that the module
__init sections are valid before updating them. However, between the
check for a valid module __init section and the subsequent jump
label update, the module's __init section could be freed out from under
us.

We fix this potential race by adding a notifier callback to the
MODULE_STATE_LIVE state. This notifier is called *after* the __init
section has been run but before it is going to be freed. In the
callback, the jump label code zeros the key value for any __init jump
code within the module, and we add a check for a non-zero key value when
we update jump labels. In this way we require no additional data
structures.

Thanks to Mathieu Desnoyers for pointing out this race condition.

Reported-by: Mathieu Desnoyers <[email protected]>
Cc: Masami Hiramatsu <[email protected]>
Signed-off-by: Jason Baron <[email protected]>
LKML-Reference: <c6f037b7598777668025ceedd9294212fd95fa34.1285965957.git.jbaron@redhat.com>

[ Renamed remove_module_init() to remove_jump_label_module_init()
  as suggested by Masami Hiramatsu. ]

Signed-off-by: Steven Rostedt <[email protected]>
  • Loading branch information
jibaron authored and rostedt committed Oct 28, 2010
1 parent e3e1288 commit b842f8f
Showing 1 changed file with 40 additions and 1 deletion.
41 changes: 40 additions & 1 deletion kernel/jump_label.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ void jump_label_update(unsigned long key, enum jump_label_type type)
count = e_module->nr_entries;
iter = e_module->table;
while (count--) {
if (kernel_text_address(iter->code))
if (iter->key &&
kernel_text_address(iter->code))
arch_jump_label_transform(iter, type);
iter++;
}
Expand Down Expand Up @@ -366,6 +367,39 @@ static void remove_jump_label_module(struct module *mod)
}
}

static void remove_jump_label_module_init(struct module *mod)
{
struct hlist_head *head;
struct hlist_node *node, *node_next, *module_node, *module_node_next;
struct jump_label_entry *e;
struct jump_label_module_entry *e_module;
struct jump_entry *iter;
int i, count;

/* if the module doesn't have jump label entries, just return */
if (!mod->num_jump_entries)
return;

for (i = 0; i < JUMP_LABEL_TABLE_SIZE; i++) {
head = &jump_label_table[i];
hlist_for_each_entry_safe(e, node, node_next, head, hlist) {
hlist_for_each_entry_safe(e_module, module_node,
module_node_next,
&(e->modules), hlist) {
if (e_module->mod != mod)
continue;
count = e_module->nr_entries;
iter = e_module->table;
while (count--) {
if (within_module_init(iter->code, mod))
iter->key = 0;
iter++;
}
}
}
}
}

static int
jump_label_module_notify(struct notifier_block *self, unsigned long val,
void *data)
Expand All @@ -386,6 +420,11 @@ jump_label_module_notify(struct notifier_block *self, unsigned long val,
remove_jump_label_module(mod);
mutex_unlock(&jump_label_mutex);
break;
case MODULE_STATE_LIVE:
mutex_lock(&jump_label_mutex);
remove_jump_label_module_init(mod);
mutex_unlock(&jump_label_mutex);
break;
}
return ret;
}
Expand Down

0 comments on commit b842f8f

Please sign in to comment.