Address confirmed receiver security findings B1-B6: B1 (HIGH): add O_NONBLOCK to the three receiver read-opens that opened an existing destination/basis entry before the S_ISREG gate (incremental_check_open_destination, basis_open_regular, hardlink_read_source) so a client-planted FIFO can no longer block the receive thread forever while the post-open type gate still rejects it. B2 (HIGH/MED): --inplace now fstatat(AT_SYMLINK_NOFOLLOW)-probes the target and refuses any existing non-regular entry, opens with O_NONBLOCK, and re-checks S_ISREG on the opened fd. This stops a FIFO from hanging the open and stops a char/block device from being written directly (bypassing --write-devices). B3 (MED): under --dry-run the incremental quick-skip no longer reads/hashes the destination file for --checksum/--delta; it decides from metadata only and reports would-transfer when the comparison is inconclusive, closing the read-only-module content-hash oracle. B4 (LOW): xattr_name_appliable() now gates the two system.posix_acl_* names on preserve_acls (--acls), not the derived use_xattrs (--xattrs OR --acls). The receiver drops (never applies) ACL entries when -A was not negotiated while keeping user.* working for -X. B5 (INFO): receive_manifest_section() charges a per-entry overhead against MAX_MANIFEST_BYTES and the aggregate entry count across all three sections is capped at MAX_MANIFEST_ENTRIES. B6 (MED): data_charge_session() reserves decompressed/chunk-copy bytes against the owning ProtocolSession (MAX_CONNECTION_MEMORY) and records them on the Data so data_destroy() releases them via the Data.owner path. Applied to the whole-file/append/delta decompression sites and chunk_deserialize() per-file copies; a missing session owner degrades to the previous uncharged behavior. Tests: FIFO destination/basis non-hang (with alarm), --inplace FIFO/device refusal, dry-run no-read oracle test plus updated metadata-only dry-run tests, ACL-without--acls drop, manifest total-entry cap, and chunk session charging.
38 lines
1.4 KiB
C
38 lines
1.4 KiB
C
#ifndef CHUNK_H
|
|
#define CHUNK_H
|
|
|
|
#include "config.h"
|
|
#include "data.h"
|
|
#include "file.h"
|
|
#include <stdbool.h>
|
|
#include <sys/stat.h>
|
|
|
|
#define DESIRED_CHUNK_SIZE (10 * 1024 * 1024)
|
|
|
|
typedef struct {
|
|
File** items;
|
|
int element_count;
|
|
} Chunk;
|
|
|
|
Chunk* chunk_create(File** items, int element_count);
|
|
void chunk_destroy(void* chunk);
|
|
Data* chunk_serialize(Chunk* chunk, bool use_metadata);
|
|
Chunk* chunk_deserialize(Data* data, bool use_metadata);
|
|
Data* chunk_compress(Chunk* chunk, int compression_level, bool use_metadata);
|
|
Data* chunk_compress_with_threads(Chunk* chunk, int compression_level, bool use_metadata,
|
|
int compression_threads);
|
|
Chunk* receive_chunk_data(int fd, const Config* config);
|
|
|
|
/* Charge `charge` retained bytes of `data` against `session`'s per-connection
|
|
* budget (MAX_CONNECTION_MEMORY), mirroring the protocol layer's accounting, and
|
|
* record them on `data` so data_destroy() returns the charge through the
|
|
* Data.owner path. Returns false (leaving `data` uncharged) when the ceiling
|
|
* would be exceeded. A NULL/zero-size charge or a NULL session is a no-op
|
|
* success. The receive-side decompression and chunk-copy paths know the owning
|
|
* session only through the Data.owner of the buffer they are processing, so
|
|
* this is the entry point that lets them participate in the connection budget
|
|
* without a session handle (B6). */
|
|
bool data_charge_session(Data* data, ProtocolSession* session, size_t charge);
|
|
|
|
#endif
|