Skip to content

Commit fe0f12b

Browse files
Follow symlinks in the FileRegexMatch procedure (#1173)
1 parent 1be8f4b commit fe0f12b

File tree

2 files changed

+79
-1
lines changed

2 files changed

+79
-1
lines changed

src/modules/complianceengine/src/lib/procedures/FileRegexMatch.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,28 @@ Result<Status> AuditFileRegexMatch(const AuditFileRegexMatchParams& params, Indi
144144
struct dirent* entry = nullptr;
145145
for (errno = 0, entry = readdir(dir); nullptr != entry; errno = 0, entry = readdir(dir))
146146
{
147-
if (entry->d_type != DT_REG)
147+
if (entry->d_type != DT_REG && entry->d_type != DT_LNK)
148148
{
149149
continue;
150150
}
151151

152+
if (entry->d_type == DT_LNK)
153+
{
154+
struct stat st;
155+
if (0 != stat((params.path + "/" + entry->d_name).c_str(), &st))
156+
{
157+
const int status = errno;
158+
OsConfigLogInfo(context.GetLogHandle(), "Failed to stat file '%s/%s': %s", params.path.c_str(), entry->d_name, strerror(status));
159+
errorCount++;
160+
continue;
161+
}
162+
163+
if (!S_ISREG(st.st_mode))
164+
{
165+
continue;
166+
}
167+
}
168+
152169
if (!regex_match(entry->d_name, params.filenamePattern))
153170
{
154171
OsConfigLogDebug(context.GetLogHandle(), "Ignoring file '%s' in directory '%s'", entry->d_name, params.path.c_str());

src/modules/complianceengine/tests/procedures/FileRegexMatchTest.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,3 +527,64 @@ TEST_F(FileRegexMatchTest, Audit_TestPattern)
527527
ASSERT_TRUE(result.HasValue());
528528
EXPECT_EQ(result.Value(), Status::Compliant);
529529
}
530+
531+
TEST_F(FileRegexMatchTest, Audit_SymlinkFollow_1)
532+
{
533+
MakeTempfile("test");
534+
const auto targetFilename = mTempfiles.back();
535+
const auto linkFilename = targetFilename + ".link";
536+
537+
AuditFileRegexMatchParams params;
538+
params.path = mTempdir;
539+
params.filenamePattern = regex(".*\\.link");
540+
params.matchOperation = Operation::Match;
541+
params.matchPattern = R"(^test$)";
542+
params.behavior = Behavior::AtLeastOneExists;
543+
544+
ASSERT_EQ(0, symlink(targetFilename.c_str(), linkFilename.c_str()));
545+
auto result = AuditFileRegexMatch(params, mIndicators, mContext);
546+
EXPECT_EQ(0, unlink(linkFilename.c_str()));
547+
ASSERT_TRUE(result.HasValue());
548+
EXPECT_EQ(result.Value(), Status::Compliant);
549+
}
550+
551+
TEST_F(FileRegexMatchTest, Audit_SymlinkFollow_2)
552+
{
553+
MakeTempfile("test");
554+
const auto targetFilename = mTempfiles.back();
555+
const auto linkFilename = targetFilename + ".link";
556+
557+
AuditFileRegexMatchParams params;
558+
params.path = mTempdir;
559+
params.filenamePattern = regex(".*\\.link");
560+
params.matchOperation = Operation::Match;
561+
params.matchPattern = R"(^foo$)"; // pattern mismatch against 'test'
562+
params.behavior = Behavior::AtLeastOneExists;
563+
564+
ASSERT_EQ(0, symlink(targetFilename.c_str(), linkFilename.c_str()));
565+
auto result = AuditFileRegexMatch(params, mIndicators, mContext);
566+
EXPECT_EQ(0, unlink(linkFilename.c_str()));
567+
ASSERT_TRUE(result.HasValue());
568+
EXPECT_EQ(result.Value(), Status::NonCompliant);
569+
}
570+
571+
TEST_F(FileRegexMatchTest, Audit_SymlinkFollow_Directory)
572+
{
573+
const auto targetDirectory = std::string(mTempdir) + "/Audit_SymlinkFollow_Directory";
574+
const auto linkFilename = targetDirectory + ".link";
575+
576+
AuditFileRegexMatchParams params;
577+
params.path = mTempdir;
578+
params.filenamePattern = regex(".*\\.link");
579+
params.matchOperation = Operation::Match;
580+
params.matchPattern = R"(.*)";
581+
params.behavior = Behavior::NoneExist;
582+
583+
ASSERT_EQ(0, mkdir(targetDirectory.c_str(), 0755));
584+
EXPECT_EQ(0, symlink(targetDirectory.c_str(), linkFilename.c_str()));
585+
auto result = AuditFileRegexMatch(params, mIndicators, mContext);
586+
EXPECT_EQ(0, unlink(linkFilename.c_str()));
587+
EXPECT_EQ(0, rmdir(targetDirectory.c_str()));
588+
ASSERT_TRUE(result.HasValue());
589+
EXPECT_EQ(result.Value(), Status::Compliant);
590+
}

0 commit comments

Comments
 (0)