summaryrefslogtreecommitdiff
path: root/indra/llmessage/llxfermanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llmessage/llxfermanager.cpp')
-rw-r--r--indra/llmessage/llxfermanager.cpp190
1 files changed, 148 insertions, 42 deletions
diff --git a/indra/llmessage/llxfermanager.cpp b/indra/llmessage/llxfermanager.cpp
index fc75b3ae75..b9cddc8e45 100644
--- a/indra/llmessage/llxfermanager.cpp
+++ b/indra/llmessage/llxfermanager.cpp
@@ -2,30 +2,25 @@
* @file llxfermanager.cpp
* @brief implementation of LLXferManager class for a collection of xfers
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -64,7 +59,7 @@ LLXferManager::LLXferManager (LLVFS *vfs)
LLXferManager::~LLXferManager ()
{
- free();
+ cleanup();
}
///////////////////////////////////////////////////////////
@@ -86,7 +81,7 @@ void LLXferManager::init (LLVFS *vfs)
///////////////////////////////////////////////////////////
-void LLXferManager::free ()
+void LLXferManager::cleanup ()
{
LLXfer *xferp;
LLXfer *delp;
@@ -406,8 +401,8 @@ U64 LLXferManager::registerXfer(const void *datap, const S32 length)
///////////////////////////////////////////////////////////
-void LLXferManager::requestFile(const char* local_filename,
- const char* remote_filename,
+void LLXferManager::requestFile(const std::string& local_filename,
+ const std::string& remote_filename,
ELLPath remote_path,
const LLHost& remote_host,
BOOL delete_remote_on_completion,
@@ -444,7 +439,7 @@ void LLXferManager::requestFile(const char* local_filename,
// Note: according to AaronB, this is here to deal with locks on files that were
// in transit during a crash,
if(delete_remote_on_completion &&
- (strstr(remote_filename,".tmp") == &remote_filename[strlen(remote_filename)-4])) /* Flawfinder : ignore */
+ (remote_filename.substr(remote_filename.length()-4) == ".tmp"))
{
LLFile::remove(local_filename);
}
@@ -464,7 +459,7 @@ void LLXferManager::requestFile(const char* local_filename,
}
}
-void LLXferManager::requestFile(const char* remote_filename,
+void LLXferManager::requestFile(const std::string& remote_filename,
ELLPath remote_path,
const LLHost& remote_host,
BOOL delete_remote_on_completion,
@@ -540,7 +535,7 @@ void LLXferManager::requestVFile(const LLUUID& local_id,
/*
void LLXferManager::requestXfer(
- const char *local_filename,
+ const std::string& local_filename,
BOOL delete_remote_on_completion,
U64 xfer_id,
const LLHost &remote_host,
@@ -634,11 +629,11 @@ void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user
// confirm it if it was a resend of the last one, since the confirmation might have gotten dropped
if (decodePacketNum(packetnum) == (xferp->mPacketNum - 1))
{
- llinfos << "Reconfirming xfer " << xferp->mRemoteHost << ":" << xferp->getName() << " packet " << packetnum << llendl; sendConfirmPacket(mesgsys, id, decodePacketNum(packetnum), mesgsys->getSender());
+ llinfos << "Reconfirming xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet " << packetnum << llendl; sendConfirmPacket(mesgsys, id, decodePacketNum(packetnum), mesgsys->getSender());
}
else
{
- llinfos << "Ignoring xfer " << xferp->mRemoteHost << ":" << xferp->getName() << " recv'd packet " << packetnum << "; expecting " << xferp->mPacketNum << llendl;
+ llinfos << "Ignoring xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " recv'd packet " << packetnum << "; expecting " << xferp->mPacketNum << llendl;
}
return;
}
@@ -713,11 +708,89 @@ void LLXferManager::sendConfirmPacket (LLMessageSystem *mesgsys, U64 id, S32 pac
///////////////////////////////////////////////////////////
+static bool find_and_remove(std::multiset<std::string>& files,
+ const std::string& filename)
+{
+ std::multiset<std::string>::iterator ptr;
+ if ( (ptr = files.find(filename)) != files.end())
+ {
+ //erase(filename) erases *all* entries with that key
+ files.erase(ptr);
+ return true;
+ }
+ return false;
+}
+
+void LLXferManager::expectFileForRequest(const std::string& filename)
+{
+ mExpectedRequests.insert(filename);
+}
+
+bool LLXferManager::validateFileForRequest(const std::string& filename)
+{
+ return find_and_remove(mExpectedRequests, filename);
+}
+
+void LLXferManager::expectFileForTransfer(const std::string& filename)
+{
+ mExpectedTransfers.insert(filename);
+}
+
+bool LLXferManager::validateFileForTransfer(const std::string& filename)
+{
+ return find_and_remove(mExpectedTransfers, filename);
+}
+
+static bool remove_prefix(std::string& filename, const std::string& prefix)
+{
+ if (std::equal(prefix.begin(), prefix.end(), filename.begin()))
+ {
+ filename = filename.substr(prefix.length());
+ return true;
+ }
+ return false;
+}
+
+static bool verify_cache_filename(const std::string& filename)
+{
+ //NOTE: This routine is only used to check file names that our own
+ // code places in the cache directory. As such, it can be limited
+ // to this very restrictive file name pattern. It does not need to
+ // handle other characters. The only known uses of this are (with examples):
+ // sim to sim object pass: fc0b72d8-9456-63d9-a802-a557ef847313.tmp
+ // sim to viewer mute list: mute_b78eacd0-1244-448e-93ca-28ede242f647.tmp
+ // sim to viewer task inventory: inventory_d8ab59d2-baf0-0e79-c4c2-a3f99b9fcf45.tmp
+
+ //IMPORTANT: Do not broaden the filenames accepted by this routine
+ // without careful analysis. Anything allowed by this function can
+ // be downloaded by the viewer.
+
+ size_t len = filename.size();
+ //const boost::regex expr("[0-9a-zA-Z_-]<1,46>\.tmp");
+ if (len < 5 || len > 50)
+ {
+ return false;
+ }
+ for(size_t i=0; i<(len-4); ++i)
+ {
+ char c = filename[i];
+ bool ok = isalnum(c) || '_'==c || '-'==c;
+ if (!ok)
+ {
+ return false;
+ }
+ }
+ return filename[len-4] == '.'
+ && filename[len-3] == 't'
+ && filename[len-2] == 'm'
+ && filename[len-1] == 'p';
+}
+
void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user_data*/)
{
U64 id;
- char local_filename[MAX_STRING]; /* Flawfinder : ignore */
+ std::string local_filename;
ELLPath local_path = LL_PATH_NONE;
S32 result = LL_ERR_NOERR;
LLUUID uuid;
@@ -732,18 +805,13 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user
llinfos << "xfer request id: " << U64_to_str(id, U64_BUF, sizeof(U64_BUF))
<< " to " << mesgsys->getSender() << llendl;
- mesgsys->getStringFast(_PREHASH_XferID, _PREHASH_Filename, MAX_STRING, local_filename);
+ mesgsys->getStringFast(_PREHASH_XferID, _PREHASH_Filename, local_filename);
- U8 local_path_u8;
- mesgsys->getU8("XferID", "FilePath", local_path_u8);
- if( local_path_u8 < (U8)LL_PATH_COUNT )
{
+ U8 local_path_u8;
+ mesgsys->getU8("XferID", "FilePath", local_path_u8);
local_path = (ELLPath)local_path_u8;
}
- else
- {
- llwarns << "Invalid file path in LLXferManager::processFileRequest() " << (U32)local_path_u8 << llendl;
- }
mesgsys->getUUIDFast(_PREHASH_XferID, _PREHASH_VFileID, uuid);
mesgsys->getS16Fast(_PREHASH_XferID, _PREHASH_VFileType, type_s16);
@@ -780,8 +848,45 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user
llerrs << "Xfer allcoation error" << llendl;
}
}
- else if (strlen(local_filename)) /* Flawfinder : ignore */
+ else if (!local_filename.empty())
{
+ // See DEV-21775 for detailed security issues
+
+ if (local_path == LL_PATH_NONE)
+ {
+ // this handles legacy simulators that are passing objects
+ // by giving a filename that explicitly names the cache directory
+ static const std::string legacy_cache_prefix = "data/";
+ if (remove_prefix(local_filename, legacy_cache_prefix))
+ {
+ local_path = LL_PATH_CACHE;
+ }
+ }
+
+ switch (local_path)
+ {
+ case LL_PATH_NONE:
+ if(!validateFileForTransfer(local_filename))
+ {
+ llwarns << "SECURITY: Unapproved filename '" << local_filename << llendl;
+ return;
+ }
+ break;
+
+ case LL_PATH_CACHE:
+ if(!verify_cache_filename(local_filename))
+ {
+ llwarns << "SECURITY: Illegal cache filename '" << local_filename << llendl;
+ return;
+ }
+ break;
+
+ default:
+ llwarns << "SECURITY: Restricted file dir enum: " << (U32)local_path << llendl;
+ return;
+ }
+
+
std::string expanded_filename = gDirUtilp->getExpandedFilename( local_path, local_filename );
llinfos << "starting file transfer: " << expanded_filename << " to " << mesgsys->getSender() << llendl;
@@ -861,6 +966,7 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user
}
}
+
///////////////////////////////////////////////////////////
void LLXferManager::processConfirmation (LLMessageSystem *mesgsys, void ** /*user_data*/)
@@ -923,7 +1029,7 @@ void LLXferManager::retransmitUnackedPackets ()
{
if (xferp->mRetries > LL_PACKET_RETRY_LIMIT)
{
- llinfos << "dropping xfer " << xferp->mRemoteHost << ":" << xferp->getName() << " packet retransmit limit exceeded, xfer dropped" << llendl;
+ llinfos << "dropping xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet retransmit limit exceeded, xfer dropped" << llendl;
xferp->abort(LL_ERR_TCP_TIMEOUT);
delp = xferp;
xferp = xferp->mNext;
@@ -931,7 +1037,7 @@ void LLXferManager::retransmitUnackedPackets ()
}
else
{
- llinfos << "resending xfer " << xferp->mRemoteHost << ":" << xferp->getName() << " packet unconfirmed after: "<< et << " sec, packet " << xferp->mPacketNum << llendl;
+ llinfos << "resending xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet unconfirmed after: "<< et << " sec, packet " << xferp->mPacketNum << llendl;
xferp->resendLastPacket();
xferp = xferp->mNext;
}
@@ -946,7 +1052,7 @@ void LLXferManager::retransmitUnackedPackets ()
}
else if (xferp->mStatus == e_LL_XFER_ABORTED)
{
- llwarns << "Removing aborted xfer " << xferp->mRemoteHost << ":" << xferp->getName() << llendl;
+ llwarns << "Removing aborted xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << llendl;
delp = xferp;
xferp = xferp->mNext;
removeXfer(delp,&mSendList);