Skip to content

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

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions