2 * Copyright (C) 2010-2019 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
27 #import "SandboxExtension.h"
29 #if ENABLE(SANDBOX_EXTENSIONS)
31 #import "DataReference.h"
34 #import <wtf/FileSystem.h>
35 #import <wtf/spi/darwin/SandboxSPI.h>
36 #import <wtf/text/CString.h>
40 class SandboxExtensionImpl {
42 static std::unique_ptr<SandboxExtensionImpl> create(const char* path, SandboxExtension::Type type, Optional<pid_t> pid = WTF::nullopt)
44 std::unique_ptr<SandboxExtensionImpl> impl { new SandboxExtensionImpl(path, type, pid) };
50 SandboxExtensionImpl(const char* serializedFormat, size_t length)
51 : m_token { strndup(serializedFormat, length) }
55 ~SandboxExtensionImpl()
60 bool WARN_UNUSED_RETURN consume()
62 m_handle = sandbox_extension_consume(m_token);
63 #if PLATFORM(IOS_FAMILY_SIMULATOR)
64 return !sandbox_check(getpid(), 0, SANDBOX_FILTER_NONE);
67 LOG_ERROR("Could not create a sandbox extension for '%s', errno = %d", m_token, errno);
76 return !sandbox_extension_release(std::exchange(m_handle, 0));
79 const char* WARN_UNUSED_RETURN getSerializedFormat(size_t& length)
81 length = strlen(m_token);
86 char* sandboxExtensionForType(const char* path, SandboxExtension::Type type, Optional<pid_t> pid = WTF::nullopt)
89 case SandboxExtension::Type::ReadOnly:
90 return sandbox_extension_issue_file(APP_SANDBOX_READ, path, 0);
91 case SandboxExtension::Type::ReadWrite:
92 return sandbox_extension_issue_file(APP_SANDBOX_READ_WRITE, path, 0);
93 case SandboxExtension::Type::Mach:
94 #if HAVE(SANDBOX_ISSUE_MACH_EXTENSION_TO_PROCESS_BY_PID)
95 return sandbox_extension_issue_mach_to_process_by_pid("com.apple.webkit.extension.mach"_s, path, 0, pid.value());
101 case SandboxExtension::Type::Generic:
102 return sandbox_extension_issue_generic(path, 0);
103 case SandboxExtension::Type::ReadByPid:
104 #if HAVE(SANDBOX_ISSUE_READ_EXTENSION_TO_PROCESS_BY_PID)
105 return sandbox_extension_issue_file_to_process_by_pid(APP_SANDBOX_READ, path, 0, pid.value());
108 ASSERT_NOT_REACHED();
114 SandboxExtensionImpl(const char* path, SandboxExtension::Type type, Optional<pid_t> pid = WTF::nullopt)
115 : m_token { sandboxExtensionForType(path, type, pid) }
120 int64_t m_handle { 0 };
123 SandboxExtension::Handle::Handle()
127 SandboxExtension::Handle::Handle(Handle&&) = default;
128 SandboxExtension::Handle& SandboxExtension::Handle::operator=(Handle&&) = default;
130 SandboxExtension::Handle::~Handle()
132 if (m_sandboxExtension)
133 m_sandboxExtension->invalidate();
136 void SandboxExtension::Handle::encode(IPC::Encoder& encoder) const
138 if (!m_sandboxExtension) {
139 encoder << IPC::DataReference();
144 const char* serializedFormat = m_sandboxExtension->getSerializedFormat(length);
145 ASSERT(serializedFormat);
147 encoder << IPC::DataReference(reinterpret_cast<const uint8_t*>(serializedFormat), length);
149 // Encoding will destroy the sandbox extension locally.
150 m_sandboxExtension = 0;
153 auto SandboxExtension::Handle::decode(IPC::Decoder& decoder) -> Optional<Handle>
155 IPC::DataReference dataReference;
156 if (!decoder.decode(dataReference))
159 if (dataReference.isEmpty())
163 handle.m_sandboxExtension = std::make_unique<SandboxExtensionImpl>(reinterpret_cast<const char*>(dataReference.data()), dataReference.size());
164 return WTFMove(handle);
167 SandboxExtension::HandleArray::HandleArray()
171 SandboxExtension::HandleArray::~HandleArray()
175 void SandboxExtension::HandleArray::allocate(size_t size)
180 ASSERT(m_data.isEmpty());
185 SandboxExtension::Handle& SandboxExtension::HandleArray::operator[](size_t i)
187 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(i < m_data.size());
191 const SandboxExtension::Handle& SandboxExtension::HandleArray::operator[](size_t i) const
193 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(i < m_data.size());
197 size_t SandboxExtension::HandleArray::size() const
199 return m_data.size();
202 void SandboxExtension::HandleArray::encode(IPC::Encoder& encoder) const
204 encoder << static_cast<uint64_t>(size());
205 for (auto& handle : m_data)
209 Optional<SandboxExtension::HandleArray> SandboxExtension::HandleArray::decode(IPC::Decoder& decoder)
211 Optional<uint64_t> size;
215 SandboxExtension::HandleArray handles;
216 handles.allocate(*size);
217 for (size_t i = 0; i < *size; ++i) {
218 Optional<SandboxExtension::Handle> handle;
222 handles[i] = WTFMove(*handle);
224 return WTFMove(handles);
227 RefPtr<SandboxExtension> SandboxExtension::create(Handle&& handle)
229 if (!handle.m_sandboxExtension)
232 return adoptRef(new SandboxExtension(handle));
235 String stringByResolvingSymlinksInPath(const String& path)
237 return [(NSString *)path stringByResolvingSymlinksInPath];
240 String resolveAndCreateReadWriteDirectoryForSandboxExtension(const String& path)
242 NSError *error = nil;
243 NSString *nsPath = path;
245 if (![[NSFileManager defaultManager] createDirectoryAtPath:nsPath withIntermediateDirectories:YES attributes:nil error:&error]) {
246 NSLog(@"could not create directory \"%@\" for future sandbox extension, error %@", nsPath, error);
250 return resolvePathForSandboxExtension(path);
253 String resolvePathForSandboxExtension(const String& path)
255 String resolvedPath = stringByResolvingSymlinksInPath(path);
256 if (resolvedPath.isNull()) {
257 LOG_ERROR("Could not create a valid file system representation for the string '%s' of length %lu", resolvedPath.utf8().data(), resolvedPath.length());
264 bool SandboxExtension::createHandleWithoutResolvingPath(const String& path, Type type, Handle& handle)
266 ASSERT(!handle.m_sandboxExtension);
268 handle.m_sandboxExtension = SandboxExtensionImpl::create(path.utf8().data(), type);
269 if (!handle.m_sandboxExtension) {
270 LOG_ERROR("Could not create a sandbox extension for '%s'", path.utf8().data());
276 bool SandboxExtension::createHandle(const String& path, Type type, Handle& handle)
278 ASSERT(!handle.m_sandboxExtension);
280 return createHandleWithoutResolvingPath(resolvePathForSandboxExtension(path), type, handle);
283 bool SandboxExtension::createHandleForReadWriteDirectory(const String& path, SandboxExtension::Handle& handle)
285 String resolvedPath = resolveAndCreateReadWriteDirectoryForSandboxExtension(path);
286 if (resolvedPath.isNull())
289 return SandboxExtension::createHandleWithoutResolvingPath(resolvedPath, SandboxExtension::Type::ReadWrite, handle);
292 String SandboxExtension::createHandleForTemporaryFile(const String& prefix, Type type, Handle& handle)
294 ASSERT(!handle.m_sandboxExtension);
296 Vector<char> path(PATH_MAX);
297 if (!confstr(_CS_DARWIN_USER_TEMP_DIR, path.data(), path.size()))
300 // Shrink the vector.
301 path.shrink(strlen(path.data()));
303 // FIXME: Change to a runtime assertion that the path ends with a slash once <rdar://problem/23579077> is
304 // fixed in all iOS Simulator versions that we use.
305 if (path.last() != '/')
308 // Append the file name.
309 path.append(prefix.utf8().data(), prefix.length());
312 handle.m_sandboxExtension = SandboxExtensionImpl::create(FileSystem::fileSystemRepresentation(path.data()).data(), type);
314 if (!handle.m_sandboxExtension) {
315 WTFLogAlways("Could not create a sandbox extension for temporary file '%s'", path.data());
318 return String(path.data());
321 bool SandboxExtension::createHandleForGenericExtension(const String& extensionClass, Handle& handle)
323 ASSERT(!handle.m_sandboxExtension);
325 handle.m_sandboxExtension = SandboxExtensionImpl::create(extensionClass.utf8().data(), Type::Generic);
326 if (!handle.m_sandboxExtension) {
327 WTFLogAlways("Could not create a '%s' sandbox extension", extensionClass.utf8().data());
334 bool SandboxExtension::createHandleForMachLookupByPid(const String& service, pid_t pid, Handle& handle)
336 ASSERT(!handle.m_sandboxExtension);
338 handle.m_sandboxExtension = SandboxExtensionImpl::create(service.utf8().data(), Type::Mach, pid);
339 if (!handle.m_sandboxExtension) {
340 WTFLogAlways("Could not create a '%s' sandbox extension", service.utf8().data());
347 bool SandboxExtension::createHandleForReadByPid(const String& path, ProcessID pid, Handle& handle)
349 ASSERT(!handle.m_sandboxExtension);
351 handle.m_sandboxExtension = SandboxExtensionImpl::create(path.utf8().data(), Type::ReadByPid, pid);
352 if (!handle.m_sandboxExtension) {
353 WTFLogAlways("Could not create a '%s' sandbox extension", path.utf8().data());
360 SandboxExtension::SandboxExtension(const Handle& handle)
361 : m_sandboxExtension(WTFMove(handle.m_sandboxExtension))
365 SandboxExtension::~SandboxExtension()
367 if (!m_sandboxExtension)
373 bool SandboxExtension::revoke()
375 ASSERT(m_sandboxExtension);
381 return m_sandboxExtension->invalidate();
384 bool SandboxExtension::consume()
386 ASSERT(m_sandboxExtension);
391 return m_sandboxExtension->consume();
394 bool SandboxExtension::consumePermanently()
396 ASSERT(m_sandboxExtension);
398 bool result = m_sandboxExtension->consume();
400 // Destroy the extension without invalidating it.
401 m_sandboxExtension = nullptr;
406 bool SandboxExtension::consumePermanently(const Handle& handle)
408 if (!handle.m_sandboxExtension)
411 bool result = handle.m_sandboxExtension->consume();
413 // Destroy the extension without invalidating it.
414 handle.m_sandboxExtension = nullptr;
419 } // namespace WebKit
421 #endif // ENABLE(SANDBOX_EXTENSIONS)