From 999da09776ffb248df0a9fa1fe2939d7ee8306b0 Mon Sep 17 00:00:00 2001 From: millert Date: Mon, 23 May 2022 15:17:11 +0000 Subject: [PATCH] Respect RLIMIT_FSIZE when extending a file via truncat(2)/ftruncate(2). This refactors the commin parts of sys_truncate() and sys_ftruncate() into dotruncate(). If the new size of the file is larger than the RLIMIT_FSIZE limit _and_ the file is being extended, not truncated, return EFBIG. Adapted from a diff by Piotr Durlej. With help from and OK by deraadt@ guenther@. --- lib/libc/sys/truncate.2 | 7 ++--- sys/kern/vfs_syscalls.c | 57 ++++++++++++++++++++++++++--------------- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/lib/libc/sys/truncate.2 b/lib/libc/sys/truncate.2 index 820583c650e..6356841033d 100644 --- a/lib/libc/sys/truncate.2 +++ b/lib/libc/sys/truncate.2 @@ -1,4 +1,4 @@ -.\" $OpenBSD: truncate.2,v 1.20 2020/02/11 13:19:17 schwarze Exp $ +.\" $OpenBSD: truncate.2,v 1.21 2022/05/23 15:17:11 millert Exp $ .\" $NetBSD: truncate.2,v 1.7 1995/02/27 12:39:00 cgd Exp $ .\" .\" Copyright (c) 1983, 1991, 1993 @@ -30,7 +30,7 @@ .\" .\" @(#)truncate.2 8.1 (Berkeley) 6/4/93 .\" -.Dd $Mdocdate: February 11 2020 $ +.Dd $Mdocdate: May 23 2022 $ .Dt TRUNCATE 2 .Os .Sh NAME @@ -73,7 +73,8 @@ is a negative value. .It Bq Er EFBIG The .Fa length -exceeds the maximum file size of the underlying filesystem. +exceeds the process's file size limit or the maximum file size +of the underlying filesystem. .It Bq Er EIO An I/O error occurred updating the inode. .El diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 31122a286f4..4a8e37afb4c 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_syscalls.c,v 1.356 2022/02/17 03:12:34 rob Exp $ */ +/* $OpenBSD: vfs_syscalls.c,v 1.357 2022/05/23 15:17:11 millert Exp $ */ /* $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $ */ /* @@ -60,6 +60,8 @@ #include #include #include +#include +#include #include @@ -2808,6 +2810,35 @@ dofutimens(struct proc *p, int fd, struct timespec ts[2]) return (dovutimens(p, vp, ts)); } +/* + * Truncate a file given a vnode. + */ +int +dotruncate(struct proc *p, struct vnode *vp, off_t len) +{ + struct vattr vattr; + int error; + + if (len < 0) + return EINVAL; + if (vp->v_type == VDIR) + return EISDIR; + if ((error = vn_writechk(vp)) != 0) + return error; + if (vp->v_type == VREG && len > lim_cur_proc(p, RLIMIT_FSIZE)) { + if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0) + return error; + if (len > vattr.va_size) { + /* if extending over the limit, send signal and fail */ + psignal(p, SIGXFSZ); + return EFBIG; + } + } + VATTR_NULL(&vattr); + vattr.va_size = len; + return VOP_SETATTR(vp, &vattr, p->p_ucred, p); +} + /* * Truncate a file given its path name. */ @@ -2819,7 +2850,6 @@ sys_truncate(struct proc *p, void *v, register_t *retval) syscallarg(off_t) length; } */ *uap = v; struct vnode *vp; - struct vattr vattr; int error; struct nameidata nd; @@ -2830,14 +2860,8 @@ sys_truncate(struct proc *p, void *v, register_t *retval) return (error); vp = nd.ni_vp; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - if (vp->v_type == VDIR) - error = EISDIR; - else if ((error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0 && - (error = vn_writechk(vp)) == 0) { - VATTR_NULL(&vattr); - vattr.va_size = SCARG(uap, length); - error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); - } + if ((error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) + error = dotruncate(p, vp, SCARG(uap, length)); vput(vp); return (error); } @@ -2852,28 +2876,19 @@ sys_ftruncate(struct proc *p, void *v, register_t *retval) syscallarg(int) fd; syscallarg(off_t) length; } */ *uap = v; - struct vattr vattr; struct vnode *vp; struct file *fp; - off_t len; int error; if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0) return (error); - len = SCARG(uap, length); - if ((fp->f_flag & FWRITE) == 0 || len < 0) { + if ((fp->f_flag & FWRITE) == 0) { error = EINVAL; goto bad; } vp = fp->f_data; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - if (vp->v_type == VDIR) - error = EISDIR; - else if ((error = vn_writechk(vp)) == 0) { - VATTR_NULL(&vattr); - vattr.va_size = len; - error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); - } + error = dotruncate(p, vp, SCARG(uap, length)); VOP_UNLOCK(vp); bad: FRELE(fp, p); -- 2.20.1