forked from mirrors/linux
		
	selftests/bpf: Add test for prealloc_lru_pop bug
Add a regression test to check against invalid check_and_init_map_value call inside prealloc_lru_pop. The kptr should not be reset to NULL once we set it after deleting the map element. Hence, we trigger a program that updates the element causing its reuse, and checks whether the unref kptr is reset or not. If it is, prealloc_lru_pop does an incorrect check_and_init_map_value call and the test fails. Acked-by: Yonghong Song <yhs@fb.com> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Link: https://lore.kernel.org/r/20220809213033.24147-4-memxor@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
		
							parent
							
								
									275c30bcee
								
							
						
					
					
						commit
						de7b992710
					
				
					 2 changed files with 70 additions and 0 deletions
				
			
		
							
								
								
									
										21
									
								
								tools/testing/selftests/bpf/prog_tests/lru_bug.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								tools/testing/selftests/bpf/prog_tests/lru_bug.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | |||
| // SPDX-License-Identifier: GPL-2.0
 | ||||
| #include <test_progs.h> | ||||
| 
 | ||||
| #include "lru_bug.skel.h" | ||||
| 
 | ||||
| void test_lru_bug(void) | ||||
| { | ||||
| 	struct lru_bug *skel; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	skel = lru_bug__open_and_load(); | ||||
| 	if (!ASSERT_OK_PTR(skel, "lru_bug__open_and_load")) | ||||
| 		return; | ||||
| 	ret = lru_bug__attach(skel); | ||||
| 	if (!ASSERT_OK(ret, "lru_bug__attach")) | ||||
| 		goto end; | ||||
| 	usleep(1); | ||||
| 	ASSERT_OK(skel->data->result, "prealloc_lru_pop doesn't call check_and_init_map_value"); | ||||
| end: | ||||
| 	lru_bug__destroy(skel); | ||||
| } | ||||
							
								
								
									
										49
									
								
								tools/testing/selftests/bpf/progs/lru_bug.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								tools/testing/selftests/bpf/progs/lru_bug.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,49 @@ | |||
| // SPDX-License-Identifier: GPL-2.0
 | ||||
| #include <vmlinux.h> | ||||
| #include <bpf/bpf_tracing.h> | ||||
| #include <bpf/bpf_helpers.h> | ||||
| 
 | ||||
| struct map_value { | ||||
| 	struct task_struct __kptr *ptr; | ||||
| }; | ||||
| 
 | ||||
| struct { | ||||
| 	__uint(type, BPF_MAP_TYPE_LRU_HASH); | ||||
| 	__uint(max_entries, 1); | ||||
| 	__type(key, int); | ||||
| 	__type(value, struct map_value); | ||||
| } lru_map SEC(".maps"); | ||||
| 
 | ||||
| int pid = 0; | ||||
| int result = 1; | ||||
| 
 | ||||
| SEC("fentry/bpf_ktime_get_ns") | ||||
| int printk(void *ctx) | ||||
| { | ||||
| 	struct map_value v = {}; | ||||
| 
 | ||||
| 	if (pid == bpf_get_current_task_btf()->pid) | ||||
| 		bpf_map_update_elem(&lru_map, &(int){0}, &v, 0); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| SEC("fentry/do_nanosleep") | ||||
| int nanosleep(void *ctx) | ||||
| { | ||||
| 	struct map_value val = {}, *v; | ||||
| 	struct task_struct *current; | ||||
| 
 | ||||
| 	bpf_map_update_elem(&lru_map, &(int){0}, &val, 0); | ||||
| 	v = bpf_map_lookup_elem(&lru_map, &(int){0}); | ||||
| 	if (!v) | ||||
| 		return 0; | ||||
| 	bpf_map_delete_elem(&lru_map, &(int){0}); | ||||
| 	current = bpf_get_current_task_btf(); | ||||
| 	v->ptr = current; | ||||
| 	pid = current->pid; | ||||
| 	bpf_ktime_get_ns(); | ||||
| 	result = !v->ptr; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| char _license[] SEC("license") = "GPL"; | ||||
		Loading…
	
		Reference in a new issue
	
	 Kumar Kartikeya Dwivedi
						Kumar Kartikeya Dwivedi