Staging
v0.8.1
https://github.com/torvalds/linux
Revision 5b41e74ad1b0bf7bc51765ae74e5dc564afc3e48 authored by Dmitri Monakhov on 28 March 2008, 21:15:52 UTC, committed by Linus Torvalds on 28 March 2008, 21:45:21 UTC
Current nobh_write_end() implementation ignore partial writes(copied < len)
case if page was fully mapped and simply mark page as Uptodate, which is
totally wrong because area [pos+copied, pos+len) wasn't updated explicitly in
previous write_begin call.  It simply contains garbage from pagecache and
result in data leakage.

#TEST_CASE_BEGIN:
~~~~~~~~~~~~~~~~
In fact issue triggered by classical testcase
	open("/mnt/test", O_RDWR|O_CREAT|O_TRUNC, 0666) = 3
	ftruncate(3, 409600)                    = 0
	writev(3, [{"a", 1}, {NULL, 4095}], 2)  = 1
##TESTCASE_SOURCE:
~~~~~~~~~~~~~~~~~
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <sys/mman.h>
#include <errno.h>
int main(int argc, char **argv)
{
	int fd,  ret;
	void* p;
	struct iovec iov[2];
	fd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666);
	ftruncate(fd, 409600);
	iov[0].iov_base="a";
	iov[0].iov_len=1;
	iov[1].iov_base=NULL;
	iov[1].iov_len=4096;
	ret = writev(fd, iov, sizeof(iov)/sizeof(struct iovec));
	printf("writev  = %d, err = %d\n", ret, errno);
	return 0;
}
##TESTCASE RESULT:
~~~~~~~~~~~~~~~~~~
[root@ts63 ~]# mount | grep mnt2
/dev/mapper/test on /mnt2 type ext2 (rw,nobh)
[root@ts63 ~]#  /tmp/writev /mnt2/test
writev  = 1, err = 0
[root@ts63 ~]# hexdump -C /mnt2/test

00000000  61 65 62 6f 6f 74 00 00  f0 b9 b4 59 3a 00 00 00  |aeboot.....Y:...|
00000010  20 00 00 00 00 00 00 00  21 00 00 00 00 00 00 00  | .......!.......|
00000020  df df df df df df df df  df df df df df df df df  |................|
00000030  3a 00 00 00 2a 00 00 00  21 00 00 00 00 00 00 00  |:...*...!.......|
00000040  60 c0 8c 00 00 00 00 00  40 4a 8d 00 00 00 00 00  |`.......@J......|
00000050  00 00 00 00 00 00 00 00  41 00 00 00 00 00 00 00  |........A.......|
00000060  74 69 6d 65 20 64 64 20  69 66 3d 2f 64 65 76 2f  |time dd if=/dev/|
00000070  6c 6f 6f 70 30 20 20 6f  66 3d 2f 64 65 76 2f 6e  |loop0  of=/dev/n|
skip..
00000f50  00 00 00 00 00 00 00 00  31 00 00 00 00 00 00 00  |........1.......|
00000f60  6d 6b 66 73 2e 65 78 74  33 20 2f 64 65 76 2f 76  |mkfs.ext3 /dev/v|
00000f70  7a 76 67 2f 74 65 73 74  20 2d 62 34 30 39 36 00  |zvg/test -b4096.|
00000f80  a0 fe 8c 00 00 00 00 00  21 00 00 00 00 00 00 00  |........!.......|
00000f90  23 31 32 30 35 39 35 30  34 30 34 00 3a 00 00 00  |#1205950404.:...|
00000fa0  20 00 8d 00 00 00 00 00  21 00 00 00 00 00 00 00  | .......!.......|
00000fb0  d0 cf 8c 00 00 00 00 00  10 d0 8c 00 00 00 00 00  |................|
00000fc0  00 00 00 00 00 00 00 00  41 00 00 00 00 00 00 00  |........A.......|
00000fd0  6d 6f 75 6e 74 20 2f 64  65 76 2f 76 7a 76 67 2f  |mount /dev/vzvg/|
00000fe0  74 65 73 74 20 20 2f 76  7a 20 2d 6f 20 64 61 74  |test  /vz -o dat|
00000ff0  61 3d 77 72 69 74 65 62  61 63 6b 00 00 00 00 00  |a=writeback.....|
00001000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

As you can see file's page contains garbage from pagecache instead of zeros.
#TEST_CASE_END

Attached patch:
- Add sanity check BUG_ON in order to prevent incorrect usage by caller,
  This is function invariant because page can has buffers and in no zero
  *fadata pointer at the same time.
- Always attach buffers to page is it is partial write case.
- Always switch back to generic_write_end if page has buffers.
  This is reasonable because if page already has buffer then generic_write_begin
  was called previously.

Signed-off-by: Dmitri Monakhov <dmonakhov@openvz.org>
Reviewed-by: Nick Piggin <npiggin@suse.de>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 1d4a788
History
Tip revision: 5b41e74ad1b0bf7bc51765ae74e5dc564afc3e48 authored by Dmitri Monakhov on 28 March 2008, 21:15:52 UTC
vfs: fix data leak in nobh_write_end()
Tip revision: 5b41e74
File Mode Size
basic
genksyms
kconfig
ksymoops
mod
package
rt-tester
.gitignore -rw-r--r-- 77 bytes
Kbuild.include -rw-r--r-- 9.1 KB
Lindent -rwxr-xr-x 65 bytes
Makefile -rw-r--r-- 893 bytes
Makefile.build -rw-r--r-- 11.1 KB
Makefile.clean -rw-r--r-- 3.2 KB
Makefile.headersinst -rw-r--r-- 6.9 KB
Makefile.host -rw-r--r-- 6.5 KB
Makefile.lib -rw-r--r-- 6.7 KB
Makefile.modinst -rw-r--r-- 1.0 KB
Makefile.modpost -rw-r--r-- 4.9 KB
bin2c.c -rw-r--r-- 702 bytes
binoffset.c -rw-r--r-- 3.9 KB
bloat-o-meter -rwxr-xr-x 1.7 KB
checkincludes.pl -rwxr-xr-x 529 bytes
checkkconfigsymbols.sh -rwxr-xr-x 1.8 KB
checkpatch.pl -rwxr-xr-x 50.2 KB
checkstack.pl -rwxr-xr-x 4.2 KB
checksyscalls.sh -rwxr-xr-x 3.1 KB
checkversion.pl -rwxr-xr-x 1.8 KB
cleanfile -rwxr-xr-x 3.4 KB
cleanpatch -rwxr-xr-x 5.0 KB
conmakehash.c -rw-r--r-- 6.0 KB
decodecode -rw-r--r-- 1.1 KB
export_report.pl -rw-r--r-- 4.2 KB
extract-ikconfig -rwxr-xr-x 1.7 KB
gcc-version.sh -rw-r--r-- 818 bytes
gcc-x86_64-has-stack-protector.sh -rw-r--r-- 187 bytes
gen_initramfs_list.sh -rw-r--r-- 6.6 KB
hdrcheck.sh -rwxr-xr-x 281 bytes
kallsyms.c -rw-r--r-- 13.3 KB
kernel-doc -rwxr-xr-x 55.3 KB
makelst -rwxr-xr-x 773 bytes
mkcompile_h -rwxr-xr-x 2.5 KB
mkmakefile -rw-r--r-- 1.0 KB
mksysmap -rw-r--r-- 1.3 KB
mkuboot.sh -rwxr-xr-x 379 bytes
mkversion -rw-r--r-- 74 bytes
namespace.pl -rwxr-xr-x 13.1 KB
patch-kernel -rwxr-xr-x 9.7 KB
pnmtologo.c -rw-r--r-- 11.7 KB
profile2linkerlist.pl -rw-r--r-- 378 bytes
setlocalversion -rwxr-xr-x 1.5 KB
show_delta -rwxr-xr-x 3.0 KB
unifdef.c -rw-r--r-- 29.0 KB
ver_linux -rwxr-xr-x 3.2 KB

back to top