+2011-09-22 Alexey Proskuryakov <ap@apple.com>
+
+ [WK2] UIProcess should check that WebProcess isn't sending unexpected file: URLs to it
+ https://bugs.webkit.org/show_bug.cgi?id=68573
+
+ Reviewed by Anders Carlsson.
+
+ Re-landing with a slightly less aggressive check.
+
+ * UIProcess/API/mac/WKView.mm:
+ (maybeCreateSandboxExtensionFromPasteboard): Return a boolean, telling the caller whether
+ an extension actually needed to be created
+ (-[WKView performDragOperation:]): Tell process proxy when the process is going to get
+ universal file read sandbox extension.
+
+ * UIProcess/WebContext.cpp:
+ (WebKit::WebContext::didPerformClientRedirect): Check the URLs.
+ (WebKit::WebContext::didPerformServerRedirect): Ditto.
+ (WebKit::WebContext::didUpdateHistoryTitle): Ditto.
+ (WebKit::WebContext::getPluginPath): Ditto. Also, properly parse the URL - we can never
+ assume that a string coming from WebProcess is a ParsedURLString.
+
+ * UIProcess/WebPageProxy.cpp:
+ (WebKit::WebPageProxy::reattachToWebProcessWithItem): Tell process proxy when the process
+ is going to get universal file read sandbox extension.
+ (WebKit::WebPageProxy::maybeInitializeSandboxExtensionHandle): Changed to return a boolean,
+ telling the caller whether an extension actually needed to be created.
+ (WebKit::WebPageProxy::loadURL): Tell process proxy about extension.
+ (WebKit::WebPageProxy::loadURLRequest): Ditto.
+ (WebKit::WebPageProxy::loadHTMLString): Tell process proxy if a file URL was used as a base
+ one for a string. In this case, WebKit2 assumes that WebProcess has access to a subdirectory,
+ (typically, one where error page resources live), and can load from it.
+ (WebKit::WebPageProxy::loadAlternateHTMLString): Ditto.
+ (WebKit::WebPageProxy::goForward): Tell process proxy about extension.
+ (WebKit::WebPageProxy::goBack): Tell process proxy about extension.
+ (WebKit::WebPageProxy::goToBackForwardItem): Tell process proxy about extension.
+ (WebKit::WebPageProxy::didStartProvisionalLoadForFrame): Check the URL.
+ (WebKit::WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrame): Ditto.
+ (WebKit::WebPageProxy::didSameDocumentNavigationForFrame): Ditto.
+ (WebKit::WebPageProxy::decidePolicyForNavigationAction): Ditto.
+ (WebKit::WebPageProxy::decidePolicyForNewWindowAction): Ditto.
+ (WebKit::WebPageProxy::decidePolicyForResponse): Ditto.
+ (WebKit::WebPageProxy::didInitiateLoadForResource): Ditto.
+ (WebKit::WebPageProxy::didSendRequestForResource): Ditto.
+ (WebKit::WebPageProxy::didReceiveResponseForResource): Ditto.
+ (WebKit::WebPageProxy::missingPluginButtonClicked): Ditto.
+
+ * UIProcess/WebPageProxy.h: Changed initializeSandboxExtensionHandle() to return a bool,
+ and renamed to maybeInitializeSandboxExtensionHandle (matching WKView counterpart).
+
+ * UIProcess/WebProcessProxy.cpp:
+ (WebKit::WebProcessProxy::WebProcessProxy): Initialize m_mayHaveUniversalFileReadSandboxExtension.
+ It's going to be true if we ever granted an extension for "/".
+ (WebKit::WebProcessProxy::willLoadHTMLStringWithBaseURL): Remember the path, we should expect
+ that WebProcess will load subresources from it.
+ (WebKit::WebProcessProxy::checkURLReceivedFromWebProcess): Check that it's reasonable to expect
+ WebProcess send us a URL like this.
+ (WebKit::WebProcessProxy::addBackForwardItem): Check the URLs.
+
+ * UIProcess/WebProcessProxy.h: Added data members remembering what to expect from this process.
+
+ * UIProcess/cf/WebPageProxyCF.cpp: (WebKit::WebPageProxy::restoreFromSessionStateData):
+ Tell process proxy when the process is going to get universal file read sandbox extension.
+
2011-09-22 Alpha Lam <hclam@chromium.org>
https://bugs.webkit.org/show_bug.cgi?id=68081
// FIXME: This code is more or less copied from Pasteboard::getBestURL.
// It would be nice to be able to share the code somehow.
-static void maybeCreateSandboxExtensionFromPasteboard(NSPasteboard *pasteboard, SandboxExtension::Handle& sandboxExtensionHandle)
+static bool maybeCreateSandboxExtensionFromPasteboard(NSPasteboard *pasteboard, SandboxExtension::Handle& sandboxExtensionHandle)
{
NSArray *types = [pasteboard types];
if (![types containsObject:NSFilenamesPboardType])
- return;
+ return false;
NSArray *files = [pasteboard propertyListForType:NSFilenamesPboardType];
if ([files count] != 1)
- return;
+ return false;
NSString *file = [files objectAtIndex:0];
BOOL isDirectory;
if (![[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:&isDirectory])
- return;
+ return false;
if (isDirectory)
- return;
+ return false;
SandboxExtension::createHandle("/", SandboxExtension::ReadOnly, sandboxExtensionHandle);
+ return true;
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)draggingInfo
DragData dragData(draggingInfo, client, global, static_cast<DragOperation>([draggingInfo draggingSourceOperationMask]), [self applicationFlags:draggingInfo]);
SandboxExtension::Handle sandboxExtensionHandle;
- maybeCreateSandboxExtensionFromPasteboard([draggingInfo draggingPasteboard], sandboxExtensionHandle);
+ bool createdExtension = maybeCreateSandboxExtensionFromPasteboard([draggingInfo draggingPasteboard], sandboxExtensionHandle);
+ if (createdExtension)
+ _data->_page->process()->willAcquireUniversalFileReadSandboxExtension();
_data->_page->performDrag(&dragData, [[draggingInfo draggingPasteboard] name], sandboxExtensionHandle);
#include <wtf/RefCountedLeakCounter.h>
#endif
-#define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, process()->connection())
+#define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, m_process->connection())
+#define MESSAGE_CHECK_URL(url) MESSAGE_CHECK_BASE(m_process->checkURLReceivedFromWebProcess(url), m_process->connection())
using namespace WebCore;
WebFrameProxy* frame = m_process->webFrame(frameID);
MESSAGE_CHECK(frame);
MESSAGE_CHECK(frame->page() == page);
-
+ MESSAGE_CHECK_URL(sourceURLString);
+ MESSAGE_CHECK_URL(destinationURLString);
+
m_historyClient.didPerformClientRedirect(this, page, sourceURLString, destinationURLString, frame);
}
WebFrameProxy* frame = m_process->webFrame(frameID);
MESSAGE_CHECK(frame);
MESSAGE_CHECK(frame->page() == page);
-
+ MESSAGE_CHECK_URL(sourceURLString);
+ MESSAGE_CHECK_URL(destinationURLString);
+
m_historyClient.didPerformServerRedirect(this, page, sourceURLString, destinationURLString, frame);
}
WebFrameProxy* frame = m_process->webFrame(frameID);
MESSAGE_CHECK(frame);
MESSAGE_CHECK(frame->page() == page);
+ MESSAGE_CHECK_URL(url);
m_historyClient.didUpdateHistoryTitle(this, page, title, url, frame);
}
void WebContext::getPluginPath(const String& mimeType, const String& urlString, String& pluginPath)
{
+ MESSAGE_CHECK_URL(urlString);
+
String newMimeType = mimeType.lower();
- PluginModuleInfo plugin = pluginInfoStore().findPlugin(newMimeType, KURL(ParsedURLString, urlString));
+ PluginModuleInfo plugin = pluginInfoStore().findPlugin(newMimeType, KURL(KURL(), urlString));
if (!plugin.path)
return;
// This controls what strategy we use for mouse wheel coalescing.
#define MERGE_WHEEL_EVENTS 1
-#define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, process()->connection())
+#define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, m_process->connection())
+#define MESSAGE_CHECK_URL(url) MESSAGE_CHECK_BASE(m_process->checkURLReceivedFromWebProcess(url), m_process->connection())
using namespace WebCore;
return;
SandboxExtension::Handle sandboxExtensionHandle;
- initializeSandboxExtensionHandle(KURL(KURL(), item->url()), sandboxExtensionHandle);
+ bool createdExtension = maybeInitializeSandboxExtensionHandle(KURL(KURL(), item->url()), sandboxExtensionHandle);
+ if (createdExtension)
+ process()->willAcquireUniversalFileReadSandboxExtension();
process()->send(Messages::WebPage::GoToBackForwardItem(item->itemID(), sandboxExtensionHandle), m_pageID);
process()->responsivenessTimer()->start();
}
return false;
}
-void WebPageProxy::initializeSandboxExtensionHandle(const KURL& url, SandboxExtension::Handle& sandboxExtensionHandle)
+bool WebPageProxy::maybeInitializeSandboxExtensionHandle(const KURL& url, SandboxExtension::Handle& sandboxExtensionHandle)
{
if (!url.isLocalFile())
- return;
+ return false;
// Don't give the inspector full access to the file system.
if (WebInspectorProxy::isInspectorPage(this))
- return;
+ return false;
SandboxExtension::createHandle("/", SandboxExtension::ReadOnly, sandboxExtensionHandle);
+ return true;
}
void WebPageProxy::loadURL(const String& url)
reattachToWebProcess();
SandboxExtension::Handle sandboxExtensionHandle;
- initializeSandboxExtensionHandle(KURL(KURL(), url), sandboxExtensionHandle);
+ bool createdExtension = maybeInitializeSandboxExtensionHandle(KURL(KURL(), url), sandboxExtensionHandle);
+ if (createdExtension)
+ process()->willAcquireUniversalFileReadSandboxExtension();
process()->send(Messages::WebPage::LoadURL(url, sandboxExtensionHandle), m_pageID);
process()->responsivenessTimer()->start();
}
reattachToWebProcess();
SandboxExtension::Handle sandboxExtensionHandle;
- initializeSandboxExtensionHandle(urlRequest->resourceRequest().url(), sandboxExtensionHandle);
+ bool createdExtension = maybeInitializeSandboxExtensionHandle(urlRequest->resourceRequest().url(), sandboxExtensionHandle);
+ if (createdExtension)
+ process()->willAcquireUniversalFileReadSandboxExtension();
process()->send(Messages::WebPage::LoadURLRequest(urlRequest->resourceRequest(), sandboxExtensionHandle), m_pageID);
process()->responsivenessTimer()->start();
}
if (!isValid())
reattachToWebProcess();
+ process()->willLoadHTMLStringWithBaseURL(baseURL);
process()->send(Messages::WebPage::LoadHTMLString(htmlString, baseURL), m_pageID);
process()->responsivenessTimer()->start();
}
if (m_mainFrame)
m_mainFrame->setUnreachableURL(unreachableURL);
+ process()->willLoadHTMLStringWithBaseURL(baseURL);
process()->send(Messages::WebPage::LoadAlternateHTMLString(htmlString, baseURL, unreachableURL), m_pageID);
process()->responsivenessTimer()->start();
}
}
SandboxExtension::Handle sandboxExtensionHandle;
- initializeSandboxExtensionHandle(KURL(KURL(), forwardItem->url()), sandboxExtensionHandle);
+ bool createdExtension = maybeInitializeSandboxExtensionHandle(KURL(KURL(), forwardItem->url()), sandboxExtensionHandle);
+ if (createdExtension)
+ process()->willAcquireUniversalFileReadSandboxExtension();
process()->send(Messages::WebPage::GoForward(forwardItem->itemID(), sandboxExtensionHandle), m_pageID);
process()->responsivenessTimer()->start();
}
}
SandboxExtension::Handle sandboxExtensionHandle;
- initializeSandboxExtensionHandle(KURL(KURL(), backItem->url()), sandboxExtensionHandle);
+ bool createdExtension = maybeInitializeSandboxExtensionHandle(KURL(KURL(), backItem->url()), sandboxExtensionHandle);
+ if (createdExtension)
+ process()->willAcquireUniversalFileReadSandboxExtension();
process()->send(Messages::WebPage::GoBack(backItem->itemID(), sandboxExtensionHandle), m_pageID);
process()->responsivenessTimer()->start();
}
setPendingAPIRequestURL(item->url());
SandboxExtension::Handle sandboxExtensionHandle;
- initializeSandboxExtensionHandle(KURL(KURL(), item->url()), sandboxExtensionHandle);
+ bool createdExtension = maybeInitializeSandboxExtensionHandle(KURL(KURL(), item->url()), sandboxExtensionHandle);
+ if (createdExtension)
+ process()->willAcquireUniversalFileReadSandboxExtension();
process()->send(Messages::WebPage::GoToBackForwardItem(item->itemID(), sandboxExtensionHandle), m_pageID);
process()->responsivenessTimer()->start();
}
WebFrameProxy* frame = process()->webFrame(frameID);
MESSAGE_CHECK(frame);
+ MESSAGE_CHECK_URL(url);
frame->setUnreachableURL(unreachableURL);
WebFrameProxy* frame = process()->webFrame(frameID);
MESSAGE_CHECK(frame);
+ MESSAGE_CHECK_URL(url);
frame->didReceiveServerRedirectForProvisionalLoad(url);
WebFrameProxy* frame = process()->webFrame(frameID);
MESSAGE_CHECK(frame);
+ MESSAGE_CHECK_URL(url);
clearPendingAPIRequestURL();
frame->didSameDocumentNavigation(url);
WebFrameProxy* frame = process()->webFrame(frameID);
MESSAGE_CHECK(frame);
+ MESSAGE_CHECK_URL(request.url());
NavigationType navigationType = static_cast<NavigationType>(opaqueNavigationType);
WebEvent::Modifiers modifiers = static_cast<WebEvent::Modifiers>(opaqueModifiers);
WebFrameProxy* frame = process()->webFrame(frameID);
MESSAGE_CHECK(frame);
+ MESSAGE_CHECK_URL(request.url());
NavigationType navigationType = static_cast<NavigationType>(opaqueNavigationType);
WebEvent::Modifiers modifiers = static_cast<WebEvent::Modifiers>(opaqueModifiers);
WebFrameProxy* frame = process()->webFrame(frameID);
MESSAGE_CHECK(frame);
-
+ MESSAGE_CHECK_URL(request.url());
+ MESSAGE_CHECK_URL(response.url());
+
RefPtr<WebFramePolicyListenerProxy> listener = frame->setUpPolicyListenerProxy(listenerID);
ASSERT(!m_inDecidePolicyForMIMEType);
{
WebFrameProxy* frame = process()->webFrame(frameID);
MESSAGE_CHECK(frame);
+ MESSAGE_CHECK_URL(request.url());
m_resourceLoadClient.didInitiateLoadForResource(this, frame, resourceIdentifier, request, pageIsProvisionallyLoading);
}
{
WebFrameProxy* frame = process()->webFrame(frameID);
MESSAGE_CHECK(frame);
+ MESSAGE_CHECK_URL(request.url());
m_resourceLoadClient.didSendRequestForResource(this, frame, resourceIdentifier, request, redirectResponse);
}
{
WebFrameProxy* frame = process()->webFrame(frameID);
MESSAGE_CHECK(frame);
+ MESSAGE_CHECK_URL(response.url());
m_resourceLoadClient.didReceiveResponseForResource(this, frame, resourceIdentifier, response);
}
void WebPageProxy::missingPluginButtonClicked(const String& mimeType, const String& url, const String& pluginsPageURL)
{
+ MESSAGE_CHECK_URL(url);
+ MESSAGE_CHECK_URL(pluginsPageURL);
+
m_uiClient.missingPluginButtonClicked(this, mimeType, url, pluginsPageURL);
}
void clearPendingAPIRequestURL() { m_pendingAPIRequestURL = String(); }
void setPendingAPIRequestURL(const String& pendingAPIRequestURL) { m_pendingAPIRequestURL = pendingAPIRequestURL; }
- void initializeSandboxExtensionHandle(const WebCore::KURL&, SandboxExtension::Handle&);
+ bool maybeInitializeSandboxExtensionHandle(const WebCore::KURL&, SandboxExtension::Handle&);
#if PLATFORM(MAC)
void substitutionsPanelIsShowing(bool&);
using namespace WebCore;
using namespace std;
+#define MESSAGE_CHECK_URL(url) MESSAGE_CHECK_BASE(checkURLReceivedFromWebProcess(url), connection())
+
namespace WebKit {
template<typename HashMap>
WebProcessProxy::WebProcessProxy(PassRefPtr<WebContext> context)
: m_responsivenessTimer(this)
, m_context(context)
+ , m_mayHaveUniversalFileReadSandboxExtension(false)
{
connect();
}
m_backForwardListItemMap.set(item->itemID(), item);
}
+void WebProcessProxy::willLoadHTMLStringWithBaseURL(const String& urlString)
+{
+ KURL url(KURL(), urlString);
+ if (!url.isLocalFile())
+ return;
+
+ // Client loads an alternate string. This doesn't grant universal file read, but the web process is assumed
+ // to have read access to this directory already.
+ m_localPathsWithAssumedReadAccess.add(url.fileSystemPath());
+}
+
+bool WebProcessProxy::checkURLReceivedFromWebProcess(const String& urlString)
+{
+ return checkURLReceivedFromWebProcess(KURL(KURL(), urlString));
+}
+
+bool WebProcessProxy::checkURLReceivedFromWebProcess(const KURL& url)
+{
+ // FIXME: Consider checking that the URL is valid. Currently, WebProcess sends invalid URLs in many cases, but it probably doesn't have good reasons to do that.
+
+ // Any other non-file URL is OK.
+ if (!url.isLocalFile())
+ return true;
+
+ // Any file URL is also OK if we've loaded a file URL through API before, granting universal read access.
+ if (m_mayHaveUniversalFileReadSandboxExtension)
+ return true;
+
+ // If we loaded a string with a file base URL before, loading resources from that subdirectory is fine.
+ // There are no ".." components, because all URLs received from WebProcess are parsed with KURL, which removes those.
+ String path = url.fileSystemPath();
+ for (HashSet<String>::const_iterator iter = m_localPathsWithAssumedReadAccess.begin(); iter != m_localPathsWithAssumedReadAccess.end(); ++iter) {
+ if (path.startsWith(*iter))
+ return true;
+ }
+
+ // A Web process that was never asked to load a file URL should not ever ask us to do anything with a file URL.
+ return false;
+}
+
void WebProcessProxy::addBackForwardItem(uint64_t itemID, const String& originalURL, const String& url, const String& title, const CoreIPC::DataReference& backForwardData)
{
+ MESSAGE_CHECK_URL(originalURL);
+ MESSAGE_CHECK_URL(url);
+
std::pair<WebBackForwardListItemMap::iterator, bool> result = m_backForwardListItemMap.add(itemID, 0);
if (result.second) {
// New item.
void registerNewWebBackForwardListItem(WebBackForwardListItem*);
+ void willAcquireUniversalFileReadSandboxExtension() { m_mayHaveUniversalFileReadSandboxExtension = true; }
+ void willLoadHTMLStringWithBaseURL(const String&);
+
+ bool checkURLReceivedFromWebProcess(const String&);
+ bool checkURLReceivedFromWebProcess(const WebCore::KURL&);
+
// FIXME: This variant of send is deprecated. All clients should move to an overload that take a message type.
template<typename E, typename T> bool deprecatedSend(E messageID, uint64_t destinationID, const T& arguments);
RefPtr<WebContext> m_context;
+ bool m_mayHaveUniversalFileReadSandboxExtension; // True if a read extension for "/" was ever granted - we don't track whether WebProcess still has it.
+ HashSet<String> m_localPathsWithAssumedReadAccess;
+
HashMap<uint64_t, WebPageProxy*> m_pageMap;
WebFrameProxyMap m_frameMap;
WebBackForwardListItemMap m_backForwardListItemMap;
else {
SandboxExtension::Handle sandboxExtensionHandle;
if (WebBackForwardListItem* item = m_backForwardList->currentItem()) {
- initializeSandboxExtensionHandle(KURL(KURL(), item->url()), sandboxExtensionHandle);
+ bool createdExtension = maybeInitializeSandboxExtensionHandle(KURL(KURL(), item->url()), sandboxExtensionHandle);
+ if (createdExtension)
+ process()->willAcquireUniversalFileReadSandboxExtension();
setPendingAPIRequestURL(item->url());
}