mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 08:38:45 +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 */ | 	/* Check whether the address range is reserved */ | ||||||
| 	if (ftrace_text_reserved(src, src + len - 1) || | 	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 -EBUSY; | ||||||
| 
 | 
 | ||||||
| 	return len; | 	return len; | ||||||
|  |  | ||||||
|  | @ -20,9 +20,10 @@ extern struct jump_entry __stop___jump_table[]; | ||||||
| 
 | 
 | ||||||
| extern void arch_jump_label_transform(struct jump_entry *entry, | extern void arch_jump_label_transform(struct jump_entry *entry, | ||||||
| 				 enum jump_label_type type); | 				 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_update(unsigned long key, enum jump_label_type type); | ||||||
| extern void jump_label_apply_nops(struct module *mod); | 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) \ | #define enable_jump_label(key) \ | ||||||
| 	jump_label_update((unsigned long)key, JUMP_LABEL_ENABLE); | 	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; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static inline int jump_label_text_reserved(void *start, void *end) | ||||||
|  | { | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -177,6 +177,89 @@ void jump_label_update(unsigned long key, enum jump_label_type type) | ||||||
| 	mutex_unlock(&jump_label_mutex); | 	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) | static __init int init_jump_label(void) | ||||||
| { | { | ||||||
| 	int ret; | 	int ret; | ||||||
|  |  | ||||||
|  | @ -1147,7 +1147,8 @@ int __kprobes register_kprobe(struct kprobe *p) | ||||||
| 	preempt_disable(); | 	preempt_disable(); | ||||||
| 	if (!kernel_text_address((unsigned long) p->addr) || | 	if (!kernel_text_address((unsigned long) p->addr) || | ||||||
| 	    in_kprobes_functions((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(); | 		preempt_enable(); | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Jason Baron
						Jason Baron