Skip to content

Security fix in flist.c breaks --delete-missing-args with --files-from #910

@mgkeeley

Description

@mgkeeley

The mode validation added as part of recent security hardening in recv_file_entry() (flist.c lines 864–876) breaks the --delete-missing-args feature when used with --files-from.

Steps to reproduce

echo "path/to/deleted/file.txt" | rsync --delete --delete-missing-args \
  --files-from=- ./ user@remote:dest/

Where path/to/deleted/file.txt does not exist locally but exists on the remote.

Expected behaviour

The file is deleted on the remote, as documented for --delete-missing-args.

Actual behaviour

invalid file mode 00 for path/to/deleted/file.php [receiver]
rsync error: protocol incompatibility (code 2) at flist.c(874) [receiver=3.4.3]

Root cause

The sender deliberately sends mode=0 for missing-args entries — this is intentional by design, as documented in the sender code in flist.c:

} else /* (missing_args == 2) */ {
    /* Send the arg as a "missing" entry with
     * mode 0, which tells the generator to delete it. */
    memset(&st, 0, sizeof st);
}

The generator in generator.c correctly handles this case:

if (missing_args == 2 && file->mode == 0) {
    if (filter_list.head && check_filter(&filter_list, FINFO, fname, is_dir) < 0)
        return;
    if (statret == 0)
        delete_item(fname, sx.st.st_mode, del_opts);
    return;
}

However, the security validation added to recv_file_entry() rejects mode=0 before the entry ever reaches the generator:

if (!S_ISREG(mode) && !S_ISDIR(mode) && !S_ISLNK(mode)
 && !S_ISCHR(mode) && !S_ISBLK(mode)
 && !S_ISFIFO(mode) && !S_ISSOCK(mode)) {
    rprintf(FERROR, "invalid file mode 0%o for %s [%s]\n",
        (unsigned)mode, lastname, who_am_i());
    exit_cleanup(RERR_PROTOCOL);
}

Proposed fix

Add a missing_args == 2 exception to the mode validation:

if (!S_ISREG(mode) && !S_ISDIR(mode) && !S_ISLNK(mode)
 && !S_ISCHR(mode) && !S_ISBLK(mode)
 && !S_ISFIFO(mode) && !S_ISSOCK(mode)
 && !(missing_args == 2 && mode == 0)) {
    rprintf(FERROR, "invalid file mode 0%o for %s [%s]\n",
        (unsigned)mode, lastname, who_am_i());
    exit_cleanup(RERR_PROTOCOL);
}

Versions affected

3.4.3, plus security backports in 3.2.7. I haven't checked other versions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions