mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 00:28:52 +02:00 
			
		
		
		
	jump label: Add jump_label_text_reserved() to reserve jump points
Add a jump_label_text_reserved(void *start, void *end), so that other pieces of code that want to modify kernel text, can first verify that jump label has not reserved the instruction. Acked-by: Masami Hiramatsu <mhiramat@redhat.com> Signed-off-by: Jason Baron <jbaron@redhat.com> LKML-Reference: <06236663a3a7b1c1f13576bb9eccb6d9c17b7bfe.1284733808.git.jbaron@redhat.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
This commit is contained in:
		
							parent
							
								
									e0cf0cd496
								
							
						
					
					
						commit
						4c3ef6d793
					
				
					 4 changed files with 94 additions and 3 deletions
				
			
		|  | @ -1218,7 +1218,8 @@ static int __kprobes copy_optimized_instructions(u8 *dest, u8 *src) | |||
| 	} | ||||
| 	/* Check whether the address range is reserved */ | ||||
| 	if (ftrace_text_reserved(src, src + len - 1) || | ||||
| 	    alternatives_text_reserved(src, src + len - 1)) | ||||
| 	    alternatives_text_reserved(src, src + len - 1) || | ||||
| 	    jump_label_text_reserved(src, src + len - 1)) | ||||
| 		return -EBUSY; | ||||
| 
 | ||||
| 	return len; | ||||
|  |  | |||
|  | @ -20,9 +20,10 @@ extern struct jump_entry __stop___jump_table[]; | |||
| 
 | ||||
| extern void arch_jump_label_transform(struct jump_entry *entry, | ||||
| 				 enum jump_label_type type); | ||||
| extern void arch_jump_label_text_poke_early(jump_label_t addr); | ||||
| extern void jump_label_update(unsigned long key, enum jump_label_type type); | ||||
| extern void jump_label_apply_nops(struct module *mod); | ||||
| extern void arch_jump_label_text_poke_early(jump_label_t addr); | ||||
| extern int jump_label_text_reserved(void *start, void *end); | ||||
| 
 | ||||
| #define enable_jump_label(key) \ | ||||
| 	jump_label_update((unsigned long)key, JUMP_LABEL_ENABLE); | ||||
|  | @ -53,6 +54,11 @@ static inline int jump_label_apply_nops(struct module *mod) | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static inline int jump_label_text_reserved(void *start, void *end) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -177,6 +177,89 @@ void jump_label_update(unsigned long key, enum jump_label_type type) | |||
| 	mutex_unlock(&jump_label_mutex); | ||||
| } | ||||
| 
 | ||||
| static int addr_conflict(struct jump_entry *entry, void *start, void *end) | ||||
| { | ||||
| 	if (entry->code <= (unsigned long)end && | ||||
| 		entry->code + JUMP_LABEL_NOP_SIZE > (unsigned long)start) | ||||
| 		return 1; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_MODULES | ||||
| 
 | ||||
| static int module_conflict(void *start, void *end) | ||||
| { | ||||
| 	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; | ||||
| 	int conflict = 0; | ||||
| 
 | ||||
| 	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) { | ||||
| 				count = e_module->nr_entries; | ||||
| 				iter = e_module->table; | ||||
| 				while (count--) { | ||||
| 					if (addr_conflict(iter, start, end)) { | ||||
| 						conflict = 1; | ||||
| 						goto out; | ||||
| 					} | ||||
| 					iter++; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| out: | ||||
| 	return conflict; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| /***
 | ||||
|  * jump_label_text_reserved - check if addr range is reserved | ||||
|  * @start: start text addr | ||||
|  * @end: end text addr | ||||
|  * | ||||
|  * checks if the text addr located between @start and @end | ||||
|  * overlaps with any of the jump label patch addresses. Code | ||||
|  * that wants to modify kernel text should first verify that | ||||
|  * it does not overlap with any of the jump label addresses. | ||||
|  * | ||||
|  * returns 1 if there is an overlap, 0 otherwise | ||||
|  */ | ||||
| int jump_label_text_reserved(void *start, void *end) | ||||
| { | ||||
| 	struct jump_entry *iter; | ||||
| 	struct jump_entry *iter_start = __start___jump_table; | ||||
| 	struct jump_entry *iter_stop = __start___jump_table; | ||||
| 	int conflict = 0; | ||||
| 
 | ||||
| 	mutex_lock(&jump_label_mutex); | ||||
| 	iter = iter_start; | ||||
| 	while (iter < iter_stop) { | ||||
| 		if (addr_conflict(iter, start, end)) { | ||||
| 			conflict = 1; | ||||
| 			goto out; | ||||
| 		} | ||||
| 		iter++; | ||||
| 	} | ||||
| 
 | ||||
| 	/* now check modules */ | ||||
| #ifdef CONFIG_MODULES | ||||
| 	conflict = module_conflict(start, end); | ||||
| #endif | ||||
| out: | ||||
| 	mutex_unlock(&jump_label_mutex); | ||||
| 	return conflict; | ||||
| } | ||||
| 
 | ||||
| static __init int init_jump_label(void) | ||||
| { | ||||
| 	int ret; | ||||
|  |  | |||
|  | @ -1147,7 +1147,8 @@ int __kprobes register_kprobe(struct kprobe *p) | |||
| 	preempt_disable(); | ||||
| 	if (!kernel_text_address((unsigned long) p->addr) || | ||||
| 	    in_kprobes_functions((unsigned long) p->addr) || | ||||
| 	    ftrace_text_reserved(p->addr, p->addr)) { | ||||
| 	    ftrace_text_reserved(p->addr, p->addr) || | ||||
| 	    jump_label_text_reserved(p->addr, p->addr)) { | ||||
| 		preempt_enable(); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Jason Baron
						Jason Baron