fix(filter): bound .rsync-filter lines and guard capacity growth
Read per-directory filter files through the bounded reader, guard the rule list's capacity doubling against INT_MAX/2 overflow, and escape the local directory path before logging a read failure.
This commit is contained in:
+20
-4
@@ -2,6 +2,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -176,6 +177,8 @@ bool filter_rule_list_add(FilterRuleList* list, FilterRule* rule) {
|
|||||||
if (!list || !rule)
|
if (!list || !rule)
|
||||||
return false;
|
return false;
|
||||||
if (list->count == list->capacity) {
|
if (list->count == list->capacity) {
|
||||||
|
if (list->capacity > INT_MAX / 2)
|
||||||
|
return false;
|
||||||
int new_cap = list->capacity > 0 ? list->capacity * 2 : 8;
|
int new_cap = list->capacity > 0 ? list->capacity * 2 : 8;
|
||||||
FilterRule** grown = realloc(list->items, (size_t)new_cap * sizeof(FilterRule*));
|
FilterRule** grown = realloc(list->items, (size_t)new_cap * sizeof(FilterRule*));
|
||||||
if (!grown)
|
if (!grown)
|
||||||
@@ -322,8 +325,10 @@ FilterRuleList* filter_file_read(const char* dir_path, const char* owner_rel, bo
|
|||||||
if (!fp) {
|
if (!fp) {
|
||||||
if (errno == ENOENT || errno == ENOTDIR)
|
if (errno == ENOENT || errno == ENOTDIR)
|
||||||
return filter_rule_list_create();
|
return filter_rule_list_create();
|
||||||
log_message(LOG_LEVEL_WARNING, "Could not read .rsync-filter in %s: %s", dir_path,
|
char* escaped_dir = output_escape(dir_path, log_get_8_bit_output());
|
||||||
strerror(errno));
|
log_message(LOG_LEVEL_WARNING, "Could not read .rsync-filter in %s: %s",
|
||||||
|
escaped_dir ? escaped_dir : "<allocation failed>", strerror(errno));
|
||||||
|
free(escaped_dir);
|
||||||
return filter_rule_list_create();
|
return filter_rule_list_create();
|
||||||
}
|
}
|
||||||
if (exists)
|
if (exists)
|
||||||
@@ -336,9 +341,20 @@ FilterRuleList* filter_file_read(const char* dir_path, const char* owner_rel, bo
|
|||||||
}
|
}
|
||||||
char* line = NULL;
|
char* line = NULL;
|
||||||
size_t line_cap = 0;
|
size_t line_cap = 0;
|
||||||
ssize_t n;
|
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
while ((n = getline(&line, &line_cap, fp)) != -1) {
|
while (true) {
|
||||||
|
ssize_t n = utils_getdelim_bounded(fp, &line, &line_cap, '\n', UTILS_MAX_LINE_LEN);
|
||||||
|
if (n < 0) {
|
||||||
|
if (errno == EFBIG) {
|
||||||
|
snprintf(err, err_size, "line in .rsync-filter exceeds %d bytes", (int)UTILS_MAX_LINE_LEN);
|
||||||
|
} else {
|
||||||
|
snprintf(err, err_size, "error reading .rsync-filter: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (n == 0)
|
||||||
|
break;
|
||||||
const char* p = line;
|
const char* p = line;
|
||||||
while (*p == ' ' || *p == '\t')
|
while (*p == ' ' || *p == '\t')
|
||||||
p++;
|
p++;
|
||||||
|
|||||||
Reference in New Issue
Block a user