Bug 1416016 - Resolve symlinks in the file broker as a last resort. r?jld
MozReview-Commit-ID: B7OMyARk9u8
--- a/security/sandbox/linux/broker/SandboxBroker.cpp
+++ b/security/sandbox/linux/broker/SandboxBroker.cpp
@@ -541,27 +541,33 @@ DoConnect(const char* aPath, size_t aLen
if (connect(fd, reinterpret_cast<struct sockaddr*>(&sun), sizeof(sun)) < 0) {
close(fd);
return -1;
}
return fd;
}
size_t
-SandboxBroker::ConvertToRealPath(char* aPath, size_t aBufSize, size_t aPathLen)
+SandboxBroker::RealPath(char* aPath, size_t aBufSize, size_t aPathLen)
+{
+ char* result = realpath(aPath, nullptr);
+ if (result != nullptr) {
+ base::strlcpy(aPath, result, aBufSize);
+ free(result);
+ // Size changed, but guaranteed to be 0 terminated
+ aPathLen = strlen(aPath);
+ }
+ return aPathLen;
+}
+
+size_t
+SandboxBroker::ConvertRelativePath(char* aPath, size_t aBufSize, size_t aPathLen)
{
if (strstr(aPath, "..") != nullptr) {
- char* result = realpath(aPath, nullptr);
- if (result != nullptr) {
- base::strlcpy(aPath, result, aBufSize);
- free(result);
- // Size changed, but guaranteed to be 0 terminated
- aPathLen = strlen(aPath);
- }
- // ValidatePath will handle failure to translate
+ return RealPath(aPath, aBufSize, aPathLen);
}
return aPathLen;
}
size_t
SandboxBroker::RemapTempDirs(char* aPath, size_t aBufSize, size_t aPathLen)
{
nsAutoCString path(aPath);
@@ -779,42 +785,52 @@ SandboxBroker::ThreadMain(void)
// We do not assume the second path is 0-terminated, this is
// enforced below.
strncpy(pathBuf2, recvBuf + first_len + 1, kMaxPathLen + 1);
// First string is guaranteed to be 0-terminated.
pathLen = first_len;
// Look up the first pathname but first translate relative paths.
- pathLen = ConvertToRealPath(pathBuf, sizeof(pathBuf), pathLen);
+ pathLen = ConvertRelativePath(pathBuf, sizeof(pathBuf), pathLen);
perms = mPolicy->Lookup(nsDependentCString(pathBuf, pathLen));
// We don't have permissions on the requested dir.
if (!perms) {
// Was it a tempdir that we can remap?
pathLen = RemapTempDirs(pathBuf, sizeof(pathBuf), pathLen);
perms = mPolicy->Lookup(nsDependentCString(pathBuf, pathLen));
if (!perms) {
// Did we arrive from a symlink in a path that is not writable?
// Then try to figure out the original path and see if that is
// readable. Work on the original path, this reverses
- // ConvertToRealPath above.
+ // ConvertRelative above.
int symlinkPerms = SymlinkPermissions(recvBuf, first_len);
if (symlinkPerms > 0) {
perms = symlinkPerms;
}
+ if (!perms) {
+ // Now try the opposite case: translate symlinks to their
+ // actual destination file. Firefox always resolves symlinks,
+ // and in most cases we have whitelisted fixed paths that
+ // libraries will rely on and try to open. So this codepath
+ // is mostly useful for Mesa which had its kernel interface
+ // moved around.
+ pathLen = RealPath(pathBuf, sizeof(pathBuf), pathLen);
+ perms = mPolicy->Lookup(nsDependentCString(pathBuf, pathLen));
+ }
}
}
// Same for the second path.
pathLen2 = strnlen(pathBuf2, kMaxPathLen);
if (pathLen2 > 0) {
// Force 0 termination.
pathBuf2[pathLen2] = '\0';
- pathLen2 = ConvertToRealPath(pathBuf2, sizeof(pathBuf2), pathLen2);
+ pathLen2 = ConvertRelativePath(pathBuf2, sizeof(pathBuf2), pathLen2);
int perms2 = mPolicy->Lookup(nsDependentCString(pathBuf2, pathLen2));
// Take the intersection of the permissions for both paths.
perms &= perms2;
}
} else {
// Failed to receive intelligible paths.
perms = 0;
--- a/security/sandbox/linux/broker/SandboxBroker.h
+++ b/security/sandbox/linux/broker/SandboxBroker.h
@@ -140,17 +140,18 @@ class SandboxBroker final
PathMap mSymlinkMap;
SandboxBroker(UniquePtr<const Policy> aPolicy, int aChildPid,
int& aClientFd);
void ThreadMain(void) override;
void AuditPermissive(int aOp, int aFlags, int aPerms, const char* aPath);
void AuditDenial(int aOp, int aFlags, int aPerms, const char* aPath);
// Remap relative paths to absolute paths.
- size_t ConvertToRealPath(char* aPath, size_t aBufSize, size_t aPathLen);
+ size_t ConvertRelativePath(char* aPath, size_t aBufSize, size_t aPathLen);
+ size_t RealPath(char* aPath, size_t aBufSize, size_t aPathLen);
// Remap references to /tmp and friends to the content process tempdir
size_t RemapTempDirs(char* aPath, size_t aBufSize, size_t aPathLen);
nsCString ReverseSymlinks(const nsACString& aPath);
// Retrieves permissions for the path the original symlink sits in.
int SymlinkPermissions(const char* aPath, const size_t aPathLen);
// In SandboxBrokerRealPath.cpp
char* SymlinkPath(const Policy* aPolicy, const char* __restrict aPath,
char* __restrict aResolved, int* aPermission);