Skip to content

Commit d8792a5

Browse files
charlie-rivospalmer-dabbelt
authored andcommitted
riscv: Safely remove entries from relocation list
Use the safe versions of list and hlist iteration to safely remove entries from the module relocation lists. To allow mutliple threads to load modules concurrently, move relocation list pointers onto the stack rather than using global variables. Fixes: 8fd6c51 ("riscv: Add remaining module relocations") Reported-by: Ron Economos <[email protected]> Closes: https://lore.kernel.org/linux-riscv/[email protected] Signed-off-by: Charlie Jenkins <[email protected]> Tested-by: Björn Töpel <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent b85ea95 commit d8792a5

File tree

1 file changed

+82
-28
lines changed

1 file changed

+82
-28
lines changed

arch/riscv/kernel/module.c

Lines changed: 82 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,6 @@ struct relocation_handlers {
4040
long buffer);
4141
};
4242

43-
unsigned int initialize_relocation_hashtable(unsigned int num_relocations);
44-
void process_accumulated_relocations(struct module *me);
45-
int add_relocation_to_accumulate(struct module *me, int type, void *location,
46-
unsigned int hashtable_bits, Elf_Addr v);
47-
48-
struct hlist_head *relocation_hashtable;
49-
50-
struct list_head used_buckets_list;
51-
5243
/*
5344
* The auipc+jalr instruction pair can reach any PC-relative offset
5445
* in the range [-2^31 - 2^11, 2^31 - 2^11)
@@ -604,7 +595,10 @@ static const struct relocation_handlers reloc_handlers[] = {
604595
/* 192-255 nonstandard ABI extensions */
605596
};
606597

607-
void process_accumulated_relocations(struct module *me)
598+
static void
599+
process_accumulated_relocations(struct module *me,
600+
struct hlist_head **relocation_hashtable,
601+
struct list_head *used_buckets_list)
608602
{
609603
/*
610604
* Only ADD/SUB/SET/ULEB128 should end up here.
@@ -624,18 +618,25 @@ void process_accumulated_relocations(struct module *me)
624618
* - Each relocation entry for a location address
625619
*/
626620
struct used_bucket *bucket_iter;
621+
struct used_bucket *bucket_iter_tmp;
627622
struct relocation_head *rel_head_iter;
623+
struct hlist_node *rel_head_iter_tmp;
628624
struct relocation_entry *rel_entry_iter;
625+
struct relocation_entry *rel_entry_iter_tmp;
629626
int curr_type;
630627
void *location;
631628
long buffer;
632629

633-
list_for_each_entry(bucket_iter, &used_buckets_list, head) {
634-
hlist_for_each_entry(rel_head_iter, bucket_iter->bucket, node) {
630+
list_for_each_entry_safe(bucket_iter, bucket_iter_tmp,
631+
used_buckets_list, head) {
632+
hlist_for_each_entry_safe(rel_head_iter, rel_head_iter_tmp,
633+
bucket_iter->bucket, node) {
635634
buffer = 0;
636635
location = rel_head_iter->location;
637-
list_for_each_entry(rel_entry_iter,
638-
rel_head_iter->rel_entry, head) {
636+
list_for_each_entry_safe(rel_entry_iter,
637+
rel_entry_iter_tmp,
638+
rel_head_iter->rel_entry,
639+
head) {
639640
curr_type = rel_entry_iter->type;
640641
reloc_handlers[curr_type].reloc_handler(
641642
me, &buffer, rel_entry_iter->value);
@@ -648,11 +649,14 @@ void process_accumulated_relocations(struct module *me)
648649
kfree(bucket_iter);
649650
}
650651

651-
kfree(relocation_hashtable);
652+
kfree(*relocation_hashtable);
652653
}
653654

654-
int add_relocation_to_accumulate(struct module *me, int type, void *location,
655-
unsigned int hashtable_bits, Elf_Addr v)
655+
static int add_relocation_to_accumulate(struct module *me, int type,
656+
void *location,
657+
unsigned int hashtable_bits, Elf_Addr v,
658+
struct hlist_head *relocation_hashtable,
659+
struct list_head *used_buckets_list)
656660
{
657661
struct relocation_entry *entry;
658662
struct relocation_head *rel_head;
@@ -661,6 +665,10 @@ int add_relocation_to_accumulate(struct module *me, int type, void *location,
661665
unsigned long hash;
662666

663667
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
668+
669+
if (!entry)
670+
return -ENOMEM;
671+
664672
INIT_LIST_HEAD(&entry->head);
665673
entry->type = type;
666674
entry->value = v;
@@ -669,7 +677,10 @@ int add_relocation_to_accumulate(struct module *me, int type, void *location,
669677

670678
current_head = &relocation_hashtable[hash];
671679

672-
/* Find matching location (if any) */
680+
/*
681+
* Search for the relocation_head for the relocations that happen at the
682+
* provided location
683+
*/
673684
bool found = false;
674685
struct relocation_head *rel_head_iter;
675686

@@ -681,19 +692,45 @@ int add_relocation_to_accumulate(struct module *me, int type, void *location,
681692
}
682693
}
683694

695+
/*
696+
* If there has not yet been any relocations at the provided location,
697+
* create a relocation_head for that location and populate it with this
698+
* relocation_entry.
699+
*/
684700
if (!found) {
685701
rel_head = kmalloc(sizeof(*rel_head), GFP_KERNEL);
702+
703+
if (!rel_head) {
704+
kfree(entry);
705+
return -ENOMEM;
706+
}
707+
686708
rel_head->rel_entry =
687709
kmalloc(sizeof(struct list_head), GFP_KERNEL);
710+
711+
if (!rel_head->rel_entry) {
712+
kfree(entry);
713+
kfree(rel_head);
714+
return -ENOMEM;
715+
}
716+
688717
INIT_LIST_HEAD(rel_head->rel_entry);
689718
rel_head->location = location;
690719
INIT_HLIST_NODE(&rel_head->node);
691720
if (!current_head->first) {
692721
bucket =
693722
kmalloc(sizeof(struct used_bucket), GFP_KERNEL);
723+
724+
if (!bucket) {
725+
kfree(entry);
726+
kfree(rel_head);
727+
kfree(rel_head->rel_entry);
728+
return -ENOMEM;
729+
}
730+
694731
INIT_LIST_HEAD(&bucket->head);
695732
bucket->bucket = current_head;
696-
list_add(&bucket->head, &used_buckets_list);
733+
list_add(&bucket->head, used_buckets_list);
697734
}
698735
hlist_add_head(&rel_head->node, current_head);
699736
}
@@ -704,7 +741,9 @@ int add_relocation_to_accumulate(struct module *me, int type, void *location,
704741
return 0;
705742
}
706743

707-
unsigned int initialize_relocation_hashtable(unsigned int num_relocations)
744+
static unsigned int
745+
initialize_relocation_hashtable(unsigned int num_relocations,
746+
struct hlist_head **relocation_hashtable)
708747
{
709748
/* Can safely assume that bits is not greater than sizeof(long) */
710749
unsigned long hashtable_size = roundup_pow_of_two(num_relocations);
@@ -720,12 +759,13 @@ unsigned int initialize_relocation_hashtable(unsigned int num_relocations)
720759

721760
hashtable_size <<= should_double_size;
722761

723-
relocation_hashtable = kmalloc_array(hashtable_size,
724-
sizeof(*relocation_hashtable),
725-
GFP_KERNEL);
726-
__hash_init(relocation_hashtable, hashtable_size);
762+
*relocation_hashtable = kmalloc_array(hashtable_size,
763+
sizeof(*relocation_hashtable),
764+
GFP_KERNEL);
765+
if (!*relocation_hashtable)
766+
return -ENOMEM;
727767

728-
INIT_LIST_HEAD(&used_buckets_list);
768+
__hash_init(*relocation_hashtable, hashtable_size);
729769

730770
return hashtable_bits;
731771
}
@@ -742,7 +782,17 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
742782
Elf_Addr v;
743783
int res;
744784
unsigned int num_relocations = sechdrs[relsec].sh_size / sizeof(*rel);
745-
unsigned int hashtable_bits = initialize_relocation_hashtable(num_relocations);
785+
struct hlist_head *relocation_hashtable;
786+
struct list_head used_buckets_list;
787+
unsigned int hashtable_bits;
788+
789+
hashtable_bits = initialize_relocation_hashtable(num_relocations,
790+
&relocation_hashtable);
791+
792+
if (hashtable_bits < 0)
793+
return hashtable_bits;
794+
795+
INIT_LIST_HEAD(&used_buckets_list);
746796

747797
pr_debug("Applying relocate section %u to %u\n", relsec,
748798
sechdrs[relsec].sh_info);
@@ -823,14 +873,18 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
823873
}
824874

825875
if (reloc_handlers[type].accumulate_handler)
826-
res = add_relocation_to_accumulate(me, type, location, hashtable_bits, v);
876+
res = add_relocation_to_accumulate(me, type, location,
877+
hashtable_bits, v,
878+
relocation_hashtable,
879+
&used_buckets_list);
827880
else
828881
res = handler(me, location, v);
829882
if (res)
830883
return res;
831884
}
832885

833-
process_accumulated_relocations(me);
886+
process_accumulated_relocations(me, &relocation_hashtable,
887+
&used_buckets_list);
834888

835889
return 0;
836890
}

0 commit comments

Comments
 (0)