generic: check that we can't write to swap files

While active, the media backing a swap file is leased to the kernel.
Userspace has no business writing to it.  Make sure we can't do this.

The two kernel patches titled as below should fix the bug:

mm: set S_SWAPFILE on blockdev swap devices
vfs: don't allow writes to swap files

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Eryu Guan <guaneryu@gmail.com>
Signed-off-by: Eryu Guan <guaneryu@gmail.com>
This commit is contained in:
Darrick J. Wong
2019-09-24 09:39:37 -07:00
committed by Eryu Guan
parent 74f448265a
commit db8feee949
6 changed files with 285 additions and 4 deletions
+131 -4
View File
@@ -3,22 +3,149 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/swap.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <signal.h>
static void usage(const char *prog)
{
fprintf(stderr, "usage: %s [-v verb] PATH\n", prog);
exit(EXIT_FAILURE);
}
enum verbs {
TEST_SWAPON = 0,
TEST_WRITE,
TEST_MWRITE_AFTER,
TEST_MWRITE_BEFORE_AND_MWRITE_AFTER,
TEST_MWRITE_BEFORE,
MAX_TEST_VERBS,
};
#define BUF_SIZE 262144
static char buf[BUF_SIZE];
static void handle_signal(int signal)
{
fprintf(stderr, "Caught signal %d, terminating...\n", signal);
exit(EXIT_FAILURE);
}
int main(int argc, char **argv)
{
int ret;
struct sigaction act = {
.sa_handler = handle_signal,
};
enum verbs verb = TEST_SWAPON;
void *p;
ssize_t sz;
int fd = -1;
int ret, c;
if (argc != 2) {
fprintf(stderr, "usage: %s PATH\n", argv[0]);
memset(buf, 0x58, BUF_SIZE);
while ((c = getopt(argc, argv, "v:")) != -1) {
switch (c) {
case 'v':
verb = atoi(optarg);
if (verb < TEST_SWAPON || verb >= MAX_TEST_VERBS) {
fprintf(stderr, "Verbs must be 0-%d.\n",
MAX_TEST_VERBS - 1);
usage(argv[0]);
}
break;
default:
usage(argv[0]);
break;
}
}
ret = sigaction(SIGSEGV, &act, NULL);
if (ret) {
perror("sigsegv action");
return EXIT_FAILURE;
}
ret = swapon(argv[1], 0);
ret = sigaction(SIGBUS, &act, NULL);
if (ret) {
perror("sigbus action");
return EXIT_FAILURE;
}
switch (verb) {
case TEST_WRITE:
case TEST_MWRITE_AFTER:
case TEST_MWRITE_BEFORE_AND_MWRITE_AFTER:
case TEST_MWRITE_BEFORE:
fd = open(argv[optind], O_RDWR);
if (fd < 0) {
perror(argv[optind]);
return EXIT_FAILURE;
}
break;
default:
break;
}
switch (verb) {
case TEST_MWRITE_BEFORE_AND_MWRITE_AFTER:
case TEST_MWRITE_BEFORE:
p = mmap(NULL, BUF_SIZE, PROT_WRITE | PROT_READ, MAP_SHARED,
fd, 65536);
if (p == MAP_FAILED) {
perror("mmap");
return EXIT_FAILURE;
}
memcpy(p, buf, BUF_SIZE);
break;
default:
break;
}
if (optind != argc - 1)
usage(argv[0]);
ret = swapon(argv[optind], 0);
if (ret) {
perror("swapon");
return EXIT_FAILURE;
}
switch (verb) {
case TEST_WRITE:
sz = pwrite(fd, buf, BUF_SIZE, 65536);
if (sz < 0) {
perror("pwrite");
return EXIT_FAILURE;
}
break;
case TEST_MWRITE_AFTER:
p = mmap(NULL, BUF_SIZE, PROT_WRITE | PROT_READ, MAP_SHARED,
fd, 65536);
if (p == MAP_FAILED) {
perror("mmap");
return EXIT_FAILURE;
}
/* fall through */
case TEST_MWRITE_BEFORE_AND_MWRITE_AFTER:
memcpy(p, buf, BUF_SIZE);
break;
default:
break;
}
if (fd >= 0) {
ret = fsync(fd);
if (ret)
perror("fsync");
ret = close(fd);
if (ret)
perror("close");
}
return EXIT_SUCCESS;
}
+70
View File
@@ -0,0 +1,70 @@
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0-or-newer
# Copyright (c) 2019, Oracle and/or its affiliates. All Rights Reserved.
#
# FS QA Test No. 569
#
# Check that we can't modify a file that's an active swap file.
seq=`basename $0`
seqres=$RESULT_DIR/$seq
echo "QA output created by $seq"
here=`pwd`
tmp=/tmp/$$
status=1 # failure is the default!
trap "_cleanup; exit \$status" 0 1 2 3 15
_cleanup()
{
cd /
swapoff $testfile
rm -rf $tmp.* $testfile
}
# get standard environment, filters and checks
. ./common/rc
. ./common/filter
# real QA test starts here
_supported_os Linux
_supported_fs generic
_require_test_program swapon
_require_scratch_swapfile
rm -f $seqres.full
_scratch_mkfs > $seqres.full 2>&1
_scratch_mount >> $seqres.full 2>&1
testfile=$SCRATCH_MNT/$seq.swap
_format_swapfile $testfile 20m
# Can you modify the swapfile via previously open file descriptors?
for verb in 1 2 3 4; do
echo "verb $verb"
"$here/src/swapon" -v $verb $testfile
swapoff $testfile
done
# Now try writing with a new file descriptor.
swapon $testfile 2>&1 | _filter_scratch
# Can we write to it?
$XFS_IO_PROG -c 'pwrite -S 0x59 64k 64k' $testfile
$XFS_IO_PROG -d -c 'pwrite -S 0x60 64k 64k' $testfile
$XFS_IO_PROG -c 'mmap -rw 64k 64k' -c 'mwrite -S 0x61 64k 64k' $testfile
# Can we change the file size?
$XFS_IO_PROG -c 'truncate 18m' $testfile
# Can you fallocate the file?
$XFS_IO_PROG -c 'falloc 0 32m' $testfile
# We test that you can't reflink, dedupe, or copy_file_range into a swapfile
# in other tests.
# success, all done
status=0
exit
+14
View File
@@ -0,0 +1,14 @@
QA output created by 569
verb 1
pwrite: Text file busy
verb 2
mmap: Text file busy
verb 3
Caught signal 7, terminating...
verb 4
pwrite: Text file busy
pwrite: Text file busy
mmap: Text file busy
no mapped regions, try 'help mmap'
ftruncate: Text file busy
fallocate: Text file busy
+56
View File
@@ -0,0 +1,56 @@
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0-or-newer
# Copyright (c) 2019, Oracle and/or its affiliates. All Rights Reserved.
#
# FS QA Test No. 570
#
# Check that we can't modify a block device that's an active swap device.
seq=`basename $0`
seqres=$RESULT_DIR/$seq
echo "QA output created by $seq"
here=`pwd`
tmp=/tmp/$$
status=1 # failure is the default!
trap "_cleanup; exit \$status" 0 1 2 3 15
_cleanup()
{
cd /
swapoff $SCRATCH_DEV
rm -rf $tmp.*
}
# get standard environment, filters and checks
. ./common/rc
. ./common/filter
# real QA test starts here
_supported_os Linux
_supported_fs generic
_require_test_program swapon
_require_scratch_nocheck
_require_block_device $SCRATCH_DEV
rm -f $seqres.full
$MKSWAP_PROG "$SCRATCH_DEV" >> $seqres.full
# Can you modify the swap dev via previously open file descriptors?
for verb in 1 2 3 4; do
echo "verb $verb"
"$here/src/swapon" -v $verb $SCRATCH_DEV
swapoff $SCRATCH_DEV
done
swapon $SCRATCH_DEV 2>&1 | _filter_scratch
# Can we write to it?
$XFS_IO_PROG -c 'pwrite -S 0x59 64k 64k' $SCRATCH_DEV
$XFS_IO_PROG -d -c 'pwrite -S 0x60 64k 64k' $SCRATCH_DEV
$XFS_IO_PROG -c 'mmap -rw 64k 64k' -c 'mwrite -S 0x61 64k 64k' $SCRATCH_DEV
# success, all done
status=0
exit
+12
View File
@@ -0,0 +1,12 @@
QA output created by 570
verb 1
pwrite: Text file busy
verb 2
mmap: Text file busy
verb 3
Caught signal 7, terminating...
verb 4
pwrite: Text file busy
pwrite: Text file busy
mmap: Text file busy
no mapped regions, try 'help mmap'
+2
View File
@@ -571,3 +571,5 @@
566 auto quick quota metadata
567 auto quick rw punch
568 auto quick rw prealloc
569 auto quick rw swap prealloc
570 auto quick rw swap