| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/file_util.h" | 5 #include "base/file_util.h" |
| 6 | 6 |
| 7 #include <dirent.h> | 7 #include <dirent.h> |
| 8 #include <errno.h> | 8 #include <errno.h> |
| 9 #include <fcntl.h> | 9 #include <fcntl.h> |
| 10 #include <libgen.h> | 10 #include <libgen.h> |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 return StringPrintf(".%s.XXXXXX", base::mac::BaseBundleID()); | 143 return StringPrintf(".%s.XXXXXX", base::mac::BaseBundleID()); |
| 144 #endif | 144 #endif |
| 145 | 145 |
| 146 #if defined(GOOGLE_CHROME_BUILD) | 146 #if defined(GOOGLE_CHROME_BUILD) |
| 147 return std::string(".com.google.Chrome.XXXXXX"); | 147 return std::string(".com.google.Chrome.XXXXXX"); |
| 148 #else | 148 #else |
| 149 return std::string(".org.chromium.Chromium.XXXXXX"); | 149 return std::string(".org.chromium.Chromium.XXXXXX"); |
| 150 #endif | 150 #endif |
| 151 } | 151 } |
| 152 | 152 |
| 153 // Creates and opens a temporary file in |directory|, returning the |
| 154 // file descriptor. |path| is set to the temporary file path. |
| 155 // This function does NOT unlink() the file. |
| 156 int CreateAndOpenFdForTemporaryFile(FilePath directory, FilePath* path) { |
| 157 ThreadRestrictions::AssertIOAllowed(); // For call to mkstemp(). |
| 158 *path = directory.Append(base::TempFileName()); |
| 159 const std::string& tmpdir_string = path->value(); |
| 160 // this should be OK since mkstemp just replaces characters in place |
| 161 char* buffer = const_cast<char*>(tmpdir_string.c_str()); |
| 162 |
| 163 return HANDLE_EINTR(mkstemp(buffer)); |
| 164 } |
| 165 |
| 166 #if defined(OS_LINUX) |
| 167 // Determine if /dev/shm files can be mapped and then mprotect'd PROT_EXEC. |
| 168 // This depends on the mount options used for /dev/shm, which vary among |
| 169 // different Linux distributions and possibly local configuration. It also |
| 170 // depends on details of kernel--ChromeOS uses the noexec option for /dev/shm |
| 171 // but its kernel allows mprotect with PROT_EXEC anyway. |
| 172 bool DetermineDevShmExecutable() { |
| 173 bool result = false; |
| 174 FilePath path; |
| 175 int fd = CreateAndOpenFdForTemporaryFile(FilePath("/dev/shm"), &path); |
| 176 if (fd >= 0) { |
| 177 file_util::ScopedFD shm_fd_closer(&fd); |
| 178 DeleteFile(path, false); |
| 179 long sysconf_result = sysconf(_SC_PAGESIZE); |
| 180 CHECK_GE(sysconf_result, 0); |
| 181 size_t pagesize = static_cast<size_t>(sysconf_result); |
| 182 CHECK_GE(sizeof(pagesize), sizeof(sysconf_result)); |
| 183 void *mapping = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, fd, 0); |
| 184 if (mapping != MAP_FAILED) { |
| 185 if (mprotect(mapping, pagesize, PROT_READ | PROT_EXEC) == 0) |
| 186 result = true; |
| 187 munmap(mapping, pagesize); |
| 188 } |
| 189 } |
| 190 return result; |
| 191 } |
| 192 #endif // defined(OS_LINUX) |
| 193 |
| 153 } // namespace | 194 } // namespace |
| 154 | 195 |
| 155 FilePath MakeAbsoluteFilePath(const FilePath& input) { | 196 FilePath MakeAbsoluteFilePath(const FilePath& input) { |
| 156 ThreadRestrictions::AssertIOAllowed(); | 197 ThreadRestrictions::AssertIOAllowed(); |
| 157 char full_path[PATH_MAX]; | 198 char full_path[PATH_MAX]; |
| 158 if (realpath(input.value().c_str(), full_path) == NULL) | 199 if (realpath(input.value().c_str(), full_path) == NULL) |
| 159 return FilePath(); | 200 return FilePath(); |
| 160 return FilePath(full_path); | 201 return FilePath(full_path); |
| 161 } | 202 } |
| 162 | 203 |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 398 // Clears the existing permission bits, and adds the new ones. | 439 // Clears the existing permission bits, and adds the new ones. |
| 399 mode_t updated_mode_bits = stat_buf.st_mode & ~FILE_PERMISSION_MASK; | 440 mode_t updated_mode_bits = stat_buf.st_mode & ~FILE_PERMISSION_MASK; |
| 400 updated_mode_bits |= mode & FILE_PERMISSION_MASK; | 441 updated_mode_bits |= mode & FILE_PERMISSION_MASK; |
| 401 | 442 |
| 402 if (HANDLE_EINTR(chmod(path.value().c_str(), updated_mode_bits)) != 0) | 443 if (HANDLE_EINTR(chmod(path.value().c_str(), updated_mode_bits)) != 0) |
| 403 return false; | 444 return false; |
| 404 | 445 |
| 405 return true; | 446 return true; |
| 406 } | 447 } |
| 407 | 448 |
| 449 #if !defined(OS_MACOSX) |
| 450 // This is implemented in file_util_mac.mm for Mac. |
| 451 bool GetTempDir(FilePath* path) { |
| 452 const char* tmp = getenv("TMPDIR"); |
| 453 if (tmp) { |
| 454 *path = FilePath(tmp); |
| 455 } else { |
| 456 #if defined(OS_ANDROID) |
| 457 return PathService::Get(base::DIR_CACHE, path); |
| 458 #else |
| 459 *path = FilePath("/tmp"); |
| 460 #endif |
| 461 } |
| 462 return true; |
| 463 } |
| 464 #endif // !defined(OS_MACOSX) |
| 465 |
| 466 #if !defined(OS_MACOSX) && !defined(OS_ANDROID) |
| 467 // This is implemented in file_util_mac.mm and file_util_android.cc for those |
| 468 // platforms. |
| 469 bool GetShmemTempDir(bool executable, FilePath* path) { |
| 470 #if defined(OS_LINUX) |
| 471 bool use_dev_shm = true; |
| 472 if (executable) { |
| 473 static const bool s_dev_shm_executable = DetermineDevShmExecutable(); |
| 474 use_dev_shm = s_dev_shm_executable; |
| 475 } |
| 476 if (use_dev_shm) { |
| 477 *path = FilePath("/dev/shm"); |
| 478 return true; |
| 479 } |
| 480 #endif |
| 481 return GetTempDir(path); |
| 482 } |
| 483 #endif // !defined(OS_MACOSX) && !defined(OS_ANDROID) |
| 484 |
| 485 #if !defined(OS_MACOSX) |
| 486 FilePath GetHomeDir() { |
| 487 #if defined(OS_CHROMEOS) |
| 488 if (SysInfo::IsRunningOnChromeOS()) |
| 489 return FilePath("/home/chronos/user"); |
| 490 #endif |
| 491 |
| 492 const char* home_dir = getenv("HOME"); |
| 493 if (home_dir && home_dir[0]) |
| 494 return FilePath(home_dir); |
| 495 |
| 496 #if defined(OS_ANDROID) |
| 497 DLOG(WARNING) << "OS_ANDROID: Home directory lookup not yet implemented."; |
| 498 #elif defined(USE_GLIB) && !defined(OS_CHROMEOS) |
| 499 // g_get_home_dir calls getpwent, which can fall through to LDAP calls. |
| 500 ThreadRestrictions::AssertIOAllowed(); |
| 501 |
| 502 home_dir = g_get_home_dir(); |
| 503 if (home_dir && home_dir[0]) |
| 504 return FilePath(home_dir); |
| 505 #endif |
| 506 |
| 507 FilePath rv; |
| 508 if (GetTempDir(&rv)) |
| 509 return rv; |
| 510 |
| 511 // Last resort. |
| 512 return FilePath("/tmp"); |
| 513 } |
| 514 #endif // !defined(OS_MACOSX) |
| 515 |
| 408 } // namespace base | 516 } // namespace base |
| 409 | 517 |
| 410 // ----------------------------------------------------------------------------- | 518 // ----------------------------------------------------------------------------- |
| 411 | 519 |
| 412 namespace file_util { | 520 namespace file_util { |
| 413 | 521 |
| 414 using base::stat_wrapper_t; | 522 using base::stat_wrapper_t; |
| 415 using base::CallStat; | 523 using base::CallStat; |
| 416 using base::CallLstat; | 524 using base::CallLstat; |
| 525 using base::CreateAndOpenFdForTemporaryFile; |
| 417 using base::DirectoryExists; | 526 using base::DirectoryExists; |
| 418 using base::FileEnumerator; | 527 using base::FileEnumerator; |
| 419 using base::FilePath; | 528 using base::FilePath; |
| 420 using base::MakeAbsoluteFilePath; | 529 using base::MakeAbsoluteFilePath; |
| 421 using base::RealPath; | 530 using base::RealPath; |
| 422 using base::VerifySpecificPathControlledByUser; | 531 using base::VerifySpecificPathControlledByUser; |
| 423 | 532 |
| 424 // Creates and opens a temporary file in |directory|, returning the | |
| 425 // file descriptor. |path| is set to the temporary file path. | |
| 426 // This function does NOT unlink() the file. | |
| 427 int CreateAndOpenFdForTemporaryFile(FilePath directory, FilePath* path) { | |
| 428 base::ThreadRestrictions::AssertIOAllowed(); // For call to mkstemp(). | |
| 429 *path = directory.Append(base::TempFileName()); | |
| 430 const std::string& tmpdir_string = path->value(); | |
| 431 // this should be OK since mkstemp just replaces characters in place | |
| 432 char* buffer = const_cast<char*>(tmpdir_string.c_str()); | |
| 433 | |
| 434 return HANDLE_EINTR(mkstemp(buffer)); | |
| 435 } | |
| 436 | |
| 437 bool CreateTemporaryFile(FilePath* path) { | 533 bool CreateTemporaryFile(FilePath* path) { |
| 438 base::ThreadRestrictions::AssertIOAllowed(); // For call to close(). | 534 base::ThreadRestrictions::AssertIOAllowed(); // For call to close(). |
| 439 FilePath directory; | 535 FilePath directory; |
| 440 if (!GetTempDir(&directory)) | 536 if (!GetTempDir(&directory)) |
| 441 return false; | 537 return false; |
| 442 int fd = CreateAndOpenFdForTemporaryFile(directory, path); | 538 int fd = CreateAndOpenFdForTemporaryFile(directory, path); |
| 443 if (fd < 0) | 539 if (fd < 0) |
| 444 return false; | 540 return false; |
| 445 ignore_result(HANDLE_EINTR(close(fd))); | 541 ignore_result(HANDLE_EINTR(close(fd))); |
| 446 return true; | 542 return true; |
| 447 } | 543 } |
| 448 | 544 |
| 449 FILE* CreateAndOpenTemporaryShmemFile(FilePath* path, bool executable) { | 545 FILE* CreateAndOpenTemporaryShmemFile(FilePath* path, bool executable) { |
| 450 FilePath directory; | 546 FilePath directory; |
| 451 if (!GetShmemTempDir(&directory, executable)) | 547 if (!GetShmemTempDir(executable, &directory)) |
| 452 return NULL; | 548 return NULL; |
| 453 | 549 |
| 454 return CreateAndOpenTemporaryFileInDir(directory, path); | 550 return CreateAndOpenTemporaryFileInDir(directory, path); |
| 455 } | 551 } |
| 456 | 552 |
| 457 FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) { | 553 FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) { |
| 458 int fd = CreateAndOpenFdForTemporaryFile(dir, path); | 554 int fd = CreateAndOpenFdForTemporaryFile(dir, path); |
| 459 if (fd < 0) | 555 if (fd < 0) |
| 460 return NULL; | 556 return NULL; |
| 461 | 557 |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 718 // directory. | 814 // directory. |
| 719 stat_wrapper_t file_info; | 815 stat_wrapper_t file_info; |
| 720 if (CallStat(real_path_result.value().c_str(), &file_info) != 0 || | 816 if (CallStat(real_path_result.value().c_str(), &file_info) != 0 || |
| 721 S_ISDIR(file_info.st_mode)) | 817 S_ISDIR(file_info.st_mode)) |
| 722 return false; | 818 return false; |
| 723 | 819 |
| 724 *normalized_path = real_path_result; | 820 *normalized_path = real_path_result; |
| 725 return true; | 821 return true; |
| 726 } | 822 } |
| 727 | 823 |
| 728 #if !defined(OS_MACOSX) | |
| 729 bool GetTempDir(FilePath* path) { | |
| 730 const char* tmp = getenv("TMPDIR"); | |
| 731 if (tmp) | |
| 732 *path = FilePath(tmp); | |
| 733 else | |
| 734 #if defined(OS_ANDROID) | |
| 735 return PathService::Get(base::DIR_CACHE, path); | |
| 736 #else | |
| 737 *path = FilePath("/tmp"); | |
| 738 #endif | |
| 739 return true; | |
| 740 } | |
| 741 | |
| 742 #if !defined(OS_ANDROID) | |
| 743 | |
| 744 #if defined(OS_LINUX) | |
| 745 // Determine if /dev/shm files can be mapped and then mprotect'd PROT_EXEC. | |
| 746 // This depends on the mount options used for /dev/shm, which vary among | |
| 747 // different Linux distributions and possibly local configuration. It also | |
| 748 // depends on details of kernel--ChromeOS uses the noexec option for /dev/shm | |
| 749 // but its kernel allows mprotect with PROT_EXEC anyway. | |
| 750 | |
| 751 namespace { | |
| 752 | |
| 753 bool DetermineDevShmExecutable() { | |
| 754 bool result = false; | |
| 755 FilePath path; | |
| 756 int fd = CreateAndOpenFdForTemporaryFile(FilePath("/dev/shm"), &path); | |
| 757 if (fd >= 0) { | |
| 758 ScopedFD shm_fd_closer(&fd); | |
| 759 DeleteFile(path, false); | |
| 760 long sysconf_result = sysconf(_SC_PAGESIZE); | |
| 761 CHECK_GE(sysconf_result, 0); | |
| 762 size_t pagesize = static_cast<size_t>(sysconf_result); | |
| 763 CHECK_GE(sizeof(pagesize), sizeof(sysconf_result)); | |
| 764 void *mapping = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, fd, 0); | |
| 765 if (mapping != MAP_FAILED) { | |
| 766 if (mprotect(mapping, pagesize, PROT_READ | PROT_EXEC) == 0) | |
| 767 result = true; | |
| 768 munmap(mapping, pagesize); | |
| 769 } | |
| 770 } | |
| 771 return result; | |
| 772 } | |
| 773 | |
| 774 }; // namespace | |
| 775 #endif // defined(OS_LINUX) | |
| 776 | |
| 777 bool GetShmemTempDir(FilePath* path, bool executable) { | |
| 778 #if defined(OS_LINUX) | |
| 779 bool use_dev_shm = true; | |
| 780 if (executable) { | |
| 781 static const bool s_dev_shm_executable = DetermineDevShmExecutable(); | |
| 782 use_dev_shm = s_dev_shm_executable; | |
| 783 } | |
| 784 if (use_dev_shm) { | |
| 785 *path = FilePath("/dev/shm"); | |
| 786 return true; | |
| 787 } | |
| 788 #endif | |
| 789 return GetTempDir(path); | |
| 790 } | |
| 791 #endif // !defined(OS_ANDROID) | |
| 792 | |
| 793 FilePath GetHomeDir() { | |
| 794 #if defined(OS_CHROMEOS) | |
| 795 if (base::SysInfo::IsRunningOnChromeOS()) | |
| 796 return FilePath("/home/chronos/user"); | |
| 797 #endif | |
| 798 | |
| 799 const char* home_dir = getenv("HOME"); | |
| 800 if (home_dir && home_dir[0]) | |
| 801 return FilePath(home_dir); | |
| 802 | |
| 803 #if defined(OS_ANDROID) | |
| 804 DLOG(WARNING) << "OS_ANDROID: Home directory lookup not yet implemented."; | |
| 805 #elif defined(USE_GLIB) && !defined(OS_CHROMEOS) | |
| 806 // g_get_home_dir calls getpwent, which can fall through to LDAP calls. | |
| 807 base::ThreadRestrictions::AssertIOAllowed(); | |
| 808 | |
| 809 home_dir = g_get_home_dir(); | |
| 810 if (home_dir && home_dir[0]) | |
| 811 return FilePath(home_dir); | |
| 812 #endif | |
| 813 | |
| 814 FilePath rv; | |
| 815 if (file_util::GetTempDir(&rv)) | |
| 816 return rv; | |
| 817 | |
| 818 // Last resort. | |
| 819 return FilePath("/tmp"); | |
| 820 } | |
| 821 #endif // !defined(OS_MACOSX) | |
| 822 | |
| 823 bool VerifyPathControlledByUser(const FilePath& base, | 824 bool VerifyPathControlledByUser(const FilePath& base, |
| 824 const FilePath& path, | 825 const FilePath& path, |
| 825 uid_t owner_uid, | 826 uid_t owner_uid, |
| 826 const std::set<gid_t>& group_gids) { | 827 const std::set<gid_t>& group_gids) { |
| 827 if (base != path && !base.IsParent(path)) { | 828 if (base != path && !base.IsParent(path)) { |
| 828 DLOG(ERROR) << "|base| must be a subdirectory of |path|. base = \"" | 829 DLOG(ERROR) << "|base| must be a subdirectory of |path|. base = \"" |
| 829 << base.value() << "\", path = \"" << path.value() << "\""; | 830 << base.value() << "\", path = \"" << path.value() << "\""; |
| 830 return false; | 831 return false; |
| 831 } | 832 } |
| 832 | 833 |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 970 result = false; | 971 result = false; |
| 971 if (HANDLE_EINTR(close(outfile)) < 0) | 972 if (HANDLE_EINTR(close(outfile)) < 0) |
| 972 result = false; | 973 result = false; |
| 973 | 974 |
| 974 return result; | 975 return result; |
| 975 } | 976 } |
| 976 #endif // !defined(OS_MACOSX) | 977 #endif // !defined(OS_MACOSX) |
| 977 | 978 |
| 978 } // namespace internal | 979 } // namespace internal |
| 979 } // namespace base | 980 } // namespace base |
| OLD | NEW |