1 /* 2 * security/ccsecurity/realpath.c 3 * 4 * Copyright (C) 2005-2012 NTT DATA CORPORATION 5 * 6 * Version: 1.8.11 2024/07/15 7 */ 8 9 #include "internal.h" 10 11 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) && LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) 12 #include <linux/nsproxy.h> 13 #include <linux/mnt_namespace.h> 14 #endif 15 16 /***** SECTION1: Constants definition *****/ 17 18 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) 19 #define s_fs_info u.generic_sbp 20 #endif 21 22 /***** SECTION2: Structure definition *****/ 23 24 /***** SECTION3: Prototype definition section *****/ 25 26 char *ccs_encode(const char *str); 27 char *ccs_encode2(const char *str, int str_len); 28 char *ccs_realpath(const struct path *path); 29 const char *ccs_get_exe(void); 30 void ccs_fill_path_info(struct ccs_path_info *ptr); 31 32 static char *ccs_get_absolute_path(const struct path *path, 33 char * const buffer, const int buflen); 34 static char *ccs_get_dentry_path(struct dentry *dentry, char * const buffer, 35 const int buflen); 36 static char *ccs_get_local_path(struct dentry *dentry, char * const buffer, 37 const int buflen); 38 static int ccs_const_part_length(const char *filename); 39 40 /***** SECTION4: Standalone functions section *****/ 41 42 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) 43 44 /** 45 * ccs_realpath_lock - Take locks for __d_path(). 46 * 47 * Returns nothing. 48 */ 49 static inline void ccs_realpath_lock(void) 50 { 51 /* dcache_lock is locked by __d_path(). */ 52 /* vfsmount_lock is locked by __d_path(). */ 53 } 54 55 /** 56 * ccs_realpath_unlock - Release locks for __d_path(). 57 * 58 * Returns nothing. 59 */ 60 static inline void ccs_realpath_unlock(void) 61 { 62 /* vfsmount_lock is unlocked by __d_path(). */ 63 /* dcache_lock is unlocked by __d_path(). */ 64 } 65 66 #elif LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 36) 67 68 /** 69 * ccs_realpath_lock - Take locks for __d_path(). 70 * 71 * Returns nothing. 72 */ 73 static inline void ccs_realpath_lock(void) 74 { 75 spin_lock(&dcache_lock); 76 /* vfsmount_lock is locked by __d_path(). */ 77 } 78 79 /** 80 * ccs_realpath_unlock - Release locks for __d_path(). 81 * 82 * Returns nothing. 83 */ 84 static inline void ccs_realpath_unlock(void) 85 { 86 /* vfsmount_lock is unlocked by __d_path(). */ 87 spin_unlock(&dcache_lock); 88 } 89 90 #elif defined(D_PATH_DISCONNECT) && !defined(CONFIG_SUSE_KERNEL) 91 92 /** 93 * ccs_realpath_lock - Take locks for __d_path(). 94 * 95 * Returns nothing. 96 * 97 * Original unambiguous-__d_path.diff in patches.apparmor.tar.bz2 inversed the 98 * order of holding dcache_lock and vfsmount_lock. That patch was applied on 99 * (at least) SUSE 11.1 and Ubuntu 8.10 and Ubuntu 9.04 kernels. 100 * 101 * However, that patch was updated to use original order and the updated patch 102 * is applied to (as far as I know) only SUSE kernels. 103 * 104 * Therefore, I need to use original order for SUSE 11.1 kernels and inversed 105 * order for other kernels. I detect it by checking D_PATH_DISCONNECT and 106 * CONFIG_SUSE_KERNEL. I don't know whether other distributions are using the 107 * updated patch or not. If you got deadlock, check fs/dcache.c for locking 108 * order, and add " && 0" to this "#elif " block if fs/dcache.c uses original 109 * order. 110 */ 111 static inline void ccs_realpath_lock(void) 112 { 113 spin_lock(ccsecurity_exports.vfsmount_lock); 114 spin_lock(&dcache_lock); 115 } 116 117 /** 118 * ccs_realpath_unlock - Release locks for __d_path(). 119 * 120 * Returns nothing. 121 */ 122 static inline void ccs_realpath_unlock(void) 123 { 124 spin_unlock(&dcache_lock); 125 spin_unlock(ccsecurity_exports.vfsmount_lock); 126 } 127 128 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) 129 130 /** 131 * ccs_realpath_lock - Take locks for __d_path(). 132 * 133 * Returns nothing. 134 */ 135 static inline void ccs_realpath_lock(void) 136 { 137 spin_lock(&dcache_lock); 138 spin_lock(ccsecurity_exports.vfsmount_lock); 139 } 140 141 /** 142 * ccs_realpath_unlock - Release locks for __d_path(). 143 * 144 * Returns nothing. 145 */ 146 static inline void ccs_realpath_unlock(void) 147 { 148 spin_unlock(ccsecurity_exports.vfsmount_lock); 149 spin_unlock(&dcache_lock); 150 } 151 152 #else 153 154 /** 155 * ccs_realpath_lock - Take locks for __d_path(). 156 * 157 * Returns nothing. 158 */ 159 static inline void ccs_realpath_lock(void) 160 { 161 spin_lock(&dcache_lock); 162 } 163 164 /** 165 * ccs_realpath_unlock - Release locks for __d_path(). 166 * 167 * Returns nothing. 168 */ 169 static inline void ccs_realpath_unlock(void) 170 { 171 spin_unlock(&dcache_lock); 172 } 173 174 #endif 175 176 /***** SECTION5: Variables definition section *****/ 177 178 /***** SECTION6: Dependent functions section *****/ 179 180 /** 181 * ccs_get_absolute_path - Get the path of a dentry but ignores chroot'ed root. 182 * 183 * @path: Pointer to "struct path". 184 * @buffer: Pointer to buffer to return value in. 185 * @buflen: Sizeof @buffer. 186 * 187 * Returns the buffer on success, an error code otherwise. 188 * 189 * Caller holds the dcache_lock and vfsmount_lock. 190 * Based on __d_path() in fs/dcache.c 191 * 192 * If dentry is a directory, trailing '/' is appended. 193 */ 194 static char *ccs_get_absolute_path(const struct path *path, 195 char * const buffer, const int buflen) 196 { 197 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) 198 char *pos = ERR_PTR(-ENOMEM); 199 if (buflen >= 256) { 200 pos = ccsecurity_exports.d_absolute_path(path, buffer, 201 buflen - 1); 202 if (!IS_ERR(pos) && *pos == '/' && pos[1]) { 203 struct inode *inode = d_backing_inode(path->dentry); 204 if (inode && S_ISDIR(inode->i_mode)) { 205 buffer[buflen - 2] = '/'; 206 buffer[buflen - 1] = '\0'; 207 } 208 } 209 } 210 return pos; 211 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) 212 /* 213 * __d_path() will start returning NULL by backporting commit 02125a82 214 * "fix apparmor dereferencing potentially freed dentry, sanitize 215 * __d_path() API". 216 * 217 * Unfortunately, __d_path() after applying that commit always returns 218 * NULL when root is empty. d_absolute_path() is provided for TOMOYO 219 * 2.x and AppArmor but TOMOYO 1.x does not use it, for TOMOYO 1.x 220 * might be built as a loadable kernel module and there is no warrantee 221 * that TOMOYO 1.x is recompiled after applying that commit. Also, 222 * I don't want to search /proc/kallsyms for d_absolute_path() because 223 * I want to keep TOMOYO 1.x architecture independent. Thus, supply 224 * non empty root like AppArmor's d_namespace_path() did. 225 */ 226 char *pos = ERR_PTR(-ENOMEM); 227 if (buflen >= 256) { 228 static bool ccs_no_empty; 229 if (!ccs_no_empty) { 230 struct path root = { }; 231 pos = ccsecurity_exports.__d_path(path, &root, buffer, 232 buflen - 1); 233 } else { 234 pos = NULL; 235 } 236 if (!pos) { 237 struct task_struct *task = current; 238 struct path root; 239 struct path tmp; 240 spin_lock(&task->fs->lock); 241 root.mnt = task->nsproxy->mnt_ns->root; 242 root.dentry = root.mnt->mnt_root; 243 path_get(&root); 244 spin_unlock(&task->fs->lock); 245 tmp = root; 246 pos = ccsecurity_exports.__d_path(path, &tmp, buffer, 247 buflen - 1); 248 path_put(&root); 249 if (!pos) 250 return ERR_PTR(-EINVAL); 251 /* Remember if __d_path() needs non empty root. */ 252 ccs_no_empty = true; 253 } 254 if (!IS_ERR(pos) && *pos == '/' && pos[1]) { 255 struct inode *inode = d_backing_inode(path->dentry); 256 if (inode && S_ISDIR(inode->i_mode)) { 257 buffer[buflen - 2] = '/'; 258 buffer[buflen - 1] = '\0'; 259 } 260 } 261 } 262 return pos; 263 #else 264 char *pos = buffer + buflen - 1; 265 struct dentry *dentry = path->dentry; 266 struct vfsmount *vfsmnt = path->mnt; 267 const char *name; 268 int len; 269 270 if (buflen < 256) 271 goto out; 272 273 *pos = '\0'; 274 if (d_is_dir(dentry)) 275 *--pos = '/'; 276 for (;;) { 277 struct dentry *parent; 278 if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { 279 if (vfsmnt->mnt_parent == vfsmnt) 280 break; 281 dentry = vfsmnt->mnt_mountpoint; 282 vfsmnt = vfsmnt->mnt_parent; 283 continue; 284 } 285 parent = dentry->d_parent; 286 name = dentry->d_name.name; 287 len = dentry->d_name.len; 288 pos -= len; 289 if (pos <= buffer) 290 goto out; 291 memmove(pos, name, len); 292 *--pos = '/'; 293 dentry = parent; 294 } 295 if (*pos == '/') 296 pos++; 297 len = dentry->d_name.len; 298 pos -= len; 299 if (pos < buffer) 300 goto out; 301 memmove(pos, dentry->d_name.name, len); 302 return pos; 303 out: 304 return ERR_PTR(-ENOMEM); 305 #endif 306 } 307 308 /** 309 * ccs_get_dentry_path - Get the path of a dentry. 310 * 311 * @dentry: Pointer to "struct dentry". 312 * @buffer: Pointer to buffer to return value in. 313 * @buflen: Sizeof @buffer. 314 * 315 * Returns the buffer on success, an error code otherwise. 316 * 317 * Based on dentry_path() in fs/dcache.c 318 * 319 * If dentry is a directory, trailing '/' is appended. 320 */ 321 static char *ccs_get_dentry_path(struct dentry *dentry, char * const buffer, 322 const int buflen) 323 { 324 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) 325 char *pos = ERR_PTR(-ENOMEM); 326 if (buflen >= 256) { 327 /* rename_lock is locked/unlocked by dentry_path_raw(). */ 328 pos = dentry_path_raw(dentry, buffer, buflen - 1); 329 if (!IS_ERR(pos) && *pos == '/' && pos[1] && 330 d_is_dir(dentry)) { 331 buffer[buflen - 2] = '/'; 332 buffer[buflen - 1] = '\0'; 333 } 334 } 335 return pos; 336 #else 337 char *pos = buffer + buflen - 1; 338 if (buflen < 256) 339 return ERR_PTR(-ENOMEM); 340 *pos = '\0'; 341 if (d_is_dir(dentry)) 342 *--pos = '/'; 343 spin_lock(&dcache_lock); 344 while (!IS_ROOT(dentry)) { 345 struct dentry *parent = dentry->d_parent; 346 const char *name = dentry->d_name.name; 347 const int len = dentry->d_name.len; 348 pos -= len; 349 if (pos <= buffer) { 350 pos = ERR_PTR(-ENOMEM); 351 break; 352 } 353 memmove(pos, name, len); 354 *--pos = '/'; 355 dentry = parent; 356 } 357 spin_unlock(&dcache_lock); 358 return pos; 359 #endif 360 } 361 362 /** 363 * ccs_get_local_path - Get the path of a dentry. 364 * 365 * @dentry: Pointer to "struct dentry". 366 * @buffer: Pointer to buffer to return value in. 367 * @buflen: Sizeof @buffer. 368 * 369 * Returns the buffer on success, an error code otherwise. 370 */ 371 static char *ccs_get_local_path(struct dentry *dentry, char * const buffer, 372 const int buflen) 373 { 374 struct super_block *sb = dentry->d_sb; 375 char *pos = ccs_get_dentry_path(dentry, buffer, buflen); 376 if (IS_ERR(pos)) 377 return pos; 378 /* Convert from $PID to self if $PID is current thread. */ 379 if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') { 380 char *ep; 381 const pid_t pid = (pid_t) simple_strtoul(pos + 1, &ep, 10); 382 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) 383 if (*ep == '/' && pid && pid == 384 task_tgid_nr_ns(current, proc_pid_ns(sb))) { 385 pos = ep - 5; 386 if (pos < buffer) 387 goto out; 388 memmove(pos, "/self", 5); 389 } 390 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) 391 if (*ep == '/' && pid && pid == 392 task_tgid_nr_ns(current, sb->s_fs_info)) { 393 pos = ep - 5; 394 if (pos < buffer) 395 goto out; 396 memmove(pos, "/self", 5); 397 } 398 #else 399 if (*ep == '/' && pid == ccs_sys_getpid()) { 400 pos = ep - 5; 401 if (pos < buffer) 402 goto out; 403 memmove(pos, "/self", 5); 404 } 405 #endif 406 goto prepend_filesystem_name; 407 } 408 /* Use filesystem name for unnamed devices. */ 409 if (!MAJOR(sb->s_dev)) 410 goto prepend_filesystem_name; 411 { 412 struct inode *inode = d_backing_inode(sb->s_root); 413 /* 414 * Use filesystem name if filesystems does not support rename() 415 * operation. 416 */ 417 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) 418 if (inode->i_op && !inode->i_op->rename) 419 goto prepend_filesystem_name; 420 #elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) 421 if (!inode->i_op->rename && !inode->i_op->rename2) 422 goto prepend_filesystem_name; 423 #else 424 if (!inode->i_op->rename) 425 goto prepend_filesystem_name; 426 #endif 427 } 428 /* Prepend device name. */ 429 { 430 char name[64]; 431 int name_len; 432 const dev_t dev = sb->s_dev; 433 name[sizeof(name) - 1] = '\0'; 434 snprintf(name, sizeof(name) - 1, "dev(%u,%u):", MAJOR(dev), 435 MINOR(dev)); 436 name_len = strlen(name); 437 pos -= name_len; 438 if (pos < buffer) 439 goto out; 440 memmove(pos, name, name_len); 441 return pos; 442 } 443 /* Prepend filesystem name. */ 444 prepend_filesystem_name: 445 { 446 const char *name = sb->s_type->name; 447 const int name_len = strlen(name); 448 pos -= name_len + 1; 449 if (pos < buffer) 450 goto out; 451 memmove(pos, name, name_len); 452 pos[name_len] = ':'; 453 } 454 return pos; 455 out: 456 return ERR_PTR(-ENOMEM); 457 } 458 459 /** 460 * ccs_realpath - Returns realpath(3) of the given pathname but ignores chroot'ed root. 461 * 462 * @path: Pointer to "struct path". 463 * 464 * Returns the realpath of the given @path on success, NULL otherwise. 465 * 466 * This function uses kzalloc(), so caller must kfree() if this function 467 * didn't return NULL. 468 */ 469 char *ccs_realpath(const struct path *path) 470 { 471 char *buf = NULL; 472 char *name = NULL; 473 unsigned int buf_len = PAGE_SIZE / 2; 474 struct dentry *dentry = path->dentry; 475 struct super_block *sb; 476 if (!dentry) 477 return NULL; 478 sb = dentry->d_sb; 479 while (1) { 480 char *pos; 481 struct inode *inode; 482 buf_len <<= 1; 483 kfree(buf); 484 buf = kmalloc(buf_len, CCS_GFP_FLAGS); 485 if (!buf) 486 break; 487 /* To make sure that pos is '\0' terminated. */ 488 buf[buf_len - 1] = '\0'; 489 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) 490 /* For "pipe:[\$]" and "socket:[\$]". */ 491 if (dentry->d_op && dentry->d_op->d_dname) { 492 pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1); 493 goto encode; 494 } 495 #endif 496 inode = d_backing_inode(sb->s_root); 497 /* 498 * Use local name for "filesystems without rename() operation 499 * and device file" or "path without vfsmount" or "absolute 500 * name is unavailable" cases. 501 */ 502 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) 503 if (!path->mnt || 504 (inode->i_op && !inode->i_op->rename && 505 !(sb->s_type->fs_flags & FS_REQUIRES_DEV))) 506 pos = ERR_PTR(-EINVAL); 507 else { 508 /* Get absolute name for the rest. */ 509 ccs_realpath_lock(); 510 pos = ccs_get_absolute_path(path, buf, buf_len - 1); 511 ccs_realpath_unlock(); 512 } 513 #elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) 514 if (!path->mnt || 515 (!inode->i_op->rename && !inode->i_op->rename2 && 516 !(sb->s_type->fs_flags & FS_REQUIRES_DEV))) 517 pos = ERR_PTR(-EINVAL); 518 else 519 pos = ccs_get_absolute_path(path, buf, buf_len - 1); 520 #else 521 if (!path->mnt || 522 (!inode->i_op->rename && 523 !(sb->s_type->fs_flags & FS_REQUIRES_DEV))) 524 pos = ERR_PTR(-EINVAL); 525 else 526 pos = ccs_get_absolute_path(path, buf, buf_len - 1); 527 #endif 528 if (pos == ERR_PTR(-EINVAL)) 529 pos = ccs_get_local_path(path->dentry, buf, 530 buf_len - 1); 531 encode: 532 if (IS_ERR(pos)) 533 continue; 534 name = ccs_encode(pos); 535 break; 536 } 537 kfree(buf); 538 if (!name) 539 ccs_warn_oom(__func__); 540 return name; 541 } 542 543 /** 544 * ccs_encode2 - Encode binary string to ascii string. 545 * 546 * @str: String in binary format. 547 * @str_len: Size of @str in byte. 548 * 549 * Returns pointer to @str in ascii format on success, NULL otherwise. 550 * 551 * This function uses kzalloc(), so caller must kfree() if this function 552 * didn't return NULL. 553 */ 554 char *ccs_encode2(const char *str, int str_len) 555 { 556 int i; 557 int len = 0; 558 const char *p = str; 559 char *cp; 560 char *cp0; 561 if (!p) 562 return NULL; 563 for (i = 0; i < str_len; i++) { 564 const unsigned char c = p[i]; 565 if (c == '\\') 566 len += 2; 567 else if (c > ' ' && c < 127) 568 len++; 569 else 570 len += 4; 571 } 572 len++; 573 /* Reserve space for appending "/". */ 574 cp = kzalloc(len + 10, CCS_GFP_FLAGS); 575 if (!cp) 576 return NULL; 577 cp0 = cp; 578 p = str; 579 for (i = 0; i < str_len; i++) { 580 const unsigned char c = p[i]; 581 if (c == '\\') { 582 *cp++ = '\\'; 583 *cp++ = '\\'; 584 } else if (c > ' ' && c < 127) { 585 *cp++ = c; 586 } else { 587 *cp++ = '\\'; 588 *cp++ = (c >> 6) + ''; 589 *cp++ = ((c >> 3) & 7) + ''; 590 *cp++ = (c & 7) + ''; 591 } 592 } 593 return cp0; 594 } 595 596 /** 597 * ccs_encode - Encode binary string to ascii string. 598 * 599 * @str: String in binary format. 600 * 601 * Returns pointer to @str in ascii format on success, NULL otherwise. 602 * 603 * This function uses kzalloc(), so caller must kfree() if this function 604 * didn't return NULL. 605 */ 606 char *ccs_encode(const char *str) 607 { 608 return str ? ccs_encode2(str, strlen(str)) : NULL; 609 } 610 611 /** 612 * ccs_const_part_length - Evaluate the initial length without a pattern in a token. 613 * 614 * @filename: The string to evaluate. 615 * 616 * Returns the initial length without a pattern in @filename. 617 */ 618 static int ccs_const_part_length(const char *filename) 619 { 620 char c; 621 int len = 0; 622 if (!filename) 623 return 0; 624 while (1) { 625 c = *filename++; 626 if (!c) 627 break; 628 if (c != '\\') { 629 len++; 630 continue; 631 } 632 c = *filename++; 633 switch (c) { 634 case '\\': /* "\\" */ 635 len += 2; 636 continue; 637 case '': /* "\ooo" */ 638 case '1': 639 case '2': 640 case '3': 641 c = *filename++; 642 if (c < '' || c > '7') 643 break; 644 c = *filename++; 645 if (c < '' || c > '7') 646 break; 647 len += 4; 648 continue; 649 } 650 break; 651 } 652 return len; 653 } 654 655 /** 656 * ccs_fill_path_info - Fill in "struct ccs_path_info" members. 657 * 658 * @ptr: Pointer to "struct ccs_path_info" to fill in. 659 * 660 * The caller sets "struct ccs_path_info"->name. 661 */ 662 void ccs_fill_path_info(struct ccs_path_info *ptr) 663 { 664 const char *name = ptr->name; 665 const int len = strlen(name); 666 ptr->total_len = len; 667 ptr->const_len = ccs_const_part_length(name); 668 ptr->is_dir = len && (name[len - 1] == '/'); 669 ptr->is_patterned = (ptr->const_len < len); 670 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0) 671 ptr->hash = full_name_hash(NULL, name, len); 672 #else 673 ptr->hash = full_name_hash(name, len); 674 #endif 675 } 676 677 /** 678 * ccs_get_exe - Get ccs_realpath() of current process. 679 * 680 * Returns the ccs_realpath() of current process on success, NULL otherwise. 681 * 682 * This function uses kzalloc(), so the caller must kfree() 683 * if this function didn't return NULL. 684 */ 685 const char *ccs_get_exe(void) 686 { 687 struct mm_struct *mm = current->mm; 688 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) 689 struct vm_area_struct *vma; 690 #endif 691 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) 692 struct path path; 693 #endif 694 struct file *exe_file = NULL; 695 const char *cp; 696 if (!mm) 697 return NULL; 698 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) 699 if (current->flags & PF_KTHREAD) 700 return NULL; 701 #else 702 if (segment_eq(get_fs(), KERNEL_DS)) 703 return NULL; 704 #endif 705 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) 706 /* Not using get_mm_exe_file() as it is not exported. */ 707 rcu_read_lock(); 708 exe_file = rcu_dereference(mm->exe_file); 709 #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0) 710 if (exe_file && !get_file_rcu(&exe_file)) 711 exe_file = NULL; 712 #else 713 if (exe_file && !get_file_rcu(exe_file)) 714 exe_file = NULL; 715 #endif 716 rcu_read_unlock(); 717 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) 718 exe_file = get_mm_exe_file(mm); 719 #else 720 down_read(&mm->mmap_sem); 721 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) 722 /* Not using get_mm_exe_file() as it is not exported. */ 723 exe_file = mm->exe_file; 724 #else 725 for (vma = mm->mmap; vma; vma = vma->vm_next) { 726 if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) { 727 exe_file = vma->vm_file; 728 break; 729 } 730 } 731 #endif 732 if (exe_file) 733 get_file(exe_file); 734 up_read(&mm->mmap_sem); 735 #endif 736 if (!exe_file) 737 return NULL; 738 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) 739 cp = ccs_realpath(&exe_file->f_path); 740 #else 741 path.mnt = exe_file->f_vfsmnt; 742 path.dentry = exe_file->f_dentry; 743 cp = ccs_realpath(&path); 744 #endif 745 fput(exe_file); 746 return cp; 747 } 748
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.