Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion php/Torrent.php
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,11 @@ public function scandir( $dir )
if( $item != '.' && $item != '..')
{
$path = $dir . DIRECTORY_SEPARATOR . $item;
if(is_link($path) && (strpos(realpath( $path ),$this->basedir.'/')===0))
// A link back into the folder would be read twice, and one out
// of the top directory would be read, and served once seeded,
// from wherever it points.
if(is_link($path) && ((strpos(realpath( $path ),$this->basedir.'/')===0) ||
!self::isInsideTopDirectory(realpath( $path ))))
continue;
if(is_dir( $path ))
$paths = array_merge( self::scandir( $path ), $paths );
Expand All @@ -757,6 +761,22 @@ public function scandir( $dir )
return $paths;
}

/** Whether $real, a resolved path, is inside $topDirectory
* @param string|false resolved path
* @return boolean
*/
static private function isInsideTopDirectory( $real )
{
global $topDirectory;
if(!isset($topDirectory) || (FileUtil::addslash($topDirectory) === '/'))
return(true);
if($real === false)
return(false);
$top = realpath($topDirectory);
$top = FileUtil::addslash(($top === false) ? $topDirectory : $top);
return(strpos(FileUtil::addslash($real), $top) === 0);
}

/** Helper to pack data hash
* @param string data
* @return string packed data hash
Expand Down
5 changes: 4 additions & 1 deletion plugins/autotools/check.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@
if( $dest_path != $source_path )
{
$files = $is_multy ? rtScanFiles( $source_path, '/.*/' ) : array( $base_name );
if( $at->skipsMove( $files ) || rtTakenDestination( $files, $dest_path ) != '' )
// The move follows links, so the destination has to stay inside the top
// directory once they are followed, not only as the settings wrote it.
if( !rTorrent::isInsideTopDirectory( $dest_path ) ||
$at->skipsMove( $files ) || rtTakenDestination( $files, $dest_path ) != '' )
$dest_path = $source_path;
}

Expand Down
6 changes: 6 additions & 0 deletions plugins/autotools/move.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ function operationOnTorrentFiles($torrent,&$base_path,$base_file,$is_multy_file,
$dest_path.=FileUtil::addslash($label);
if($at->addName && ($name!=''))
$dest_path.=FileUtil::addslash($name);
// Checked here as well as in check.php: the older and the
// copy and link hooks run this script alone.
$target = $dest_path.($is_multi ? rtAddTailSlash( $base_name ) : '');
if(!rTorrent::isInsideTopDirectory($target))
Debug( "outside the top directory: ".$target );
else
if(operationOnTorrentFiles($torrent,$base_path,$base_name,$is_multi,$dest_path,$fileop_type))
{
// if($fileop_type=="Move")
Expand Down
1 change: 1 addition & 0 deletions plugins/autotools/util_rt.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

require_once( "../../php/xmlrpc.php" );
require_once( "../../php/Torrent.php" );
require_once( "../../php/rtorrent.php" );

//------------------------------------------------------------------------------
// Debug stub
Expand Down
18 changes: 17 additions & 1 deletion plugins/autotools/watch.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ function Debug( $str )
$auto_start = $at->watch_start;
$path_to_watch = rtAddTailSlash( trim( $at->path_to_watch ) );
Debug( "path_to_watch : ".$path_to_watch );
if( $path_to_watch == '' || $path_to_watch == '/' )
// The scan, the touch and the load follow links, so the directory has
// to stay inside the top directory once they are followed.
if( $path_to_watch == '' || $path_to_watch == '/' ||
!rTorrent::isInsideTopDirectory( $path_to_watch ) )
$is_ok = false;
}
else $is_ok = false;
Expand All @@ -59,6 +62,13 @@ function Debug( $str )
Debug( "torrent file : ".$torrent_file );
Debug( "save data to : ".$dest_path );

// A link inside the watch directory is followed by the scan.
if( !rTorrent::isInsideTopDirectory( $torrent_file ) )
{
Debug( "outside the top directory: ".$torrent_file );
continue;
}

$is_ok = true;
// rTorrent store info about all added torrents,
// so we must change $torrent_file's time to trick rTorrent.
Expand All @@ -69,6 +79,12 @@ function Debug( $str )
$is_ok = false;
}

if( $is_ok && !rTorrent::isInsideTopDirectory( $dest_path ) )
{
Debug( "outside the top directory: ".$dest_path );
$is_ok = false;
}

if( $is_ok && !rtMkDir( $dest_path, 0777 ) )
{
Debug( "can't create ".$dest_path );
Expand Down
5 changes: 4 additions & 1 deletion plugins/create/action.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,10 @@ static public function getTrackerDomain($announce)
$path_edit = trim($_REQUEST['path_edit']);
if(is_dir($path_edit))
$path_edit = FileUtil::addslash($path_edit);
if(rTorrentSettings::get()->correctDirectory($path_edit))
// What is hashed here is served once it is seeded, so it has to
// stay inside the top directory once links are followed.
if(rTorrentSettings::get()->correctDirectory($path_edit) &&
rTorrent::isInsideTopDirectory($path_edit))
{
$rt = recentTrackers::load();
$trackers = array();
Expand Down
11 changes: 9 additions & 2 deletions plugins/httprpc/action.php
Original file line number Diff line number Diff line change
Expand Up @@ -570,8 +570,15 @@ function makeSimpleCall($cmds,$hash)
{
if($ss[$ndx][0]=='n')
$v = floatval($v);
if( ($ss[$ndx]=="sdirectory") && !rTorrentSettings::get()->correctDirectory($v) )
continue;
// A download added without a directory of its own is written
// there through any link along it, so it has to stay inside the
// top directory once they are followed, not only as written.
if( $ss[$ndx]=="sdirectory" )
{
require_once( '../../php/rtorrent.php' );
if( !rTorrentSettings::get()->correctDirectory($v) || !rTorrent::isInsideTopDirectory($v) )
continue;
}
$socketAlloc = rTorrentSettings::get()->getSocketAllocCategory($ss[$ndx]);
if($ss[$ndx]=="ndht")
$cmd = new rXMLRPCCommand('dht',(($v==0) ? "disable" : "auto"));
Expand Down
18 changes: 18 additions & 0 deletions plugins/unpack/unpack.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php
require_once( dirname(__FILE__)."/../../php/xmlrpc.php" );
require_once( dirname(__FILE__)."/../../php/rtorrent.php" );
require_once( dirname(__FILE__)."/../../php/cache.php");
require_once( dirname(__FILE__)."/../../php/settings.php");
require_once( dirname(__FILE__).'/../_task/task.php' );
Expand Down Expand Up @@ -256,6 +257,11 @@ public function startSilentTask($basename,$downloadname,$label,$name,$hash)
$outPath.=FileUtil::addslash($label);
if($this->addName && ($name!=''))
$outPath.=FileUtil::addslash($name);
if(!rTorrent::isInsideTopDirectory($outPath))
{
self::log("[Auto] Not unpacked: [$outPath] is outside the top directory");
return;
}
if($unpackToTemp)
{
$randTempDirectory = FileUtil::addslash( FileUtil::getTempFilename('unpack') );
Expand Down Expand Up @@ -337,6 +343,12 @@ public function startTask( $hash, $outPath, $mode, $fileno )

if($outPath=='')
$outPath = dirname($filename);
if(!rTorrent::isInsideTopDirectory($outPath))
{
self::log("[Manual] Not unpacked: [$outPath] is outside the top directory");
$ret["errors"] = array("The directory is outside the top directory. Unpack failed.");
return($ret);
}

$commands = array();
$arh = Utility::getExternal( ($mode == "zip") ? 'unzip' : 'unrar' );
Expand Down Expand Up @@ -419,6 +431,12 @@ public function startTask( $hash, $outPath, $mode, $fileno )
$outPath.=FileUtil::addslash($label);
if($this->addName && ($tname!=''))
$outPath.=FileUtil::addslash($tname);
if(!rTorrent::isInsideTopDirectory($outPath))
{
self::log("[Manual] Not unpacked: [$outPath] is outside the top directory");
$ret["errors"] = array("The directory is outside the top directory. Unpack failed.");
return($ret);
}

$commands[] = escapeshellarg($rootPath.'/plugins/unpack/un'.$mode.$postfix.'.sh')." ".
escapeshellarg($arh)." ".
Expand Down
Loading
Loading