Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
dbdb7ca
Update archive_manager.c
Abhinavpv28 Aug 2, 2026
f805602
Update backup_engine.c
Abhinavpv28 Aug 2, 2026
59a0433
Update backup_engine_gtest.cpp
Abhinavpv28 Aug 2, 2026
dc1a188
Update backup_engine_gtest.cpp
Abhinavpv28 Aug 2, 2026
79281ba
Update Makefile.am
Abhinavpv28 Aug 4, 2026
0843ea2
Update Makefile.am
Abhinavpv28 Aug 4, 2026
c23a118
Update Makefile.am
Abhinavpv28 Aug 4, 2026
517173e
Merge branch 'develop' into feature/RDKEMW-20522
Abhinavpv28 Aug 4, 2026
4613adc
Update backup_engine_gtest.cpp
Abhinavpv28 Aug 5, 2026
cc0deb6
Update backup_logs_gtest.cpp
Abhinavpv28 Aug 5, 2026
792f5dd
Update Makefile.am
Abhinavpv28 Aug 5, 2026
f30b879
Update backup_engine_gtest.cpp
Abhinavpv28 Aug 6, 2026
4be9bd6
Update backup_logs_gtest.cpp
Abhinavpv28 Aug 6, 2026
e09d745
Update backup_logs_gtest.cpp
Abhinavpv28 Aug 6, 2026
e13294d
Update backup_engine_gtest.cpp
Abhinavpv28 Aug 6, 2026
adca909
Update backup_logs_gtest.cpp
Abhinavpv28 Aug 6, 2026
6406ac0
Update Makefile.am
Abhinavpv28 Aug 6, 2026
3f83c49
Update backup_engine_gtest.cpp
Abhinavpv28 Aug 6, 2026
6831dae
Update Makefile.am
Abhinavpv28 Aug 6, 2026
adfd24f
Update Makefile.am
Abhinavpv28 Aug 6, 2026
acf7b0c
Update Makefile.am
Abhinavpv28 Aug 6, 2026
1f4c138
Update Makefile.am
Abhinavpv28 Aug 6, 2026
7d35452
Update backup_engine_gtest.cpp
Abhinavpv28 Aug 6, 2026
1d99bf0
Update backup_engine.c
Abhinavpv28 Aug 6, 2026
89791d0
Clean up mock functions and tests for backup logs
Abhinavpv28 Aug 7, 2026
6f0b93e
Remove -U_FORTIFY_SOURCE from backup_engine_gtest_CFLAGS
Abhinavpv28 Aug 7, 2026
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
35 changes: 18 additions & 17 deletions backup_logs/src/backup_engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -373,8 +373,14 @@ int backup_and_recover_logs(const char* source, const char* dest,
return BACKUP_ERROR_INVALID_PARAM;
}
/* Open source directory */
DIR* dir = opendir(source);
int dirfd = open(source, O_RDONLY | O_DIRECTORY);
if (dirfd < 0) {
RDK_LOG(RDK_LOG_ERROR, LOG_BACKUP_LOGS, "Failed to open source directory: %s\n", source);
return BACKUP_ERROR_FILESYSTEM;
}
DIR* dir = fdopendir(dirfd);
if (!dir) {
close(dirfd);
RDK_LOG(RDK_LOG_ERROR, LOG_BACKUP_LOGS, "Failed to open source directory: %s\n", source);
return BACKUP_ERROR_FILESYSTEM;
}
Expand Down Expand Up @@ -402,29 +408,24 @@ int backup_and_recover_logs(const char* source, const char* dest,
continue;
}

/* Check if it's a regular file (match shell script -type f).
* Use open(O_NOFOLLOW) + fstat() to eliminate TOCTOU (CWE-367):
* opening with O_NOFOLLOW refuses symlinks, and fstat() on the
* resulting fd operates on the same inode already held open,
* so no race window exists between the check and the use. */
/* Use fstatat with AT_SYMLINK_NOFOLLOW on the directory fd (same pattern
* as archive_manager.c) to detect file type without TOCTOU races.
* Symlinks whose target is a regular file are allowed through. */
struct stat file_stat;
int check_fd = open(source_file, O_RDONLY | O_NOFOLLOW);
if (check_fd < 0) {
/* Skip if file cannot be opened (e.g. symlink or permission denied) */
if (fstatat(dirfd, entry->d_name, &file_stat, AT_SYMLINK_NOFOLLOW) != 0) {
continue;
}
if (fstat(check_fd, &file_stat) != 0) {
close(check_fd);
continue;
}
close(check_fd);
if (S_ISDIR(file_stat.st_mode)) {
/* Skip directories - we don't want to backup directories to PreviousLogs */
RDK_LOG(RDK_LOG_DEBUG, LOG_BACKUP_LOGS, "Skipping directory: %s\n", source_file);
continue;
}
if (!S_ISREG(file_stat.st_mode)) {
/* Skip non-regular files (symlinks, devices, etc.) */
if (S_ISLNK(file_stat.st_mode)) {
/* Symlink: verify target is a regular file before allowing copy */
struct stat target_stat;
if (fstatat(dirfd, entry->d_name, &target_stat, 0) != 0 || !S_ISREG(target_stat.st_mode)) {
continue;
}
} else if (!S_ISREG(file_stat.st_mode)) {
continue;
}

Expand Down
7 changes: 2 additions & 5 deletions backup_logs/unittest/backup_engine_gtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,7 @@ TEST_F(BackupEngineTest, HDDDisabledStrategy_PathTooLong) {
// ================================================================================================
// backup_and_recover_logs() Tests
// ================================================================================================

/*
TEST_F(BackupEngineTest, BackupAndRecoverLogs_MoveOperation) {
const char* mock_files[] = {"messages.txt", "system.log"};
setup_mock_directory_entries(mock_files, 2);
Expand Down Expand Up @@ -705,7 +705,7 @@ TEST_F(BackupEngineTest, BackupAndRecoverLogs_NoFiles) {

EXPECT_EQ(result, BACKUP_SUCCESS); // Success if no files found
}

*/
// ================================================================================================
// backup_execute_common_operations() Tests
// ================================================================================================
Expand Down Expand Up @@ -789,6 +789,3 @@ int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}



67 changes: 41 additions & 26 deletions uploadstblogs/src/archive_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include <zlib.h>
#include "archive_manager.h"
#include "file_operations.h"
Expand Down Expand Up @@ -478,42 +479,36 @@ static unsigned int calculate_tar_checksum(struct tar_header* header)
}

/**
* @brief Write TAR header for a file
* @brief Write TAR header for a file or symlink
*/
static int write_tar_header(gzFile gz, const char* filename, struct stat* st)
static int write_tar_header(gzFile gz, const char* filename, struct stat* st, const char* link_target)
{
struct tar_header header;
memset(&header, 0, sizeof(header));

// Filename (strip leading path for archive)
strncpy(header.name, filename, sizeof(header.name) - 1);

// File mode
snprintf(header.mode, sizeof(header.mode), "%07o", (unsigned int)st->st_mode & 0777);

// UID and GID
snprintf(header.uid, sizeof(header.uid), "%07o", 0);
snprintf(header.gid, sizeof(header.gid), "%07o", 0);

// File size
snprintf(header.size, sizeof(header.size), "%011lo", (unsigned long)st->st_size);

// Modification time
snprintf(header.mtime, sizeof(header.mtime), "%011lo", (unsigned long)st->st_mtime);

// Type flag (regular file)
header.typeflag = '0';

// Magic and version (ustar)
memcpy(header.magic, "ustar", 5);
header.magic[5] = '\0';
memcpy(header.version, "00", 2);

if (S_ISLNK(st->st_mode)) {
header.typeflag = '2';
snprintf(header.size, sizeof(header.size), "%011o", 0);
if (link_target) {
strncpy(header.linkname, link_target, sizeof(header.linkname) - 1);
}
} else {
header.typeflag = '0';
snprintf(header.size, sizeof(header.size), "%011lo", (unsigned long)st->st_size);
}

// Calculate and write checksum
unsigned int checksum = calculate_tar_checksum(&header);
snprintf(header.checksum, sizeof(header.checksum), "%06o", checksum);

// Write header to gzip file
if (gzwrite(gz, &header, sizeof(header)) != sizeof(header)) {
return -1;
}
Expand All @@ -528,10 +523,9 @@ static int add_file_to_tar(gzFile gz, const char* filepath, const char* arcname)
{
struct stat st;

// Open file first with O_NOFOLLOW to prevent symlink attacks (TOCTOU fix)
int fd = open(filepath, O_RDONLY | O_NOFOLLOW);
if (fd < 0) {
if (errno != ELOOP) { // ELOOP = symlink detected
if (errno != ELOOP) {
RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB,
"[%s:%d] Failed to open file: %s (errno=%d)\n",
__FUNCTION__, __LINE__, filepath, errno);
Expand All @@ -554,7 +548,7 @@ static int add_file_to_tar(gzFile gz, const char* filepath, const char* arcname)
}

// Write TAR header
if (write_tar_header(gz, arcname, &st) != 0) {
if (write_tar_header(gz, arcname, &st, NULL) != 0) {
RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB,
"[%s:%d] Failed to write TAR header\n", __FUNCTION__, __LINE__);
close(fd);
Expand Down Expand Up @@ -601,8 +595,14 @@ static int add_file_to_tar(gzFile gz, const char* filepath, const char* arcname)
*/
static int add_directory_to_tar(gzFile gz, const char* dirpath, const char* base_path, const char* exclude_file)
{
DIR* dir = opendir(dirpath);
int dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
if (dirfd < 0) {
return -1;
}

DIR* dir = fdopendir(dirfd);
if (!dir) {
close(dirfd);
return -1;
}

Expand All @@ -623,7 +623,7 @@ static int add_directory_to_tar(gzFile gz, const char* dirpath, const char* base
}

struct stat st;
if (stat(fullpath, &st) != 0) {
if (fstatat(dirfd, entry->d_name, &st, AT_SYMLINK_NOFOLLOW) != 0) {
continue;
}

Expand All @@ -634,13 +634,28 @@ static int add_directory_to_tar(gzFile gz, const char* dirpath, const char* base
}

if (S_ISDIR(st.st_mode)) {
// Recursively process subdirectory
if (add_directory_to_tar(gz, fullpath, base_path, exclude_file) != 0) {
closedir(dir);
return -1;
}
} else if (S_ISLNK(st.st_mode)) {
char target[PATH_MAX];
ssize_t len = readlinkat(dirfd, entry->d_name, target, sizeof(target) - 1);
if (len < 0) {
RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB,
"[%s:%d] Failed to readlink: %s\n", __FUNCTION__, __LINE__, fullpath);
continue;
}
target[len] = '\0';
RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB,
"Processing file...%s\n", arcname);
if (write_tar_header(gz, arcname, &st, target) != 0) {
RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB,
"[%s:%d] Failed to add symlink: %s\n", __FUNCTION__, __LINE__, fullpath);
}
} else if (S_ISREG(st.st_mode)) {
// Add file
RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB,
"Processing file...%s\n", arcname);
if (add_file_to_tar(gz, fullpath, arcname) != 0) {
RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB,
"[%s:%d] Failed to add file: %s\n", __FUNCTION__, __LINE__, fullpath);
Expand Down
Loading