rsync: enforce a supported format and limit the allowed options

Many rsync options are unsafe to use in restricted environments
and may pose security risks.

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
Nicola Murino
2025-01-13 19:41:58 +01:00
parent f2123b4fb0
commit de3c987802
2 changed files with 134 additions and 5 deletions

View File

@@ -844,7 +844,7 @@ func TestRsyncOptions(t *testing.T) {
}
cmd, err := sshCmd.getSystemCommand()
assert.NoError(t, err)
assert.True(t, slices.Contains(cmd.cmd.Args, "--safe-links"),
assert.Equal(t, []string{"rsync", "--server", "-vlogDtprze.iLsfxC", "--safe-links", ".", user.HomeDir + "/"}, cmd.cmd.Args,
"--safe-links must be added if the user has the create symlinks permission")
permissions["/"] = []string{dataprovider.PermDownload, dataprovider.PermUpload, dataprovider.PermCreateDirs,
@@ -854,6 +854,12 @@ func TestRsyncOptions(t *testing.T) {
conn = &Connection{
BaseConnection: common.NewBaseConnection("", common.ProtocolSFTP, "", "", user),
}
sshCmd = sshCommand{
command: "rsync",
connection: conn,
}
_, err = sshCmd.getSystemCommand()
assert.Error(t, err)
sshCmd = sshCommand{
command: "rsync",
connection: conn,
@@ -861,8 +867,8 @@ func TestRsyncOptions(t *testing.T) {
}
cmd, err = sshCmd.getSystemCommand()
assert.NoError(t, err)
assert.True(t, slices.Contains(cmd.cmd.Args, "--munge-links"),
"--munge-links must be added if the user has the create symlinks permission")
assert.Equal(t, []string{"rsync", "--server", "-vlogDtprze.iLsfxC", "--munge-links", ".", user.HomeDir + "/"}, cmd.cmd.Args,
"--munge-links must be added if the user hasn't the create symlinks permission")
sshCmd.connection.User.VirtualFolders = append(sshCmd.connection.User.VirtualFolders, vfs.VirtualFolder{
BaseVirtualFolder: vfs.BaseVirtualFolder{
@@ -2241,3 +2247,43 @@ func TestAuthenticationErrors(t *testing.T) {
assert.ErrorIs(t, err, sftpAuthError)
assert.NotErrorIs(t, err, util.ErrNotFound)
}
func TestRsyncArguments(t *testing.T) {
assert.False(t, canAcceptRsyncArgs(nil))
args := []string{"-e", "--server"}
assert.False(t, canAcceptRsyncArgs(args))
args = []string{"--server", "--sender", "-vlogDtpre.iLsfxCIvu", ".", "."}
assert.True(t, canAcceptRsyncArgs(args))
args = []string{"--server", "--sender", "--server", "-vlogDtpre.iLsfxCIvu", ".", "."}
assert.False(t, canAcceptRsyncArgs(args))
args = []string{"--server", "..", "/"}
assert.False(t, canAcceptRsyncArgs(args))
args = []string{"--server", ".", "/"}
assert.False(t, canAcceptRsyncArgs(args))
args = []string{"--server", "--sender", "-vlogDtpre.iLsfxCIvu", ".", "."}
assert.True(t, canAcceptRsyncArgs(args))
args = []string{"--server", "--sender", "-vlogDtpre.iLsfxCIvu", "--delete", ".", "/"}
assert.True(t, canAcceptRsyncArgs(args))
args = []string{"--server", "-vlogDtpre.iLsfxCIvu", "--delete", ".", "/"}
assert.True(t, canAcceptRsyncArgs(args))
args = []string{"--server", "-vlogDtpre.iLsfxCIvu", "--delete", "/", ".", "/"}
assert.False(t, canAcceptRsyncArgs(args))
args = []string{"--server", "--sender", "-vlogDtpre.iLsfxCIvu", ".", "path1", "path2"}
assert.False(t, canAcceptRsyncArgs(args))
args = []string{"--server", "--sender", "-vlogDtpre.iLsfxCIvu", "."}
assert.False(t, canAcceptRsyncArgs(args))
args = []string{"--sender", "-vlogDtpre.iLsfxCIvu", "--delete", ".", "/"}
assert.False(t, canAcceptRsyncArgs(args))
args = []string{"--server", "-vlogDtpre.", "--delete", ".", "/"}
assert.False(t, canAcceptRsyncArgs(args))
args = []string{"--server", "--sender", "-vlogDtpre.", "--delete", ".", "/"}
assert.False(t, canAcceptRsyncArgs(args))
args = []string{"--server", "--sender", "-e.iLsfxCIvu", "--delete", ".", "/"}
assert.False(t, canAcceptRsyncArgs(args))
args = []string{"--server", "-vlogDtpre.iLsfxCIvu", "--delete", "/"}
assert.False(t, canAcceptRsyncArgs(args))
args = []string{"--server", "-vlogDtpre.iLsfxCIvu", "--delete", "--safe-links"}
assert.False(t, canAcceptRsyncArgs(args))
args = []string{"--server", "-vlogDtpre.iLsfxCIvu", "--unsupported-option", ".", "/"}
assert.False(t, canAcceptRsyncArgs(args))
}