Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only 2 : : /* 3 : : * dcookies.c 4 : : * 5 : : * Copyright 2002 John Levon <levon@movementarian.org> 6 : : * 7 : : * Persistent cookie-path mappings. These are used by 8 : : * profilers to convert a per-task EIP value into something 9 : : * non-transitory that can be processed at a later date. 10 : : * This is done by locking the dentry/vfsmnt pair in the 11 : : * kernel until released by the tasks needing the persistent 12 : : * objects. The tag is simply an unsigned long that refers 13 : : * to the pair and can be looked up from userspace. 14 : : */ 15 : : 16 : : #include <linux/syscalls.h> 17 : : #include <linux/export.h> 18 : : #include <linux/slab.h> 19 : : #include <linux/list.h> 20 : : #include <linux/mount.h> 21 : : #include <linux/capability.h> 22 : : #include <linux/dcache.h> 23 : : #include <linux/mm.h> 24 : : #include <linux/err.h> 25 : : #include <linux/errno.h> 26 : : #include <linux/dcookies.h> 27 : : #include <linux/mutex.h> 28 : : #include <linux/path.h> 29 : : #include <linux/compat.h> 30 : : #include <linux/uaccess.h> 31 : : 32 : : /* The dcookies are allocated from a kmem_cache and 33 : : * hashed onto a small number of lists. None of the 34 : : * code here is particularly performance critical 35 : : */ 36 : : struct dcookie_struct { 37 : : struct path path; 38 : : struct list_head hash_list; 39 : : }; 40 : : 41 : : static LIST_HEAD(dcookie_users); 42 : : static DEFINE_MUTEX(dcookie_mutex); 43 : : static struct kmem_cache *dcookie_cache __read_mostly; 44 : : static struct list_head *dcookie_hashtable __read_mostly; 45 : : static size_t hash_size __read_mostly; 46 : : 47 : : static inline int is_live(void) 48 : : { 49 : : return !(list_empty(&dcookie_users)); 50 : : } 51 : : 52 : : 53 : : /* The dentry is locked, its address will do for the cookie */ 54 : : static inline unsigned long dcookie_value(struct dcookie_struct * dcs) 55 : : { 56 : 0 : return (unsigned long)dcs->path.dentry; 57 : : } 58 : : 59 : : 60 : : static size_t dcookie_hash(unsigned long dcookie) 61 : : { 62 : 0 : return (dcookie >> L1_CACHE_SHIFT) & (hash_size - 1); 63 : : } 64 : : 65 : : 66 : 0 : static struct dcookie_struct * find_dcookie(unsigned long dcookie) 67 : : { 68 : : struct dcookie_struct *found = NULL; 69 : : struct dcookie_struct * dcs; 70 : : struct list_head * pos; 71 : : struct list_head * list; 72 : : 73 : 0 : list = dcookie_hashtable + dcookie_hash(dcookie); 74 : : 75 : 0 : list_for_each(pos, list) { 76 : 0 : dcs = list_entry(pos, struct dcookie_struct, hash_list); 77 : 0 : if (dcookie_value(dcs) == dcookie) { 78 : 0 : found = dcs; 79 : 0 : break; 80 : : } 81 : : } 82 : : 83 : 0 : return found; 84 : : } 85 : : 86 : : 87 : : static void hash_dcookie(struct dcookie_struct * dcs) 88 : : { 89 : 0 : struct list_head * list = dcookie_hashtable + dcookie_hash(dcookie_value(dcs)); 90 : 0 : list_add(&dcs->hash_list, list); 91 : : } 92 : : 93 : : 94 : 0 : static struct dcookie_struct *alloc_dcookie(const struct path *path) 95 : : { 96 : 0 : struct dcookie_struct *dcs = kmem_cache_alloc(dcookie_cache, 97 : : GFP_KERNEL); 98 : : struct dentry *d; 99 : 0 : if (!dcs) 100 : : return NULL; 101 : : 102 : 0 : d = path->dentry; 103 : : spin_lock(&d->d_lock); 104 : 0 : d->d_flags |= DCACHE_COOKIE; 105 : : spin_unlock(&d->d_lock); 106 : : 107 : 0 : dcs->path = *path; 108 : 0 : path_get(path); 109 : : hash_dcookie(dcs); 110 : 0 : return dcs; 111 : : } 112 : : 113 : : 114 : : /* This is the main kernel-side routine that retrieves the cookie 115 : : * value for a dentry/vfsmnt pair. 116 : : */ 117 : 0 : int get_dcookie(const struct path *path, unsigned long *cookie) 118 : : { 119 : : int err = 0; 120 : : struct dcookie_struct * dcs; 121 : : 122 : 0 : mutex_lock(&dcookie_mutex); 123 : : 124 : 0 : if (!is_live()) { 125 : : err = -EINVAL; 126 : : goto out; 127 : : } 128 : : 129 : 0 : if (path->dentry->d_flags & DCACHE_COOKIE) { 130 : 0 : dcs = find_dcookie((unsigned long)path->dentry); 131 : : } else { 132 : 0 : dcs = alloc_dcookie(path); 133 : 0 : if (!dcs) { 134 : : err = -ENOMEM; 135 : : goto out; 136 : : } 137 : : } 138 : : 139 : 0 : *cookie = dcookie_value(dcs); 140 : : 141 : : out: 142 : 0 : mutex_unlock(&dcookie_mutex); 143 : 0 : return err; 144 : : } 145 : : 146 : : 147 : : /* And here is where the userspace process can look up the cookie value 148 : : * to retrieve the path. 149 : : */ 150 : 0 : static int do_lookup_dcookie(u64 cookie64, char __user *buf, size_t len) 151 : : { 152 : 0 : unsigned long cookie = (unsigned long)cookie64; 153 : : int err = -EINVAL; 154 : : char * kbuf; 155 : : char * path; 156 : : size_t pathlen; 157 : : struct dcookie_struct * dcs; 158 : : 159 : : /* we could leak path information to users 160 : : * without dir read permission without this 161 : : */ 162 : 0 : if (!capable(CAP_SYS_ADMIN)) 163 : : return -EPERM; 164 : : 165 : 0 : mutex_lock(&dcookie_mutex); 166 : : 167 : 0 : if (!is_live()) { 168 : : err = -EINVAL; 169 : : goto out; 170 : : } 171 : : 172 : 0 : if (!(dcs = find_dcookie(cookie))) 173 : : goto out; 174 : : 175 : : err = -ENOMEM; 176 : : kbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); 177 : 0 : if (!kbuf) 178 : : goto out; 179 : : 180 : : /* FIXME: (deleted) ? */ 181 : 0 : path = d_path(&dcs->path, kbuf, PAGE_SIZE); 182 : : 183 : 0 : mutex_unlock(&dcookie_mutex); 184 : : 185 : 0 : if (IS_ERR(path)) { 186 : : err = PTR_ERR(path); 187 : 0 : goto out_free; 188 : : } 189 : : 190 : : err = -ERANGE; 191 : : 192 : 0 : pathlen = kbuf + PAGE_SIZE - path; 193 : 0 : if (pathlen <= len) { 194 : : err = pathlen; 195 : 0 : if (copy_to_user(buf, path, pathlen)) 196 : : err = -EFAULT; 197 : : } 198 : : 199 : : out_free: 200 : 0 : kfree(kbuf); 201 : 0 : return err; 202 : : out: 203 : 0 : mutex_unlock(&dcookie_mutex); 204 : 0 : return err; 205 : : } 206 : : 207 : 0 : SYSCALL_DEFINE3(lookup_dcookie, u64, cookie64, char __user *, buf, size_t, len) 208 : : { 209 : 0 : return do_lookup_dcookie(cookie64, buf, len); 210 : : } 211 : : 212 : : #ifdef CONFIG_COMPAT 213 : : COMPAT_SYSCALL_DEFINE4(lookup_dcookie, u32, w0, u32, w1, char __user *, buf, compat_size_t, len) 214 : : { 215 : : #ifdef __BIG_ENDIAN 216 : : return do_lookup_dcookie(((u64)w0 << 32) | w1, buf, len); 217 : : #else 218 : : return do_lookup_dcookie(((u64)w1 << 32) | w0, buf, len); 219 : : #endif 220 : : } 221 : : #endif 222 : : 223 : 0 : static int dcookie_init(void) 224 : : { 225 : : struct list_head * d; 226 : : unsigned int i, hash_bits; 227 : : int err = -ENOMEM; 228 : : 229 : 0 : dcookie_cache = kmem_cache_create("dcookie_cache", 230 : : sizeof(struct dcookie_struct), 231 : : 0, 0, NULL); 232 : : 233 : 0 : if (!dcookie_cache) 234 : : goto out; 235 : : 236 : 0 : dcookie_hashtable = kmalloc(PAGE_SIZE, GFP_KERNEL); 237 : 0 : if (!dcookie_hashtable) 238 : : goto out_kmem; 239 : : 240 : : err = 0; 241 : : 242 : : /* 243 : : * Find the power-of-two list-heads that can fit into the allocation.. 244 : : * We don't guarantee that "sizeof(struct list_head)" is necessarily 245 : : * a power-of-two. 246 : : */ 247 : 0 : hash_size = PAGE_SIZE / sizeof(struct list_head); 248 : : hash_bits = 0; 249 : : do { 250 : 0 : hash_bits++; 251 : 0 : } while ((hash_size >> hash_bits) != 0); 252 : 0 : hash_bits--; 253 : : 254 : : /* 255 : : * Re-calculate the actual number of entries and the mask 256 : : * from the number of bits we can fit. 257 : : */ 258 : 0 : hash_size = 1UL << hash_bits; 259 : : 260 : : /* And initialize the newly allocated array */ 261 : : d = dcookie_hashtable; 262 : : i = hash_size; 263 : : do { 264 : : INIT_LIST_HEAD(d); 265 : 0 : d++; 266 : 0 : i--; 267 : 0 : } while (i); 268 : : 269 : : out: 270 : 0 : return err; 271 : : out_kmem: 272 : 0 : kmem_cache_destroy(dcookie_cache); 273 : 0 : goto out; 274 : : } 275 : : 276 : : 277 : 0 : static void free_dcookie(struct dcookie_struct * dcs) 278 : : { 279 : 0 : struct dentry *d = dcs->path.dentry; 280 : : 281 : : spin_lock(&d->d_lock); 282 : 0 : d->d_flags &= ~DCACHE_COOKIE; 283 : : spin_unlock(&d->d_lock); 284 : : 285 : 0 : path_put(&dcs->path); 286 : 0 : kmem_cache_free(dcookie_cache, dcs); 287 : 0 : } 288 : : 289 : : 290 : 0 : static void dcookie_exit(void) 291 : : { 292 : : struct list_head * list; 293 : : struct list_head * pos; 294 : : struct list_head * pos2; 295 : : struct dcookie_struct * dcs; 296 : : size_t i; 297 : : 298 : 0 : for (i = 0; i < hash_size; ++i) { 299 : 0 : list = dcookie_hashtable + i; 300 : 0 : list_for_each_safe(pos, pos2, list) { 301 : 0 : dcs = list_entry(pos, struct dcookie_struct, hash_list); 302 : : list_del(&dcs->hash_list); 303 : 0 : free_dcookie(dcs); 304 : : } 305 : : } 306 : : 307 : 0 : kfree(dcookie_hashtable); 308 : 0 : kmem_cache_destroy(dcookie_cache); 309 : 0 : } 310 : : 311 : : 312 : : struct dcookie_user { 313 : : struct list_head next; 314 : : }; 315 : : 316 : 0 : struct dcookie_user * dcookie_register(void) 317 : : { 318 : : struct dcookie_user * user; 319 : : 320 : 0 : mutex_lock(&dcookie_mutex); 321 : : 322 : : user = kmalloc(sizeof(struct dcookie_user), GFP_KERNEL); 323 : 0 : if (!user) 324 : : goto out; 325 : : 326 : 0 : if (!is_live() && dcookie_init()) 327 : : goto out_free; 328 : : 329 : 0 : list_add(&user->next, &dcookie_users); 330 : : 331 : : out: 332 : 0 : mutex_unlock(&dcookie_mutex); 333 : 0 : return user; 334 : : out_free: 335 : 0 : kfree(user); 336 : : user = NULL; 337 : 0 : goto out; 338 : : } 339 : : 340 : : 341 : 0 : void dcookie_unregister(struct dcookie_user * user) 342 : : { 343 : 0 : mutex_lock(&dcookie_mutex); 344 : : 345 : : list_del(&user->next); 346 : 0 : kfree(user); 347 : : 348 : 0 : if (!is_live()) 349 : 0 : dcookie_exit(); 350 : : 351 : 0 : mutex_unlock(&dcookie_mutex); 352 : 0 : } 353 : : 354 : : EXPORT_SYMBOL_GPL(dcookie_register); 355 : : EXPORT_SYMBOL_GPL(dcookie_unregister); 356 : : EXPORT_SYMBOL_GPL(get_dcookie);