1/*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
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.
12 *
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.
24 */
25
26#import "config.h"
27#import "SandboxExtension.h"
28
29#if ENABLE(WEB_PROCESS_SANDBOX)
30
31#import "ArgumentDecoder.h"
32#import "ArgumentEncoder.h"
33#import "DataReference.h"
34#import "WebKitSystemInterface.h"
35#import <WebCore/FileSystem.h>
36#import <sys/stat.h>
37#import <wtf/text/CString.h>
38
39using namespace WebCore;
40
41namespace WebKit {
42
43SandboxExtension::Handle::Handle()
44    : m_sandboxExtension(0)
45{
46}
47
48SandboxExtension::Handle::~Handle()
49{
50    if (m_sandboxExtension) {
51        WKSandboxExtensionInvalidate(m_sandboxExtension);
52        WKSandboxExtensionDestroy(m_sandboxExtension);
53    }
54}
55
56void SandboxExtension::Handle::encode(CoreIPC::ArgumentEncoder* encoder) const
57{
58    if (!m_sandboxExtension) {
59        encoder->encodeBytes(0, 0);
60        return;
61    }
62
63    size_t length = 0;
64    const char *serializedFormat = WKSandboxExtensionGetSerializedFormat(m_sandboxExtension, &length);
65    ASSERT(serializedFormat);
66
67    encoder->encodeBytes(reinterpret_cast<const uint8_t*>(serializedFormat), length);
68
69    // Encoding will destroy the sandbox extension locally.
70    WKSandboxExtensionDestroy(m_sandboxExtension);
71    m_sandboxExtension = 0;
72}
73
74bool SandboxExtension::Handle::decode(CoreIPC::ArgumentDecoder* decoder, Handle& result)
75{
76    ASSERT(!result.m_sandboxExtension);
77
78    CoreIPC::DataReference dataReference;
79    if (!decoder->decodeBytes(dataReference))
80        return false;
81
82    if (dataReference.isEmpty())
83        return true;
84
85    result.m_sandboxExtension = WKSandboxExtensionCreateFromSerializedFormat(reinterpret_cast<const char*>(dataReference.data()), dataReference.size());
86    return true;
87}
88
89PassRefPtr<SandboxExtension> SandboxExtension::create(const Handle& handle)
90{
91    if (!handle.m_sandboxExtension)
92        return 0;
93
94    return adoptRef(new SandboxExtension(handle));
95}
96
97static WKSandboxExtensionType wkSandboxExtensionType(SandboxExtension::Type type)
98{
99    switch (type) {
100    case SandboxExtension::ReadOnly:
101        return WKSandboxExtensionTypeReadOnly;
102    case SandboxExtension::WriteOnly:
103        return WKSandboxExtensionTypeWriteOnly;
104    case SandboxExtension::ReadWrite:
105        return WKSandboxExtensionTypeReadWrite;
106    }
107
108    ASSERT_NOT_REACHED();
109    return WKSandboxExtensionTypeReadOnly;
110}
111
112static CString resolveSymlinksInPath(const CString& path)
113{
114    struct stat statBuf;
115
116    // Check if this file exists.
117    if (!stat(path.data(), &statBuf)) {
118        char resolvedName[PATH_MAX];
119
120        return realpath(path.data(), resolvedName);
121    }
122
123    char* slashPtr = strrchr(path.data(), '/');
124    if (slashPtr == path.data())
125        return path;
126
127    size_t parentDirectoryLength = slashPtr - path.data();
128    if (parentDirectoryLength >= PATH_MAX)
129        return CString();
130
131    // Get the parent directory.
132    char parentDirectory[PATH_MAX];
133    memcpy(parentDirectory, path.data(), parentDirectoryLength);
134    parentDirectory[parentDirectoryLength] = '\0';
135
136    // Resolve it.
137    CString resolvedParentDirectory = resolveSymlinksInPath(CString(parentDirectory));
138    if (resolvedParentDirectory.isNull())
139        return CString();
140
141    size_t lastPathComponentLength = path.length() - parentDirectoryLength;
142    size_t resolvedPathLength = resolvedParentDirectory.length() + lastPathComponentLength;
143    if (resolvedPathLength >= PATH_MAX)
144        return CString();
145
146    // Combine the resolved parent directory with the last path component.
147    char* resolvedPathBuffer;
148    CString resolvedPath = CString::newUninitialized(resolvedPathLength, resolvedPathBuffer);
149    memcpy(resolvedPathBuffer, resolvedParentDirectory.data(), resolvedParentDirectory.length());
150    memcpy(resolvedPathBuffer + resolvedParentDirectory.length(), slashPtr, lastPathComponentLength);
151
152    return resolvedPath;
153}
154
155void SandboxExtension::createHandle(const String& path, Type type, Handle& handle)
156{
157    ASSERT(!handle.m_sandboxExtension);
158
159    CString standardizedPath = resolveSymlinksInPath([[(NSString *)path stringByStandardizingPath] fileSystemRepresentation]);
160    handle.m_sandboxExtension = WKSandboxExtensionCreate(standardizedPath.data(), wkSandboxExtensionType(type));
161}
162
163String SandboxExtension::createHandleForTemporaryFile(const String& prefix, Type type, Handle& handle)
164{
165    ASSERT(!handle.m_sandboxExtension);
166
167    Vector<char> path(PATH_MAX);
168    if (!confstr(_CS_DARWIN_USER_TEMP_DIR, path.data(), path.size()))
169        return String();
170
171    // Shrink the vector.
172    path.shrink(strlen(path.data()));
173    ASSERT(path.last() == '/');
174
175    // Append the file name.
176    path.append(prefix.utf8().data(), prefix.length());
177    path.append('\0');
178
179    handle.m_sandboxExtension = WKSandboxExtensionCreate(fileSystemRepresentation(path.data()).data(), wkSandboxExtensionType(type));
180
181    if (!handle.m_sandboxExtension) {
182        return String();
183    }
184    return String(path.data());
185}
186
187SandboxExtension::SandboxExtension(const Handle& handle)
188    : m_sandboxExtension(handle.m_sandboxExtension)
189{
190    handle.m_sandboxExtension = 0;
191}
192
193SandboxExtension::~SandboxExtension()
194{
195    if (!m_sandboxExtension)
196        return;
197
198    WKSandboxExtensionInvalidate(m_sandboxExtension);
199    WKSandboxExtensionDestroy(m_sandboxExtension);
200}
201
202bool SandboxExtension::invalidate()
203{
204    ASSERT(m_sandboxExtension);
205
206    bool result = WKSandboxExtensionInvalidate(m_sandboxExtension);
207    WKSandboxExtensionDestroy(m_sandboxExtension);
208    m_sandboxExtension = 0;
209
210    return result;
211}
212
213bool SandboxExtension::consume()
214{
215    ASSERT(m_sandboxExtension);
216
217    return WKSandboxExtensionConsume(m_sandboxExtension);
218}
219
220bool SandboxExtension::consumePermanently()
221{
222    ASSERT(m_sandboxExtension);
223
224    bool result = WKSandboxExtensionConsume(m_sandboxExtension);
225
226    // Destroy the extension without invalidating it.
227    WKSandboxExtensionDestroy(m_sandboxExtension);
228    m_sandboxExtension = 0;
229
230    return result;
231}
232
233} // namespace WebKit
234
235#endif // ENABLE(WEB_PROCESS_SANDBOX)
236