fix(delete): share the per-frame manifest byte budget across delete-plan sections
This commit is contained in:
@@ -435,20 +435,22 @@ static bool valid_name(const char* value) {
|
|||||||
strchr(value, '/') == NULL;
|
strchr(value, '/') == NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool read_section(int fd, ArrayList* list, bool rel_path) {
|
/* Read one count-prefixed section. `bytes` is the running per-frame budget,
|
||||||
|
* shared across every section of the frame so a hostile peer cannot retain more
|
||||||
|
* than MAX_MANIFEST_BYTES from one STATUS_DELETE_PLAN frame. */
|
||||||
|
static bool read_section(int fd, ArrayList* list, bool rel_path, size_t* bytes) {
|
||||||
int count;
|
int count;
|
||||||
if (!receive_int(fd, &count) || count < 0 || count > MAX_MANIFEST_ENTRIES)
|
if (!receive_int(fd, &count) || count < 0 || count > MAX_MANIFEST_ENTRIES)
|
||||||
return false;
|
return false;
|
||||||
size_t bytes = 0;
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
char* value = receive_wire_str(fd);
|
char* value = receive_wire_str(fd);
|
||||||
bool ok = value && (rel_path ? valid_rel_path(value) : valid_name(value));
|
bool ok = value && (rel_path ? valid_rel_path(value) : valid_name(value));
|
||||||
if (ok) {
|
if (ok) {
|
||||||
size_t entry_size = strlen(value) + sizeof(char*) + 16;
|
size_t entry_size = strlen(value) + sizeof(char*) + 16;
|
||||||
if (entry_size > MAX_MANIFEST_BYTES - bytes) {
|
if (entry_size > MAX_MANIFEST_BYTES - *bytes) {
|
||||||
ok = false;
|
ok = false;
|
||||||
} else {
|
} else {
|
||||||
bytes += entry_size;
|
*bytes += entry_size;
|
||||||
ok = array_list_add(list, value);
|
ok = array_list_add(list, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -747,10 +749,11 @@ int delete_plan_session_receive(DeletePlanSession* session, const Config* config
|
|||||||
send_status(fd, STATUS_ERROR);
|
send_status(fd, STATUS_ERROR);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
size_t bytes = 0;
|
||||||
if (has_config) {
|
if (has_config) {
|
||||||
if (session->config_seen || !read_section(fd, session->protected_prefixes, true) ||
|
if (session->config_seen || !read_section(fd, session->protected_prefixes, true, &bytes) ||
|
||||||
!read_section(fd, session->size_skipped, true) ||
|
!read_section(fd, session->size_skipped, true, &bytes) ||
|
||||||
!read_section(fd, session->missing, true)) {
|
!read_section(fd, session->missing, true, &bytes)) {
|
||||||
send_status(fd, STATUS_ERROR);
|
send_status(fd, STATUS_ERROR);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -760,7 +763,7 @@ int delete_plan_session_receive(DeletePlanSession* session, const Config* config
|
|||||||
ArrayList* dirs = array_list_create(free);
|
ArrayList* dirs = array_list_create(free);
|
||||||
ArrayList* files = array_list_create(free);
|
ArrayList* files = array_list_create(free);
|
||||||
bool parsed = dir && (strcmp(dir, ".") == 0 || valid_rel_path(dir)) && dirs && files &&
|
bool parsed = dir && (strcmp(dir, ".") == 0 || valid_rel_path(dir)) && dirs && files &&
|
||||||
read_section(fd, dirs, false) && read_section(fd, files, false);
|
read_section(fd, dirs, false, &bytes) && read_section(fd, files, false, &bytes);
|
||||||
if (!parsed) {
|
if (!parsed) {
|
||||||
free(dir);
|
free(dir);
|
||||||
array_list_delete(dirs);
|
array_list_delete(dirs);
|
||||||
|
|||||||
Reference in New Issue
Block a user