Impl. safe-link checking for v1 file format

As mentioned in the previous commit, "safe links" is on by default,
meaning that any symlinks pointing to outside of archived files (or
invalid) will not be stored. To store such symlinks, "--no-safe-links"
must be specified.

This commit implements "safe links" for v1 of the file format.
This commit is contained in:
Stephen Seo 2024-10-21 17:10:34 +09:00
parent cef3e4184a
commit 50b1f4b274
2 changed files with 33 additions and 4 deletions

View file

@ -133,6 +133,9 @@ Following the link-count bytes, the following bytes are added for each symlink:
2. The second byte.
1. The first bit is "other write permission".
2. The second bit is "other execute permission".
3. If this bit is set, then this entry is marked invalid. The link name
will be preserved in this entry, but the following link target paths
will be set to zero-length and will not be stored.
2. 2 bytes 16-bit unsigned integer "link name" in big-endian. This does not
include the NULL at the end of the string. Must not be zero.
3. X bytes of link-name (length defined by previous value). Is a NULL-terminated

View file

@ -2079,12 +2079,26 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
abs_path);
}
}
uint_fast8_t is_invalid = 0;
if (abs_path && (state->parsed->flags & 0x20) == 0 &&
!simple_archiver_hash_map_get(abs_filenames, abs_path,
strlen(abs_path) + 1)) {
// Is not a filename being archived, set preference to absolute path.
// Is not a filename being archived.
if ((state->parsed->flags & 0x80) == 0) {
// Not a "safe link", mark invalid and continue.
is_invalid = 1;
fprintf(stderr,
"WARNING: \"%s\" points to outside of archived files (or is "
"invalid) and \"--no-safe-links\" not specified, will not "
"store abs/rel-links to this entry!\n",
(const char *)node->data);
} else {
// Safe links disabled, set preference to absolute path.
buf[0] |= 1;
}
}
// Get symlink stats for permissions.
struct stat stat_buf;
@ -2126,6 +2140,11 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
buf[0] = 0xFE;
buf[1] = 3;
#endif
if (is_invalid) {
buf[1] |= 4;
}
if (fwrite(buf, 1, 2, out_f) != 2) {
return SDAS_FAILED_TO_WRITE;
}
@ -2146,7 +2165,7 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
return SDAS_FAILED_TO_WRITE;
}
if (abs_path && (state->parsed->flags & 0x20) == 0) {
if (abs_path && (state->parsed->flags & 0x20) == 0 && !is_invalid) {
len = strlen(abs_path);
if (len >= 0xFFFF) {
fprintf(stderr,
@ -2170,7 +2189,7 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
}
}
if (rel_path) {
if (rel_path && !is_invalid) {
len = strlen(rel_path);
if (len >= 0xFFFF) {
fprintf(stderr,
@ -3682,6 +3701,13 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
return SDAS_INVALID_FILE;
}
const uint_fast8_t absolute_preferred = (buf[0] & 1) ? 1 : 0;
const uint_fast8_t is_invalid = (buf[1] & 4) ? 1 : 0;
if (is_invalid) {
fprintf(stderr,
" WARNING: This symlink entry was marked invalid (not a safe "
"link)!\n");
}
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \