Permalink
Show file tree
Hide file tree
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Prevent cross-mountpoint attacks via .augsave during saving
Previously Augeas would open PATH.augsave for writing if a rename from PATH to
PATH.augsave failed, then write the file contents in. Now if the rename fails,
it tries to unlink PATH.augsave and open it with O_EXCL first.
Mountpoints remain permitted at either PATH or PATH.augnew provided
/augeas/save/copy_if_rename_fails exists.
* src/transform.c (clone_file):
add argument to perform unlink and O_EXCL on destination filename after a
rename failure to prevent PATH.augsave being a mountpoint
* src/transform.c (transform_save, remove_file):
always try to unlink PATH.augsave if rename fails, only allowing PATH to be
a mountpoint; allow PATH or PATH.augnew to be mountpoints
* tests/
test-put-mount: check PATH being a mountpoint is supported
test-put-mount-augnew.sh: check PATH.augnew being a mountpoint is supported
test-put-mount-augsave.sh: check unlink error when PATH.augsave is a mount
Fixes BZ 772261- Loading branch information
Dominic Cleal
authored and
David Lutterkort
committed
Jul 19, 2012
1 parent
1638774
commit b8de6a8
Showing
5 changed files
with
223 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| #! /bin/bash | ||
|
|
||
| # Test that we can write into a bind mount placed at PATH.augnew with the | ||
| # copy_if_rename_fails flag. | ||
| # This requires that EXDEV or EBUSY is returned from rename(2) to activate the | ||
| # code path, so set up a bind mount on Linux. | ||
|
|
||
| if [ $UID -ne 0 -o "$(uname -s)" != "Linux" ]; then | ||
| echo "Test can only be run as root on Linux to create bind mounts" | ||
| exit 77 | ||
| fi | ||
|
|
||
| ROOT=$abs_top_builddir/build/test-put-mount-augnew | ||
| LENSES=$abs_top_srcdir/lenses | ||
|
|
||
| HOSTS=$ROOT/etc/hosts | ||
| HOSTS_AUGNEW=${HOSTS}.augnew | ||
| TARGET=$ROOT/other/real_hosts | ||
|
|
||
| rm -rf $ROOT | ||
| mkdir -p $(dirname $HOSTS) | ||
| mkdir -p $(dirname $TARGET) | ||
|
|
||
| echo 127.0.0.1 localhost > $HOSTS | ||
| touch $TARGET $HOSTS_AUGNEW | ||
|
|
||
| mount --bind $TARGET $HOSTS_AUGNEW | ||
| Exit() { | ||
| umount $HOSTS_AUGNEW | ||
| exit $1 | ||
| } | ||
|
|
||
| HOSTS_SUM=$(sum $HOSTS) | ||
|
|
||
| augtool --nostdinc -I $LENSES -r $ROOT --new <<EOF | ||
| set /augeas/save/copy_if_rename_fails 1 | ||
| set /files/etc/hosts/1/alias myhost | ||
| save | ||
| print /augeas//error | ||
| EOF | ||
|
|
||
| if [ ! -f $HOSTS ] ; then | ||
| echo "/etc/hosts is no longer a regular file" | ||
| Exit 1 | ||
| fi | ||
| if [ ! "x${HOSTS_SUM}" = "x$(sum $HOSTS)" ]; then | ||
| echo "/etc/hosts has changed" | ||
| Exit 1 | ||
| fi | ||
| if [ ! "x${HOSTS_SUM}" = "x$(sum $HOSTS)" ]; then | ||
| echo "/etc/hosts has changed" | ||
| Exit 1 | ||
| fi | ||
|
|
||
| if [ ! -s $HOSTS_AUGNEW ]; then | ||
| echo "/etc/hosts.augnew is empty" | ||
| Exit 1 | ||
| fi | ||
| if [ ! -s $TARGET ]; then | ||
| echo "/other/real_hosts is empty" | ||
| Exit 1 | ||
| fi | ||
|
|
||
| if ! grep myhost $TARGET >/dev/null; then | ||
| echo "/other/real_hosts does not contain the modification" | ||
| Exit 1 | ||
| fi | ||
|
|
||
| Exit 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| #! /bin/bash | ||
|
|
||
| # Test that we don't follow bind mounts when writing to .augsave. | ||
| # This requires that EXDEV or EBUSY is returned from rename(2) to activate the | ||
| # code path, so set up a bind mount on Linux. | ||
|
|
||
| if [ $UID -ne 0 -o "$(uname -s)" != "Linux" ]; then | ||
| echo "Test can only be run as root on Linux to create bind mounts" | ||
| exit 77 | ||
| fi | ||
|
|
||
| actual() { | ||
| (augtool --nostdinc -I $LENSES -r $ROOT --backup | grep ^/augeas) <<EOF | ||
| set /augeas/save/copy_if_rename_fails 1 | ||
| set /files/etc/hosts/1/alias myhost | ||
| save | ||
| print /augeas//error | ||
| EOF | ||
| } | ||
|
|
||
| expected() { | ||
| cat <<EOF | ||
| /augeas/files/etc/hosts/error = "clone_unlink_dst_augsave" | ||
| /augeas/files/etc/hosts/error/message = "Device or resource busy" | ||
| EOF | ||
| } | ||
|
|
||
| ROOT=$abs_top_builddir/build/test-put-mount-augsave | ||
| LENSES=$abs_top_srcdir/lenses | ||
|
|
||
| HOSTS=$ROOT/etc/hosts | ||
| HOSTS_AUGSAVE=${HOSTS}.augsave | ||
|
|
||
| ATTACK_FILE=$ROOT/other/attack | ||
|
|
||
| rm -rf $ROOT | ||
| mkdir -p $(dirname $HOSTS) | ||
| mkdir -p $(dirname $ATTACK_FILE) | ||
|
|
||
| echo 127.0.0.1 localhost > $HOSTS | ||
| touch $ATTACK_FILE $HOSTS_AUGSAVE | ||
|
|
||
| mount --bind $ATTACK_FILE $HOSTS_AUGSAVE | ||
| Exit() { | ||
| umount $HOSTS_AUGSAVE | ||
| exit $1 | ||
| } | ||
|
|
||
| ACTUAL=$(actual) | ||
| EXPECTED=$(expected) | ||
| if [ "$ACTUAL" != "$EXPECTED" ]; then | ||
| echo "No error when trying to unlink augsave (a bind mount):" | ||
| echo "$ACTUAL" | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [ -s $ATTACK_FILE ]; then | ||
| echo "/other/attack now contains data, should be blank" | ||
| Exit 1 | ||
| fi | ||
|
|
||
| Exit 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| #! /bin/bash | ||
|
|
||
| # Test that we can write into a bind mount with the copy_if_rename_fails flag. | ||
| # This requires that EXDEV or EBUSY is returned from rename(2) to activate the | ||
| # code path, so set up a bind mount on Linux. | ||
|
|
||
| if [ $UID -ne 0 -o "$(uname -s)" != "Linux" ]; then | ||
| echo "Test can only be run as root on Linux to create bind mounts" | ||
| exit 77 | ||
| fi | ||
|
|
||
| ROOT=$abs_top_builddir/build/test-put-mount | ||
| LENSES=$abs_top_srcdir/lenses | ||
|
|
||
| HOSTS=$ROOT/etc/hosts | ||
| TARGET=$ROOT/other/real_hosts | ||
|
|
||
| rm -rf $ROOT | ||
| mkdir -p $(dirname $HOSTS) | ||
| mkdir -p $(dirname $TARGET) | ||
|
|
||
| echo 127.0.0.1 localhost > $TARGET | ||
| touch $HOSTS | ||
|
|
||
| mount --bind $TARGET $HOSTS | ||
| Exit() { | ||
| umount $HOSTS | ||
| exit $1 | ||
| } | ||
|
|
||
| HOSTS_SUM=$(sum $HOSTS) | ||
|
|
||
| augtool --nostdinc -I $LENSES -r $ROOT <<EOF | ||
| set /augeas/save/copy_if_rename_fails 1 | ||
| set /files/etc/hosts/1/alias myhost | ||
| save | ||
| print /augeas//error | ||
| EOF | ||
|
|
||
| if [ ! "x${HOSTS_SUM}" != "x$(sum $HOSTS)" ]; then | ||
| echo "/etc/hosts hasn't changed" | ||
| Exit 1 | ||
| fi | ||
|
|
||
| if [ ! "x${HOSTS_SUM}" != "x$(sum $TARGET)" ]; then | ||
| echo "/other/real_hosts hasn't changed" | ||
| Exit 1 | ||
| fi | ||
|
|
||
| if ! grep myhost $TARGET >/dev/null; then | ||
| echo "/other/real_hosts does not contain the modification" | ||
| Exit 1 | ||
| fi | ||
|
|
||
| Exit 0 |