Date: Mon, 22 Apr 2002 13:40:02 -0700 (PDT) From: "peter.edwards@openet-telecom.com" <petere@openet-telecom.com> To: freebsd-bugs@FreeBSD.org Subject: Re: kern/37057: Problem with rlimits on filesystem mounted from /dev/vn0c Message-ID: <200204222040.g3MKe2N38958@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/37057; it has been noted by GNATS.
From: "peter.edwards@openet-telecom.com" <petere@openet-telecom.com>
To: freebsd-gnats-submit@FreeBSD.org, xi@borderworlds.dk
Cc:
Subject: Re: kern/37057: Problem with rlimits on filesystem mounted from
/dev/vn0c
Date: Mon, 22 Apr 2002 15:51:30 +0100 (IST)
This comes from the filesystem on which the VN device's file lies,
rather from anything above it. To explain: When you write to a
file on a filesystem hosted by a VN device, which is in turn hosted
by a file on a UFS filesystem, you get a layering like this:
(1) UFS filesystem for /dev/vnX
(2) VN device
(3) UFS filesystem for file hosting VN device
(4) disk device/swap
The filesystem (1) is the one you are explicitly writing to.
Filesystem (3) is the one generating the error: each filesystem
implementation's write() method checks if it needs to generate
SIGXFSZ, and the VN device calls VOP_WRITE(). Of course, the VN
device is accessing the entire file on which the filesystem is laid
out, so, its not surprising that it attempts to write where it
shouldn't.
There's a comment in ufs/ufs/ufs_readwrite.c which indicates what
/*
* Maybe this should be above the vnode op call, but so long as
* file servers have no limits, I don't think it matters.
*/
(This is present in rev 1.1, so its quite old)
I wonder if:
The vn device could use VOP_STRATEGY to do its I/O
and
If the best place for the check isn't in the write(2) system
call, where we know which object the user is acting on.
However, its not quite trivial to move this to the VOP operation
or write system call, because each filesystem implementation currently
updates uio_offset for IO_APPEND mode writes, and only the
filesystem-internal representation of the vnode has the current
length of the file available, so you don't have enough information
in VOP_WRITE or dofilewrite() to do the rlimits check, unlesee you call
VOP_GETATTR() and that would probably be Bad.
In the meantime, you can hack your way around by noting that user
requests are to UIO_USERSPACE, while kernel requests to
UIO_SYSSPACE/UIO_NOCOPY, and adding that to the check for sending
SIGXFSZ (patch attached).
Security could be an issue here. However, I think the only way to
extend a file from user-land at all is via write[v](2) or truncate(2),
and the only UIO_USERSPACEs I can find that can ever hit VOP_WRITE
come from write[v](2).
mmap(2) and strategy interactions never extend the file, so they
are not an issue.
(Which actually brings up another point: you can currently modify a file at
an offset beyond your maximum filesize with mmap(), but not with
write(). Of course, you can't make the file any bigger with mmap(),
but its still "weaker" security in mmap() than write())
So I don't think there's any loss of security with the following
patch, but I'm not an expert, so beware...
The patch updates the checks done by SMBFS, EXT2FS, MSDOSFS NFS, NWFS, and,
of course UFS/FFS.
-------------->8-------------- Cut Here -------------->8--------------
Index: fs/smbfs/smbfs_io.c
===================================================================
RCS file: /pub/FreeBSD/development/FreeBSD-CVS/src/sys/fs/smbfs/smbfs_io.c,v
retrieving revision 1.3.2.1
diff -u -r1.3.2.1 smbfs_io.c
--- fs/smbfs/smbfs_io.c 22 May 2001 08:32:26 -0000 1.3.2.1
+++ fs/smbfs/smbfs_io.c 22 Apr 2002 13:42:59 -0000
@@ -270,7 +270,8 @@
}
if (uiop->uio_resid == 0)
return 0;
- if (p && uiop->uio_offset + uiop->uio_resid > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
+ if (p && uiop->uio_segflg == UIO_USERSPACE && uiop->uio_offset +
+ uiop->uio_resid > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
psignal(p, SIGXFSZ);
return EFBIG;
}
Index: gnu/ext2fs/ext2_readwrite.c
===================================================================
RCS file: /pub/FreeBSD/development/FreeBSD-CVS/src/sys/gnu/ext2fs/ext2_readwrite.c,v
retrieving revision 1.18.2.2
diff -u -r1.18.2.2 ext2_readwrite.c
--- gnu/ext2fs/ext2_readwrite.c 22 Dec 2000 18:44:33 -0000 1.18.2.2
+++ gnu/ext2fs/ext2_readwrite.c 22 Apr 2002 13:43:26 -0000
@@ -218,6 +218,7 @@
*/
p = uio->uio_procp;
if (vp->v_type == VREG && p &&
+ uio->segflg == UIO_USERSPACE &&
uio->uio_offset + uio->uio_resid >
p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
psignal(p, SIGXFSZ);
Index: msdosfs/msdosfs_vnops.c
===================================================================
RCS file: /pub/FreeBSD/development/FreeBSD-CVS/src/sys/msdosfs/Attic/msdosfs_vnops.c,v
retrieving revision 1.95.2.1
diff -u -r1.95.2.1 msdosfs_vnops.c
--- msdosfs/msdosfs_vnops.c 18 Jul 2000 13:19:13 -0000 1.95.2.1
+++ msdosfs/msdosfs_vnops.c 22 Apr 2002 14:26:49 -0000
@@ -688,6 +688,7 @@
* If they've exceeded their filesize limit, tell them about it.
*/
if (p &&
+ uio->uio_segflg == UIO_USERSPACE &&
((uoff_t)uio->uio_offset + uio->uio_resid >
p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) {
psignal(p, SIGXFSZ);
Index: nfs/nfs_bio.c
===================================================================
RCS file: /pub/FreeBSD/development/FreeBSD-CVS/src/sys/nfs/Attic/nfs_bio.c,v
retrieving revision 1.83.2.2
diff -u -r1.83.2.2 nfs_bio.c
--- nfs/nfs_bio.c 20 Dec 2001 19:56:28 -0000 1.83.2.2
+++ nfs/nfs_bio.c 22 Apr 2002 13:44:51 -0000
@@ -822,8 +822,8 @@
* Maybe this should be above the vnode op call, but so long as
* file servers have no limits, i don't think it matters
*/
- if (p && uio->uio_offset + uio->uio_resid >
- p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
+ if (p && uio->uio_segflg == UIO_USERSPACE && uio->uio_offset +
+ uio->uio_resid > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
psignal(p, SIGXFSZ);
if (haverslock)
nfs_rsunlock(np, p);
Index: nwfs/nwfs_io.c
===================================================================
RCS file: /pub/FreeBSD/development/FreeBSD-CVS/src/sys/nwfs/Attic/nwfs_io.c,v
retrieving revision 1.6.2.1
diff -u -r1.6.2.1 nwfs_io.c
--- nwfs/nwfs_io.c 25 Oct 2000 02:11:10 -0000 1.6.2.1
+++ nwfs/nwfs_io.c 22 Apr 2002 13:45:23 -0000
@@ -235,7 +235,8 @@
}
}
if (uiop->uio_resid == 0) return 0;
- if (p && uiop->uio_offset + uiop->uio_resid > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
+ if (p && uiop->uio_segflg == UIO_USERSPACE &&
+ uiop->uio_offset + uiop->uio_resid > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
psignal(p, SIGXFSZ);
return (EFBIG);
}
Index: ufs/ufs/ufs_readwrite.c
===================================================================
RCS file: /pub/FreeBSD/development/FreeBSD-CVS/src/sys/ufs/ufs/ufs_readwrite.c,v
retrieving revision 1.65.2.10
diff -u -r1.65.2.10 ufs_readwrite.c
--- ufs/ufs/ufs_readwrite.c 6 Mar 2002 19:53:08 -0000 1.65.2.10
+++ ufs/ufs/ufs_readwrite.c 22 Apr 2002 14:36:14 -0000
@@ -382,6 +382,7 @@
/*
* Vnode op for writing.
*/
+
int
WRITE(ap)
struct vop_write_args /* {
@@ -451,9 +452,12 @@
/*
* Maybe this should be above the vnode op call, but so long as
* file servers have no limits, I don't think it matters.
+ * XXX: Only check !UIO_USERSPACE requests: we assume requests
+ * initiated by the kernel will be valid.
*/
p = uio->uio_procp;
if (vp->v_type == VREG && p &&
+ uio->uio_segflg == UIO_USERSPACE &&
uio->uio_offset + uio->uio_resid >
p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
psignal(p, SIGXFSZ);
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200204222040.g3MKe2N38958>
