fix: address review findings — sendfile EINTR, path traversal check
CI / lint (pull_request) Successful in 9s
CI / sanitizers (address) (pull_request) Successful in 16s
CI / sanitizers (undefined) (pull_request) Successful in 16s
CI / coverage (pull_request) Successful in 11s
CI / fuzz-build (pull_request) Successful in 13s
CI / valgrind (pull_request) Successful in 12s
CI / build-and-test (pull_request) Successful in 55s

This commit is contained in:
2026-07-21 14:17:51 +02:00
parent b20e39012e
commit bd2af8071a
+21 -3
View File
@@ -1,4 +1,5 @@
#include <dirent.h> #include <dirent.h>
#include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <libgen.h> #include <libgen.h>
#include <stddef.h> #include <stddef.h>
@@ -199,10 +200,25 @@ bool file_send_single_calls(File* file, int file_descriptor, bool use_metadata,
return true; return true;
} }
static bool has_path_traversal(const char* path) {
// Check if ".." appears as a path component — at start, end, or between '/'
const char* p = path;
while ((p = strstr(p, "..")) != NULL) {
bool at_start = (p == path);
bool after_slash = (p > path && p[-1] == '/');
bool at_end = (p[2] == '\0');
bool before_slash = (p[2] == '/');
if ((at_start || after_slash) && (at_end || before_slash))
return true;
p += 2;
}
return false;
}
bool file_save_to_disk(const char* root_directory, File* file) { bool file_save_to_disk(const char* root_directory, File* file) {
if (file->type == FILE_TYPE_SYMLINK && file->link_target) { if (file->type == FILE_TYPE_SYMLINK && file->link_target) {
// Validate link_target — reject absolute paths or traversal // Validate link_target — reject absolute paths or traversal
if (file->link_target[0] == '/' || strstr(file->link_target, "..") != NULL) { if (file->link_target[0] == '/' || has_path_traversal(file->link_target)) {
log_message(LOG_LEVEL_ERROR, "Path traversal blocked in symlink target: %s", log_message(LOG_LEVEL_ERROR, "Path traversal blocked in symlink target: %s",
file->link_target); file->link_target);
return false; return false;
@@ -210,7 +226,7 @@ bool file_save_to_disk(const char* root_directory, File* file) {
char* disk_path = path_cat((char*)root_directory, file->path); char* disk_path = path_cat((char*)root_directory, file->path);
if (disk_path == NULL) if (disk_path == NULL)
return false; return false;
if (strstr(disk_path, "..") != NULL) { if (has_path_traversal(disk_path)) {
log_message(LOG_LEVEL_ERROR, "Path traversal blocked: %s", disk_path); log_message(LOG_LEVEL_ERROR, "Path traversal blocked: %s", disk_path);
free(disk_path); free(disk_path);
return false; return false;
@@ -226,7 +242,7 @@ bool file_save_to_disk(const char* root_directory, File* file) {
char* disk_path = path_cat((char*)root_directory, file->path); char* disk_path = path_cat((char*)root_directory, file->path);
if (disk_path == NULL) if (disk_path == NULL)
return false; return false;
if (strstr(disk_path, "..") != NULL) { if (has_path_traversal(disk_path)) {
log_message(LOG_LEVEL_ERROR, "Path traversal blocked: %s", disk_path); log_message(LOG_LEVEL_ERROR, "Path traversal blocked: %s", disk_path);
free(disk_path); free(disk_path);
return false; return false;
@@ -625,6 +641,8 @@ bool file_send_sendfile(File* file, int file_descriptor, bool use_metadata, int
while ((unsigned long long)offset < file_size) { while ((unsigned long long)offset < file_size) {
ssize_t sent = sendfile(file_descriptor, fd, &offset, file_size - offset); ssize_t sent = sendfile(file_descriptor, fd, &offset, file_size - offset);
if (sent == -1) { if (sent == -1) {
if (errno == EINTR)
continue;
perror("sendfile failed"); perror("sendfile failed");
close(fd); close(fd);
return false; return false;