aio: add regression test race between write and fcntl

perform AIO-DIO and fcntl(F_SETFL) concurently. Unaligned AIO likely
results in synchronization which makes the race window wider.

Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
Reviewed-by: Eryu Guan <eguan@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
This commit is contained in:
Dmitry Monakhov
2014-11-10 18:06:19 +11:00
committed by Dave Chinner
parent fd730cff44
commit 33e0889346
4 changed files with 204 additions and 0 deletions
+150
View File
@@ -0,0 +1,150 @@
/*
* Perform aio writes to file and toggle O_DIRECT flag concurrently
* this may trigger race between file->f_flags read and modification
* unuligned aio allow to makes race window wider.
* Regression test for https://lkml.org/lkml/2014/10/8/545 CVE-2014-8086
* Patch proposed: http://www.spinics.net/lists/linux-ext4/msg45683.html
*
* Copyright (c) 2014 Dmitry Monakhov. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <libaio.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#define BUF_SIZE 512
#define LOOP_SECONDS 10
static int do_aio_loop(int fd, void *buf)
{
int err, ret;
struct io_context *ctx = NULL;
struct io_event ev;
struct iocb iocb, *iocbs[] = { &iocb };
struct timeval start, now, delta = { 0, 0 };
ret = 0;
err = io_setup(1, &ctx);
if (err) {
fprintf(stderr, "error %s during %s\n",
strerror(-err), "io_setup" );
return 1;
}
gettimeofday(&start, NULL);
while (1) {
io_prep_pwrite(&iocb, fd, buf, BUF_SIZE, BUF_SIZE);
err = io_submit(ctx, 1, iocbs);
if (err != 1) {
fprintf(stderr, "error %s during %s\n",
strerror(-err),
"io_submit");
ret = 1;
break;
}
err = io_getevents(ctx, 1, 1, &ev, NULL);
if (err != 1) {
fprintf(stderr, "error %s during %s\n",
strerror(-err),
"io_getevents");
ret = 1;
break;
}
gettimeofday(&now, NULL);
timersub(&now, &start, &delta);
if (delta.tv_sec >= LOOP_SECONDS)
break;
}
io_destroy(ctx);
return ret;
}
int main(int argc, char **argv)
{
int flags, fd;
int pid1, pid2 = 0;
int ret1, ret = 0;
if (argc != 2){
printf("Usage %s fname\n", argv[0]);
return 1;
}
fd = open(argv[1], O_CREAT | O_TRUNC | O_RDWR, 0600);
if (fd < 0)
return 1;
pid1 = fork();
if (pid1 < 0)
return 1;
if (pid1 == 0) {
struct timeval start, now, delta = { 0, 0 };
gettimeofday(&start, NULL);
/* child: toggle O_DIRECT*/
flags = fcntl(fd, F_GETFL);
while (1) {
ret = fcntl(fd, F_SETFL, flags | O_DIRECT);
if (ret)
return ret;
ret = fcntl(fd, F_SETFL, flags);
if (ret)
return ret;
gettimeofday(&now, NULL);
timersub(&now, &start, &delta);
if (delta.tv_sec >= LOOP_SECONDS)
break;
}
} else {
/* parent: AIO */
void *buf;
posix_memalign(&buf, BUF_SIZE, BUF_SIZE);
/* Two tasks which performs unaligned aio will be serialized
which maks race window wider */
pid2 = fork();
if (pid2 < 0)
goto out;
else if (pid2 > 0)
printf("All tasks are spawned\n");
ret = do_aio_loop(fd, buf);
}
out:
/* Parent wait for all others */
if (pid2 > 0){
waitpid(pid1, &ret1, 0);
if (!ret)
ret = ret1;
waitpid(pid2, &ret1, 0);
} else {
waitpid(pid1, &ret1, 0);
}
if (!ret)
ret = ret1;
return ret;
}
+51
View File
@@ -0,0 +1,51 @@
#! /bin/bash
# FS QA Test No. 036
#
# CVE-2014-8086
# Run aio-dio-fcntl-race - test aio write race with O_DIRECT toggle
#
#-----------------------------------------------------------------------
# Copyright (c) 2014 Dmitry Monakhov. All Rights Reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it would be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#-----------------------------------------------------------------------
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 /
rm -f $tmp.*
}
# get standard environment, filters and checks
. ./common/rc
. ./common/filter
# real QA test starts here
_supported_fs generic
_supported_os Linux
_require_test
_run_aiodio aio-dio-fcntl-race
exit $status
+2
View File
@@ -0,0 +1,2 @@
QA output created by 036
All tasks are spawned
+1
View File
@@ -38,6 +38,7 @@
033 auto quick rw
034 auto quick metadata log
035 auto quick
036 auto aio rw stress
053 acl repair auto quick
062 attr udf auto quick
068 other auto freeze dangerous stress