Index: base/file_util_posix.cc |
diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc |
index 323f5aa561359c74c2ba34934cc20755dec5bcd4..40d4c1bc2428f2267aaf6c690a1d8b9cdce7db7d 100644 |
--- a/base/file_util_posix.cc |
+++ b/base/file_util_posix.cc |
@@ -38,6 +38,7 @@ |
#include "base/logging.h" |
#include "base/memory/scoped_ptr.h" |
#include "base/memory/singleton.h" |
+#include "base/stl_util.h" |
#include "base/string_util.h" |
#include "base/stringprintf.h" |
#include "base/sys_string_conversions.h" |
@@ -91,7 +92,7 @@ bool RealPath(const FilePath& path, FilePath* real_path) { |
// Helper for VerifyPathControlledByUser. |
bool VerifySpecificPathControlledByUser(const FilePath& path, |
uid_t owner_uid, |
- gid_t group_gid) { |
+ const std::set<gid_t>& group_gids) { |
stat_wrapper_t stat_info; |
if (CallLstat(path.value().c_str(), &stat_info) != 0) { |
PLOG(ERROR) << "Failed to get information on path " |
@@ -111,9 +112,10 @@ bool VerifySpecificPathControlledByUser(const FilePath& path, |
return false; |
} |
- if (stat_info.st_gid != group_gid) { |
+ if ((stat_info.st_mode & S_IWGRP) && |
+ !ContainsKey(group_gids, stat_info.st_gid)) { |
LOG(ERROR) << "Path " << path.value() |
- << " is owned by the wrong group."; |
+ << " is writable by an unprivileged group."; |
return false; |
} |
@@ -990,7 +992,7 @@ bool CopyFile(const FilePath& from_path, const FilePath& to_path) { |
bool VerifyPathControlledByUser(const FilePath& base, |
const FilePath& path, |
uid_t owner_uid, |
- gid_t group_gid) { |
+ const std::set<gid_t>& group_gids) { |
if (base != path && !base.IsParent(path)) { |
LOG(ERROR) << "|base| must be a subdirectory of |path|. base = \"" |
<< base.value() << "\", path = \"" << path.value() << "\""; |
@@ -1014,12 +1016,13 @@ bool VerifyPathControlledByUser(const FilePath& base, |
} |
FilePath current_path = base; |
- if (!VerifySpecificPathControlledByUser(current_path, owner_uid, group_gid)) |
+ if (!VerifySpecificPathControlledByUser(current_path, owner_uid, group_gids)) |
return false; |
for (; ip != path_components.end(); ++ip) { |
current_path = current_path.Append(*ip); |
- if (!VerifySpecificPathControlledByUser(current_path, owner_uid, group_gid)) |
+ if (!VerifySpecificPathControlledByUser( |
+ current_path, owner_uid, group_gids)) |
return false; |
} |
return true; |
@@ -1031,20 +1034,28 @@ bool VerifyPathControlledByAdmin(const FilePath& path) { |
const FilePath kFileSystemRoot("/"); |
// The name of the administrator group on mac os. |
- const char kAdminGroupName[] = "admin"; |
+ const char* kAdminGroupNames[] = { |
Mark Mentovai
2011/10/17 18:53:57
In order for this to be properly treated as consta
Sam Kerner (Chrome)
2011/10/17 19:35:16
Done.
|
+ "admin", |
+ "wheel" |
+ }; |
// Reading the groups database may touch the file system. |
base::ThreadRestrictions::AssertIOAllowed(); |
- struct group *group_record = getgrnam(kAdminGroupName); |
- if (!group_record) { |
- PLOG(ERROR) << "Could not get the group ID of group \"" |
- << kAdminGroupName << "\"."; |
- return false; |
+ std::set<gid_t> allowed_group_ids; |
+ for (int i = 0, ie = arraysize(kAdminGroupNames); i < ie; ++i) { |
+ struct group *group_record = getgrnam(kAdminGroupNames[i]); |
Mark Mentovai
2011/10/17 18:53:57
This does a name lookup which may block. On which
Sam Kerner (Chrome)
2011/10/17 19:35:16
This function runs on the file thread. To be sure
|
+ if (!group_record) { |
+ PLOG(ERROR) << "Could not get the group ID of group \"" |
+ << kAdminGroupNames[i] << "\"."; |
+ continue; |
+ } |
+ |
+ allowed_group_ids.insert(group_record->gr_gid); |
} |
return VerifyPathControlledByUser( |
- kFileSystemRoot, path, kRootUid, group_record->gr_gid); |
+ kFileSystemRoot, path, kRootUid, allowed_group_ids); |
} |
#endif // defined(OS_MACOSX) |