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
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:
+21
-3
@@ -1,4 +1,5 @@
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <stddef.h>
|
||||
@@ -199,10 +200,25 @@ bool file_send_single_calls(File* file, int file_descriptor, bool use_metadata,
|
||||
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) {
|
||||
if (file->type == FILE_TYPE_SYMLINK && file->link_target) {
|
||||
// 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",
|
||||
file->link_target);
|
||||
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);
|
||||
if (disk_path == NULL)
|
||||
return false;
|
||||
if (strstr(disk_path, "..") != NULL) {
|
||||
if (has_path_traversal(disk_path)) {
|
||||
log_message(LOG_LEVEL_ERROR, "Path traversal blocked: %s", disk_path);
|
||||
free(disk_path);
|
||||
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);
|
||||
if (disk_path == NULL)
|
||||
return false;
|
||||
if (strstr(disk_path, "..") != NULL) {
|
||||
if (has_path_traversal(disk_path)) {
|
||||
log_message(LOG_LEVEL_ERROR, "Path traversal blocked: %s", disk_path);
|
||||
free(disk_path);
|
||||
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) {
|
||||
ssize_t sent = sendfile(file_descriptor, fd, &offset, file_size - offset);
|
||||
if (sent == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
perror("sendfile failed");
|
||||
close(fd);
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user