Skip to content

Commit f25f08a

Browse files
committed
fix(file_sharing): prevent infinite loop on circular symlinks when duplicates are allowed
1 parent 36651e5 commit f25f08a

2 files changed

Lines changed: 37 additions & 14 deletions

File tree

src/file_sharing/directory_updater.cc

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#include "util/cxx17retrocompat.h"
2626
#include "util/folderiterator.h"
27+
#include <algorithm>
2728
#include "util/rstime.h"
2829
#include "rsserver/p3face.h"
2930
#include "directory_storage.h"
@@ -219,10 +220,13 @@ bool LocalDirectoryUpdater::sweepSharedDirectories(bool& some_files_not_ready)
219220
{
220221
RS_DBG4("recursing into \"", stored_dir_it.name());
221222

222-
existing_dirs.insert(RsDirUtil::removeSymLinks(stored_dir_it.name()));
223+
std::string canonical = RsDirUtil::removeSymLinks(stored_dir_it.name());
224+
existing_dirs.insert(canonical);
225+
std::vector<std::string> current_branch_real_paths;
226+
current_branch_real_paths.push_back(canonical);
223227
recursUpdateSharedDir(
224228
stored_dir_it.name(), *stored_dir_it,
225-
existing_dirs, 1, some_files_not_ready );
229+
existing_dirs, current_branch_real_paths, 1, some_files_not_ready );
226230
/* here we need to use the list that was stored, instead of the shared
227231
* dir list, because the two are not necessarily in the same order. */
228232
}
@@ -240,7 +244,7 @@ bool LocalDirectoryUpdater::sweepSharedDirectories(bool& some_files_not_ready)
240244

241245
void LocalDirectoryUpdater::recursUpdateSharedDir(
242246
const std::string& cumulated_path, DirectoryStorage::EntryIndex indx,
243-
std::set<std::string>& existing_directories, uint32_t current_depth,
247+
std::set<std::string>& existing_directories, std::vector<std::string>& current_branch_real_paths, uint32_t current_depth,
244248
bool& some_files_not_ready )
245249
{
246250
RS_DBG4("parsing directory \"", cumulated_path, "\" index: ", indx);
@@ -300,21 +304,31 @@ void LocalDirectoryUpdater::recursUpdateSharedDir(
300304
|| (mMaxShareDepth == 0 && current_depth >= 64) )
301305
dir_is_accepted = false;
302306

303-
if(dir_is_accepted && mFollowSymLinks && mIgnoreDuplicates)
307+
if(dir_is_accepted && mFollowSymLinks)
304308
{
305309
std::string real_path = RsDirUtil::removeSymLinks(
306310
RsDirUtil::makePath(cumulated_path, dirIt.file_name()) );
307311

308-
if( existing_directories.end() !=
309-
existing_directories.find(real_path) )
312+
if (std::find(current_branch_real_paths.begin(), current_branch_real_paths.end(), real_path) != current_branch_real_paths.end())
310313
{
311-
RS_WARN( "Directory: \"", cumulated_path,
312-
"\" has real path: \"", real_path,
313-
"\" which already belongs to another "
314-
"shared directory. Ignoring" );
314+
RS_WARN( "Circular symlink detected: \"", cumulated_path,
315+
"\" points to ancestor \"", real_path,
316+
"\". Ignoring." );
315317
dir_is_accepted = false;
316318
}
317-
else existing_directories.insert(real_path);
319+
else if(mIgnoreDuplicates)
320+
{
321+
if( existing_directories.end() !=
322+
existing_directories.find(real_path) )
323+
{
324+
RS_WARN( "Directory: \"", cumulated_path,
325+
"\" has real path: \"", real_path,
326+
"\" which already belongs to another "
327+
"shared directory. Ignoring" );
328+
dir_is_accepted = false;
329+
}
330+
else existing_directories.insert(real_path);
331+
}
318332
}
319333

320334
if(dir_is_accepted) subdirs.insert(dirIt.file_name());
@@ -364,9 +378,17 @@ void LocalDirectoryUpdater::recursUpdateSharedDir(
364378
// go through the list of sub-dirs and recursively update
365379
for( DirectoryStorage::DirIterator stored_dir_it(mSharedDirectories, indx);
366380
stored_dir_it; ++stored_dir_it )
367-
recursUpdateSharedDir( RsDirUtil::makePath(cumulated_path, stored_dir_it.name()),
368-
*stored_dir_it, existing_directories,
381+
{
382+
std::string next_path = RsDirUtil::makePath(cumulated_path, stored_dir_it.name());
383+
std::string canonical = RsDirUtil::removeSymLinks(next_path);
384+
current_branch_real_paths.push_back(canonical);
385+
386+
recursUpdateSharedDir( next_path,
387+
*stored_dir_it, existing_directories, current_branch_real_paths,
369388
current_depth+1, some_files_not_ready );
389+
390+
current_branch_real_paths.pop_back();
391+
}
370392
}
371393

372394
bool LocalDirectoryUpdater::filterFile(const std::string& fname) const

src/file_sharing/directory_updater.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "file_sharing/hash_cache.h"
2929
#include "file_sharing/directory_storage.h"
3030
#include "util/rstime.h"
31+
#include <vector>
3132

3233
class LocalDirectoryUpdater: public HashStorageClient, public RsTickingThread
3334
{
@@ -67,7 +68,7 @@ class LocalDirectoryUpdater: public HashStorageClient, public RsTickingThread
6768
virtual void hash_callback(uint32_t client_param, const std::string& name, const RsFileHash& hash, uint64_t size);
6869
virtual bool hash_confirm(uint32_t client_param) ;
6970

70-
void recursUpdateSharedDir(const std::string& cumulated_path, DirectoryStorage::EntryIndex indx, std::set<std::string>& existing_directories, uint32_t current_depth,bool& files_not_ready);
71+
void recursUpdateSharedDir(const std::string& cumulated_path, DirectoryStorage::EntryIndex indx, std::set<std::string>& existing_directories, std::vector<std::string>& current_branch_real_paths, uint32_t current_depth,bool& files_not_ready);
7172
bool sweepSharedDirectories(bool &some_files_not_ready);
7273

7374
private:

0 commit comments

Comments
 (0)