Bug 670514 - Arbitrary File + Directory read via .lnk files on Windows Share. r=bz
authorBrian R. Bondy <netzen@gmail.com>
Thu, 03 May 2012 15:23:28 -0400
changeset 93039 60613f18435b3f3da1a997b6c228bf339004bbaa
parent 93004 a0356446a56a2e98d5aaf6c12aa3d826408688ee
child 93040 c045085c0436cf1ef4c4a4447c54b24e7894501e
push id8947
push usereakhgari@mozilla.com
push dateThu, 03 May 2012 21:33:59 +0000
treeherdermozilla-inbound@10cd5a5210f2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs670514
milestone15.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 670514 - Arbitrary File + Directory read via .lnk files on Windows Share. r=bz
netwerk/base/public/nsNetUtil.h
netwerk/protocol/file/nsFileChannel.cpp
netwerk/protocol/file/nsFileChannel.h
xpcom/io/nsLocalFileWin.cpp
--- a/netwerk/base/public/nsNetUtil.h
+++ b/netwerk/base/public/nsNetUtil.h
@@ -224,18 +224,24 @@ NS_NewChannel(nsIChannel           **res
     if (ioService) {
         nsCOMPtr<nsIChannel> chan;
         rv = ioService->NewChannelFromURI(uri, getter_AddRefs(chan));
         if (NS_SUCCEEDED(rv)) {
             if (loadGroup)
                 rv |= chan->SetLoadGroup(loadGroup);
             if (callbacks)
                 rv |= chan->SetNotificationCallbacks(callbacks);
-            if (loadFlags != nsIRequest::LOAD_NORMAL)
-                rv |= chan->SetLoadFlags(loadFlags);
+            if (loadFlags != nsIRequest::LOAD_NORMAL) {
+                // Retain the LOAD_REPLACE load flag if set.
+                nsLoadFlags normalLoadFlags = 0;
+                chan->GetLoadFlags(&normalLoadFlags);
+                rv |= chan->SetLoadFlags(loadFlags | 
+                                         (normalLoadFlags & 
+                                          nsIChannel::LOAD_REPLACE));
+            }
             if (channelPolicy) {
                 nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(chan);
                 if (props) {
                     props->SetPropertyAsInterface(NS_CHANNEL_PROP_CHANNEL_POLICY,
                                                   channelPolicy);
                 }
             }
             if (NS_SUCCEEDED(rv))
--- a/netwerk/protocol/file/nsFileChannel.cpp
+++ b/netwerk/protocol/file/nsFileChannel.cpp
@@ -268,16 +268,46 @@ nsFileUploadContentStream::OnCopyComplet
   // This method is being called to indicate that we are done copying.
   nsresult status = mCopyEvent->Status();
 
   CloseWithStatus(NS_FAILED(status) ? status : NS_BASE_STREAM_CLOSED);
 }
 
 //-----------------------------------------------------------------------------
 
+nsFileChannel::nsFileChannel(nsIURI *uri) 
+{
+  // If we have a link file, we should resolve its target right away.
+  // This is to protect against a same origin attack where the same link file
+  // can point to different resources right after the first resource is loaded.
+  nsCOMPtr<nsIFile> file;
+  nsCOMPtr <nsIURI> targetURI;
+  nsCAutoString fileTarget;
+  nsCOMPtr<nsILocalFile> resolvedFile;
+  bool symLink;
+  nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(uri);
+  if (fileURL && 
+      NS_SUCCEEDED(fileURL->GetFile(getter_AddRefs(file))) &&
+      NS_SUCCEEDED(file->IsSymlink(&symLink)) && 
+      symLink &&
+      NS_SUCCEEDED(file->GetNativeTarget(fileTarget)) &&
+      NS_SUCCEEDED(NS_NewNativeLocalFile(fileTarget, PR_TRUE, 
+                                         getter_AddRefs(resolvedFile))) &&
+      NS_SUCCEEDED(NS_NewFileURI(getter_AddRefs(targetURI), 
+                   resolvedFile, nsnull))) {
+    SetURI(targetURI);
+    SetOriginalURI(uri);
+    nsLoadFlags loadFlags = 0;
+    GetLoadFlags(&loadFlags);
+    SetLoadFlags(loadFlags | nsIChannel::LOAD_REPLACE);
+  } else {
+    SetURI(uri);
+  }
+}
+
 nsresult
 nsFileChannel::MakeFileInputStream(nsIFile *file,
                                    nsCOMPtr<nsIInputStream> &stream,
                                    nsCString &contentType)
 {
   // we accept that this might result in a disk hit to stat the file
   bool isDir;
   nsresult rv = file->IsDirectory(&isDir);
--- a/netwerk/protocol/file/nsFileChannel.h
+++ b/netwerk/protocol/file/nsFileChannel.h
@@ -48,19 +48,17 @@ class nsFileChannel : public nsBaseChann
                     , public nsIFileChannel
                     , public nsIUploadChannel
 {
 public: 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIFILECHANNEL
   NS_DECL_NSIUPLOADCHANNEL
 
-  nsFileChannel(nsIURI *uri) {
-    SetURI(uri);
-  }
+  nsFileChannel(nsIURI *uri);
 
 protected:
   // Called to construct a blocking file input stream for the given file.  This
   // method also returns a best guess at the content-type for the data stream.
   // NOTE: If the channel has a type hint set, contentType will be left
   // untouched. The caller should not use it in that case.
   nsresult MakeFileInputStream(nsIFile *file, nsCOMPtr<nsIInputStream> &stream,
                                nsCString &contentType);
--- a/xpcom/io/nsLocalFileWin.cpp
+++ b/xpcom/io/nsLocalFileWin.cpp
@@ -2920,29 +2920,32 @@ NS_IMETHODIMP
 nsLocalFile::IsSymlink(bool *_retval)
 {
     // Check we are correctly initialized.
     CHECK_mWorkingPath();
 
     NS_ENSURE_ARG(_retval);
 
     // unless it is a valid shortcut path it's not a symlink
-    if (!IsShortcutPath(mWorkingPath))
-    {
+    if (!IsShortcutPath(mWorkingPath)) {
         *_retval = false;
         return NS_OK;
     }
 
     // we need to know if this is a file or directory
     nsresult rv = ResolveAndStat();
-    if (NS_FAILED(rv))
+    if (NS_FAILED(rv)) {
         return rv;
-
-    // it's only a shortcut if it is a file
-    *_retval = (mFileInfo64.type == PR_FILE_FILE);
+    }
+
+    // We should not check mFileInfo64.type here for PR_FILE_FILE because lnk
+    // files can point to directories or files.  Important security checks
+    // depend on correctly identifying lnk files.  mFileInfo64 now holds info
+    // about the target of the lnk file, not the actual lnk file!
+    *_retval = true;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsLocalFile::IsSpecial(bool *_retval)
 {
     return HasFileAttribute(FILE_ATTRIBUTE_SYSTEM, _retval);
 }