3434#include < iostream>
3535#include < memory>
3636#include < random>
37+ #include < string_view>
3738
3839#include " compact_filter.h"
3940#include " db_util.h"
@@ -1226,7 +1227,40 @@ Status Storage::ReplDataManager::CleanInvalidFiles(Storage *storage, const std::
12261227 return ret;
12271228}
12281229
1230+ Status Storage::ReplDataManager::ValidateReplFileName (const std::string &repl_file) {
1231+ if (repl_file.empty ()) {
1232+ return {Status::NotOK, " empty replication file name" };
1233+ }
1234+ if (repl_file.front () == ' /' ) {
1235+ return {Status::NotOK, fmt::format (" absolute replication file name '{}' is not allowed" , repl_file)};
1236+ }
1237+ if (repl_file.back () == ' /' ) {
1238+ return {Status::NotOK, fmt::format (" unsafe replication file name '{}' is not allowed" , repl_file)};
1239+ }
1240+
1241+ for (size_t begin = 0 ; begin < repl_file.size ();) {
1242+ auto end = repl_file.find (' /' , begin);
1243+ auto component = std::string_view (repl_file).substr (begin, end - begin);
1244+ if (component.empty () || component == " ." || component == " .." ) {
1245+ return {Status::NotOK, fmt::format (" unsafe replication file name '{}' is not allowed" , repl_file)};
1246+ }
1247+ if (component.find (' \0 ' ) != std::string_view::npos || component.find (' \\ ' ) != std::string_view::npos ||
1248+ component.find (' :' ) != std::string_view::npos) {
1249+ return {Status::NotOK, fmt::format (" unsafe replication file name '{}' is not allowed" , repl_file)};
1250+ }
1251+ if (end == std::string::npos) break ;
1252+ begin = end + 1 ;
1253+ }
1254+
1255+ return Status::OK ();
1256+ }
1257+
12291258int Storage::ReplDataManager::OpenDataFile (Storage *storage, const std::string &repl_file, uint64_t *file_size) {
1259+ if (auto s = ValidateReplFileName (repl_file); !s.IsOK ()) {
1260+ ERROR (" [storage] Invalid replication data file '{}': {}" , repl_file, s.Msg ());
1261+ return NullFD;
1262+ }
1263+
12301264 std::string abs_path = storage->config_ ->checkpoint_dir + " /" + repl_file;
12311265 auto s = storage->env_ ->FileExists (abs_path);
12321266 if (!s.ok ()) {
@@ -1282,6 +1316,9 @@ Status Storage::ReplDataManager::ParseMetaAndSave(Storage *storage, rocksdb::Bac
12821316 }
12831317
12841318 auto filename = std::string (line.get (), cptr - line.get () - 1 );
1319+ if (auto s = ValidateReplFileName (filename); !s.IsOK ()) {
1320+ return s;
1321+ }
12851322 while (*(cptr++) != ' ' ) {
12861323 }
12871324
@@ -1311,6 +1348,11 @@ Status MkdirRecursively(rocksdb::Env *env, const std::string &dir) {
13111348
13121349std::unique_ptr<rocksdb::WritableFile> Storage::ReplDataManager::NewTmpFile (Storage *storage, const std::string &dir,
13131350 const std::string &repl_file) {
1351+ if (auto s = ValidateReplFileName (repl_file); !s.IsOK ()) {
1352+ ERROR (" [storage] Invalid replication data file '{}': {}" , repl_file, s.Msg ());
1353+ return nullptr ;
1354+ }
1355+
13141356 std::string tmp_file = dir + " /" + repl_file + " .tmp" ;
13151357 auto s = storage->env_ ->FileExists (tmp_file);
13161358 if (s.ok ()) {
@@ -1335,6 +1377,10 @@ std::unique_ptr<rocksdb::WritableFile> Storage::ReplDataManager::NewTmpFile(Stor
13351377}
13361378
13371379Status Storage::ReplDataManager::SwapTmpFile (Storage *storage, const std::string &dir, const std::string &repl_file) {
1380+ if (auto s = ValidateReplFileName (repl_file); !s.IsOK ()) {
1381+ return s;
1382+ }
1383+
13381384 std::string tmp_file = dir + " /" + repl_file + " .tmp" ;
13391385 std::string orig_file = dir + " /" + repl_file;
13401386
@@ -1349,6 +1395,7 @@ Status Storage::ReplDataManager::SwapTmpFile(Storage *storage, const std::string
13491395bool Storage::ReplDataManager::FileExists (Storage *storage, const std::string &dir, const std::string &repl_file,
13501396 uint32_t crc) {
13511397 if (storage->IsClosing ()) return false ;
1398+ if (!ValidateReplFileName (repl_file).IsOK ()) return false ;
13521399
13531400 auto file_path = dir + " /" + repl_file;
13541401 auto s = storage->env_ ->FileExists (file_path);
0 commit comments