Impl. "safe links" by default for v0

By default, links that point to outside of archive (or possibly doesn't
point to anything) will be ignored. Use "--no-safe-links" to preserve
such symlinks.

Note this has only been implemented for v0 of the file format in this
commit, and not yet v1.
This commit is contained in:
Stephen Seo 2024-10-21 16:55:39 +09:00
parent 7ee54bddf2
commit cef3e4184a
4 changed files with 78 additions and 9 deletions

View file

@ -57,6 +57,11 @@ Following the file-count bytes, the following bytes are added for each file:
2. The second bit is "other execute permission". 2. The second bit is "other execute permission".
3. The third bit is UNSET if relative links are preferred, and is SET 3. The third bit is UNSET if relative links are preferred, and is SET
if absolute links are preferred. if absolute links are preferred.
4. The fourth bit is set if this file/symlink-entry is invalid and must
be skipped. Ignore following bytes after these 4 bytes bit-flags in
this specification and skip to the next entry; if marked invalid,
the following specification bytes for this file/symlink entry must
not exist.
3. The third byte. 3. The third byte.
1. Currently unused. 1. Currently unused.
4. The fourth byte. 4. The fourth byte.

View file

@ -114,6 +114,20 @@ void cleanup_temp_filename_delete(void ***ptrs_array) {
#endif #endif
} }
void cleanup_overwrite_filename_delete_simple(char **filename) {
if (filename && *filename) {
if ((*filename)[0] != 0) {
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
unlink(*filename);
#endif
}
free(*filename);
*filename = NULL;
}
}
int write_files_fn(void *data, void *ud) { int write_files_fn(void *data, void *ud) {
if (is_sig_int_occurred) { if (is_sig_int_occurred) {
return 1; return 1;
@ -773,16 +787,39 @@ int write_files_fn(void *data, void *ud) {
if (abs_path && (state->parsed->flags & 0x20) == 0 && if (abs_path && (state->parsed->flags & 0x20) == 0 &&
!simple_archiver_hash_map_get(state->map, abs_path, !simple_archiver_hash_map_get(state->map, abs_path,
strlen(abs_path) + 1)) { strlen(abs_path) + 1)) {
// Is not a filename being archived, set preference to absolute path. // Is not a filename being archived.
fprintf(stderr, if ((state->parsed->flags & 0x80) != 0) {
"NOTICE: abs_path exists, \"--no-abs-symlink\" not specified, " // No safe links, set preference to absolute path.
"and link refers to file NOT in archive; preferring abs_path.\n"); fprintf(
((uint8_t *)temp_to_write->buf)[1] |= 0x4; stderr,
"NOTICE: abs_path exists, \"--no-abs-symlink\" not specified, "
"and link refers to file NOT in archive; preferring abs_path.\n");
((uint8_t *)temp_to_write->buf)[1] |= 0x4;
} else {
// Safe links, do not store symlink!
fprintf(stderr,
"WARNING: Symlink \"%s\" points to outside archive contents, "
"will not be stored! (Use \"--no-safe-links\" to disable this "
"behavior)\n",
file_info->filename);
((uint8_t *)temp_to_write->buf)[1] |= 0x8;
}
} }
// Store the 4 byte bit-flags for file. // Store the 4 byte bit-flags for file.
simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write); simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
if ((((uint8_t *)temp_to_write->buf)[1] & 0x8) != 0) {
// Skipped symlink.
simple_archiver_list_get(to_write, write_list_datas_fn, state->out_f);
simple_archiver_list_free(&to_write);
char format_str[64];
snprintf(format_str, 64, FILE_COUNTS_OUTPUT_FORMAT_STR_1, state->digits,
state->digits);
fprintf(stderr, format_str, ++(state->count), state->max);
return 0;
}
// Store the absolute and relative paths. // Store the absolute and relative paths.
if (!abs_path) { if (!abs_path) {
fprintf(stderr, fprintf(stderr,
@ -2802,6 +2839,9 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
simple_archiver_helper_cleanup_malloced))) void *out_f_name = NULL; simple_archiver_helper_cleanup_malloced))) void *out_f_name = NULL;
__attribute__((cleanup(simple_archiver_helper_cleanup_FILE))) FILE *out_f = __attribute__((cleanup(simple_archiver_helper_cleanup_FILE))) FILE *out_f =
NULL; NULL;
__attribute__((cleanup(
cleanup_overwrite_filename_delete_simple))) char *to_overwrite_dest =
NULL;
if (u16 < SIMPLE_ARCHIVER_BUFFER_SIZE) { if (u16 < SIMPLE_ARCHIVER_BUFFER_SIZE) {
if (fread(buf, 1, u16 + 1, in_f) != (size_t)u16 + 1) { if (fread(buf, 1, u16 + 1, in_f) != (size_t)u16 + 1) {
return SDAS_INVALID_FILE; return SDAS_INVALID_FILE;
@ -2831,12 +2871,14 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
if (fd == -1) { if (fd == -1) {
if (errno == ELOOP) { if (errno == ELOOP) {
// Is an existing symbolic file. // Is an existing symbolic file.
unlink((const char *)buf); // Defer deletion to after "is invalid" check.
to_overwrite_dest = strdup((const char *)buf);
} }
} else { } else {
close(fd); close(fd);
// Is an existing file. // Is an existing file.
unlink((const char *)buf); // Defer deletion to after "is invalid" check.
to_overwrite_dest = strdup((const char *)buf);
} }
} }
if (!skip) { if (!skip) {
@ -2878,12 +2920,14 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
if (fd == -1) { if (fd == -1) {
if (errno == ELOOP) { if (errno == ELOOP) {
// Is an existing symbolic file. // Is an existing symbolic file.
unlink((const char *)uc_heap_buf); // Defer deletion to after "is invalid" check.
to_overwrite_dest = strdup((const char *)uc_heap_buf);
} }
} else { } else {
close(fd); close(fd);
// Is an existing file. // Is an existing file.
unlink((const char *)uc_heap_buf); // Defer deletion to after "is invalid" check.
to_overwrite_dest = strdup((const char *)uc_heap_buf);
} }
} }
if (!skip) { if (!skip) {
@ -2898,6 +2942,17 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
return SDAS_INVALID_FILE; return SDAS_INVALID_FILE;
} }
// Check for "invalid entry" flag.
if ((buf[1] & 0x8) != 0) {
free(to_overwrite_dest);
to_overwrite_dest = NULL;
fprintf(stderr, " This file entry was marked invalid, skipping...\n");
continue;
} else {
// Do deferred overwrite action: remove existing file/symlink.
cleanup_overwrite_filename_delete_simple(&to_overwrite_dest);
}
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \ #if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \ SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX

View file

@ -168,6 +168,9 @@ void simple_archiver_print_usage(void) {
fprintf(stderr, "--overwrite-extract : allows overwriting when extracting\n"); fprintf(stderr, "--overwrite-extract : allows overwriting when extracting\n");
fprintf(stderr, fprintf(stderr,
"--no-abs-symlink : do not store absolute paths for symlinks\n"); "--no-abs-symlink : do not store absolute paths for symlinks\n");
fprintf(stderr,
"--no-safe-links : keep symlinks that link to outside archive "
"contents\n");
fprintf(stderr, fprintf(stderr,
"--temp-files-dir <dir> : where to store temporary files created " "--temp-files-dir <dir> : where to store temporary files created "
"when compressing (defaults to current working directory)\n"); "when compressing (defaults to current working directory)\n");
@ -303,6 +306,11 @@ int simple_archiver_parse_args(int argc, const char **argv,
out->flags |= 0x8; out->flags |= 0x8;
} else if (strcmp(argv[0], "--no-abs-symlink") == 0) { } else if (strcmp(argv[0], "--no-abs-symlink") == 0) {
out->flags |= 0x20; out->flags |= 0x20;
} else if (strcmp(argv[0], "--no-safe-links") == 0) {
out->flags |= 0x80;
fprintf(stderr,
"NOTICE: Disabling safe-links, symlinks that point to outside "
"archived files will be preserved!\n");
} else if (strcmp(argv[0], "--temp-files-dir") == 0) { } else if (strcmp(argv[0], "--temp-files-dir") == 0) {
if (argc < 2) { if (argc < 2) {
fprintf(stderr, "ERROR: --temp-files-dir is missing an argument!\n"); fprintf(stderr, "ERROR: --temp-files-dir is missing an argument!\n");

View file

@ -36,6 +36,7 @@ typedef struct SDArchiverParsed {
/// 0b xxx1 xxxx - Create archive to stdout or read archive from stdin. /// 0b xxx1 xxxx - Create archive to stdout or read archive from stdin.
/// 0b xx1x xxxx - Do not save absolute paths for symlinks. /// 0b xx1x xxxx - Do not save absolute paths for symlinks.
/// 0b x1xx xxxx - Sort files by size before archiving. /// 0b x1xx xxxx - Sort files by size before archiving.
/// 0b 1xxx xxxx - No safe links.
uint32_t flags; uint32_t flags;
/// Null-terminated string. /// Null-terminated string.
char *filename; char *filename;