Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 <fnmatch.h> | 10 #include <fnmatch.h> |
| 11 #include <grp.h> | |
| 11 #include <libgen.h> | 12 #include <libgen.h> |
| 12 #include <limits.h> | 13 #include <limits.h> |
| 13 #include <stdio.h> | 14 #include <stdio.h> |
| 14 #include <stdlib.h> | 15 #include <stdlib.h> |
| 15 #include <string.h> | 16 #include <string.h> |
| 16 #include <sys/errno.h> | 17 #include <sys/errno.h> |
| 17 #include <sys/mman.h> | 18 #include <sys/mman.h> |
| 18 #include <sys/param.h> | 19 #include <sys/param.h> |
| 19 #include <sys/stat.h> | 20 #include <sys/stat.h> |
| 20 #include <sys/time.h> | 21 #include <sys/time.h> |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 66 } // namespace | 67 } // namespace |
| 67 | 68 |
| 68 #if defined(OS_OPENBSD) || defined(OS_FREEBSD) || \ | 69 #if defined(OS_OPENBSD) || defined(OS_FREEBSD) || \ |
| 69 (defined(OS_MACOSX) && \ | 70 (defined(OS_MACOSX) && \ |
| 70 MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) | 71 MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) |
| 71 typedef struct stat stat_wrapper_t; | 72 typedef struct stat stat_wrapper_t; |
| 72 static int CallStat(const char *path, stat_wrapper_t *sb) { | 73 static int CallStat(const char *path, stat_wrapper_t *sb) { |
| 73 base::ThreadRestrictions::AssertIOAllowed(); | 74 base::ThreadRestrictions::AssertIOAllowed(); |
| 74 return stat(path, sb); | 75 return stat(path, sb); |
| 75 } | 76 } |
| 77 static int CallLstat(const char *path, stat_wrapper_t *sb) { | |
| 78 base::ThreadRestrictions::AssertIOAllowed(); | |
| 79 return lstat(path, sb); | |
| 80 } | |
| 76 #else | 81 #else |
| 77 typedef struct stat64 stat_wrapper_t; | 82 typedef struct stat64 stat_wrapper_t; |
| 78 static int CallStat(const char *path, stat_wrapper_t *sb) { | 83 static int CallStat(const char *path, stat_wrapper_t *sb) { |
| 79 base::ThreadRestrictions::AssertIOAllowed(); | 84 base::ThreadRestrictions::AssertIOAllowed(); |
| 80 return stat64(path, sb); | 85 return stat64(path, sb); |
| 81 } | 86 } |
| 87 static int CallLstat(const char *path, stat_wrapper_t *sb) { | |
| 88 base::ThreadRestrictions::AssertIOAllowed(); | |
| 89 return lstat64(path, sb); | |
| 90 } | |
| 82 #endif | 91 #endif |
| 83 | 92 |
| 84 static std::string TempFileName() { | 93 static std::string TempFileName() { |
| 85 #if defined(OS_MACOSX) | 94 #if defined(OS_MACOSX) |
| 86 return StringPrintf(".%s.XXXXXX", base::mac::BaseBundleID()); | 95 return StringPrintf(".%s.XXXXXX", base::mac::BaseBundleID()); |
| 87 #endif | 96 #endif |
| 88 | 97 |
| 89 #if defined(GOOGLE_CHROME_BUILD) | 98 #if defined(GOOGLE_CHROME_BUILD) |
| 90 return std::string(".com.google.Chrome.XXXXXX"); | 99 return std::string(".com.google.Chrome.XXXXXX"); |
| 91 #else | 100 #else |
| (...skipping 841 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 933 | 942 |
| 934 if (HANDLE_EINTR(close(infile)) < 0) | 943 if (HANDLE_EINTR(close(infile)) < 0) |
| 935 result = false; | 944 result = false; |
| 936 if (HANDLE_EINTR(close(outfile)) < 0) | 945 if (HANDLE_EINTR(close(outfile)) < 0) |
| 937 result = false; | 946 result = false; |
| 938 | 947 |
| 939 return result; | 948 return result; |
| 940 } | 949 } |
| 941 #endif // defined(OS_MACOSX) | 950 #endif // defined(OS_MACOSX) |
| 942 | 951 |
| 952 // Helper for IsPathControlledByUser. | |
| 953 bool SpecificPathControlledByUser(const FilePath& path, | |
|
Evan Martin
2011/08/30 17:26:38
Should be in the anon namespace if it's not part o
Sam Kerner (Chrome)
2011/09/16 18:12:59
Done.
| |
| 954 uid_t owner_uid, | |
| 955 gid_t group_gid) { | |
| 956 stat_wrapper_t stat_info; | |
| 957 if (CallLstat(path.value().c_str(), &stat_info) != 0) { | |
| 958 PLOG(ERROR) << "Failed to get information on path " | |
| 959 << path.value(); | |
| 960 return false; | |
| 961 } | |
| 962 | |
| 963 if (S_ISLNK(stat_info.st_mode)) { | |
| 964 LOG(ERROR) << "Path " << path.value() | |
| 965 << " is a symbolic link."; | |
| 966 return false; | |
| 967 } | |
| 968 | |
| 969 if (stat_info.st_uid != owner_uid) { | |
| 970 LOG(ERROR) << "Path " << path.value() | |
| 971 << " is owned by the wrong user."; | |
|
Evan Martin
2011/08/30 17:26:38
It seems you're reporting it as an error when thes
Sam Kerner (Chrome)
2011/09/16 18:12:59
Done.
| |
| 972 return false; | |
| 973 } | |
| 974 | |
| 975 if (stat_info.st_gid != group_gid) { | |
| 976 LOG(ERROR) << "Path " << path.value() | |
| 977 << " is owned by the wrong group."; | |
| 978 return false; | |
| 979 } | |
| 980 | |
| 981 if (stat_info.st_mode & S_IWOTH) { | |
| 982 LOG(ERROR) << "Path "<< path.value() | |
|
Evan Martin
2011/08/30 17:26:38
space before <<
Sam Kerner (Chrome)
2011/09/16 18:12:59
Done.
| |
| 983 << " is writable by any user."; | |
| 984 return false; | |
| 985 } | |
| 986 | |
| 987 return true; | |
| 988 } | |
| 989 | |
| 990 bool IsPathControlledByUser(const FilePath& base, | |
| 991 const FilePath& path, | |
| 992 uid_t owner_uid, | |
| 993 gid_t group_gid) { | |
| 994 if (base != path && !base.IsParent(path)) { | |
| 995 LOG(ERROR) << "|base| must be a subdirectory of |path|. base = " | |
| 996 << base.value() << " path = " << path.value(); | |
| 997 return false; | |
| 998 } | |
| 999 | |
| 1000 std::vector<FilePath::StringType> base_components; | |
| 1001 std::vector<FilePath::StringType> path_components; | |
| 1002 | |
| 1003 base.GetComponents(&base_components); | |
| 1004 path.GetComponents(&path_components); | |
| 1005 | |
| 1006 std::vector<FilePath::StringType>::const_iterator ib, ip; | |
| 1007 for (ib = base_components.begin(), ip = path_components.begin(); | |
| 1008 ib != base_components.end(); ++ib, ++ip) { | |
| 1009 // |base| must be a subpath of |path|, so all components should match. | |
| 1010 // If these CHECKs fail, look at the test that base is a parent of | |
| 1011 // path at the top of this function. | |
| 1012 CHECK(ip != path_components.end()); | |
| 1013 CHECK(*ip == *ib); | |
| 1014 } | |
| 1015 | |
| 1016 FilePath current_path = base; | |
| 1017 if (!SpecificPathControlledByUser(current_path, owner_uid, group_gid)) | |
| 1018 return false; | |
| 1019 | |
| 1020 for (; ip != path_components.end(); ++ip) { | |
| 1021 current_path = current_path.Append(*ip); | |
| 1022 if (!SpecificPathControlledByUser(current_path, owner_uid, group_gid)) | |
| 1023 return false; | |
| 1024 } | |
| 1025 return true; | |
| 1026 } | |
| 1027 | |
| 1028 bool IsPathControlledByAdmin(const FilePath& path) { | |
| 1029 const unsigned kRootUid = 0; | |
| 1030 const FilePath kFileSystemRoot("/"); | |
| 1031 | |
| 1032 // The name of the administrator group on mac os. | |
| 1033 const char kAdminGroupName[] = "admin"; | |
| 1034 | |
| 1035 // Reading the groups database may touch the file system. | |
| 1036 base::ThreadRestrictions::AssertIOAllowed(); | |
|
Evan Martin
2011/08/30 17:26:38
Thanks for doing this!
| |
| 1037 | |
| 1038 struct group *groupRecord = getgrnam(kAdminGroupName); | |
|
Evan Martin
2011/08/30 17:26:38
group_record, not groupRecord
Sam Kerner (Chrome)
2011/09/16 18:12:59
Done.
| |
| 1039 if (!groupRecord) { | |
| 1040 PLOG(ERROR) << "Could not get the group ID of group \"" | |
| 1041 << kAdminGroupName << "\"."; | |
| 1042 return false; | |
| 1043 } | |
| 1044 | |
| 1045 return IsPathControlledByUser( | |
| 1046 kFileSystemRoot, path, kRootUid, groupRecord->gr_gid); | |
| 1047 } | |
| 1048 | |
| 943 } // namespace file_util | 1049 } // namespace file_util |
| OLD | NEW |