mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Enforce file size rlimits in VFS2
Updates #1035 PiperOrigin-RevId: 301255357
This commit is contained in:
committed by
gVisor bot
parent
0f60799a4f
commit
2a6c4369be
@@ -713,7 +713,7 @@ func (d *dentry) setStat(ctx context.Context, creds *auth.Credentials, stat *lin
|
||||
if stat.Mask&^(linux.STATX_MODE|linux.STATX_UID|linux.STATX_GID|linux.STATX_ATIME|linux.STATX_MTIME|linux.STATX_SIZE) != 0 {
|
||||
return syserror.EPERM
|
||||
}
|
||||
if err := vfs.CheckSetStat(creds, stat, uint16(atomic.LoadUint32(&d.mode))&^linux.S_IFMT, auth.KUID(atomic.LoadUint32(&d.uid)), auth.KGID(atomic.LoadUint32(&d.gid))); err != nil {
|
||||
if err := vfs.CheckSetStat(ctx, creds, stat, uint16(atomic.LoadUint32(&d.mode))&^linux.S_IFMT, auth.KUID(atomic.LoadUint32(&d.uid)), auth.KGID(atomic.LoadUint32(&d.gid))); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := mnt.CheckBeginWrite(); err != nil {
|
||||
|
||||
@@ -126,6 +126,11 @@ func (fd *regularFileFD) PWrite(ctx context.Context, src usermem.IOSequence, off
|
||||
if opts.Flags != 0 {
|
||||
return 0, syserror.EOPNOTSUPP
|
||||
}
|
||||
limit, err := vfs.CheckLimit(ctx, offset, src.NumBytes())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
src = src.TakeFirst64(limit)
|
||||
|
||||
d := fd.dentry()
|
||||
d.metadataMu.Lock()
|
||||
|
||||
@@ -107,6 +107,14 @@ func (fd *specialFileFD) PWrite(ctx context.Context, src usermem.IOSequence, off
|
||||
return 0, syserror.EOPNOTSUPP
|
||||
}
|
||||
|
||||
if fd.dentry().fileType() == linux.S_IFREG {
|
||||
limit, err := vfs.CheckLimit(ctx, offset, src.NumBytes())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
src = src.TakeFirst64(limit)
|
||||
}
|
||||
|
||||
// Do a buffered write. See rationale in PRead.
|
||||
if d := fd.dentry(); d.fs.opts.interop != InteropModeShared {
|
||||
d.touchCMtime(ctx)
|
||||
|
||||
@@ -112,7 +112,6 @@ func (f *defaultFileFD) PWrite(ctx context.Context, src usermem.IOSequence, offs
|
||||
if f.inode.isStream {
|
||||
return 0, syserror.ESPIPE
|
||||
}
|
||||
|
||||
return writeToHostFD(ctx, f.inode.hostFD, src, offset, int(opts.Flags))
|
||||
}
|
||||
|
||||
@@ -146,6 +145,12 @@ func writeToHostFD(ctx context.Context, hostFD int, src usermem.IOSequence, offs
|
||||
return 0, syserror.EOPNOTSUPP
|
||||
}
|
||||
|
||||
limit, err := vfs.CheckLimit(ctx, offset, src.NumBytes())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
src = src.TakeFirst64(limit)
|
||||
|
||||
var writer safemem.Writer
|
||||
if offset == -1 {
|
||||
writer = safemem.FromIOWriter{fd.NewReadWriter(hostFD)}
|
||||
|
||||
@@ -270,7 +270,7 @@ func (i *inode) fstat(opts vfs.StatOptions) (linux.Statx, error) {
|
||||
}
|
||||
|
||||
// SetStat implements kernfs.Inode.
|
||||
func (i *inode) SetStat(fs *vfs.Filesystem, creds *auth.Credentials, opts vfs.SetStatOptions) error {
|
||||
func (i *inode) SetStat(ctx context.Context, fs *vfs.Filesystem, creds *auth.Credentials, opts vfs.SetStatOptions) error {
|
||||
s := opts.Stat
|
||||
|
||||
m := s.Mask
|
||||
@@ -280,7 +280,7 @@ func (i *inode) SetStat(fs *vfs.Filesystem, creds *auth.Credentials, opts vfs.Se
|
||||
if m&^(linux.STATX_MODE|linux.STATX_SIZE|linux.STATX_ATIME|linux.STATX_MTIME) != 0 {
|
||||
return syserror.EPERM
|
||||
}
|
||||
if err := vfs.CheckSetStat(creds, &s, uint16(i.Mode().Permissions()), i.uid, i.gid); err != nil {
|
||||
if err := vfs.CheckSetStat(ctx, creds, &s, uint16(i.Mode().Permissions()), i.uid, i.gid); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -382,7 +382,7 @@ type fileDescription struct {
|
||||
// SetStat implements vfs.FileDescriptionImpl.
|
||||
func (f *fileDescription) SetStat(ctx context.Context, opts vfs.SetStatOptions) error {
|
||||
creds := auth.CredentialsFromContext(ctx)
|
||||
return f.inode.SetStat(nil, creds, opts)
|
||||
return f.inode.SetStat(ctx, nil, creds, opts)
|
||||
}
|
||||
|
||||
// Stat implements vfs.FileDescriptionImpl.
|
||||
|
||||
@@ -64,7 +64,7 @@ func (f *DynamicBytesFile) Open(rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vf
|
||||
// SetStat implements Inode.SetStat. By default DynamicBytesFile doesn't allow
|
||||
// inode attributes to be changed. Override SetStat() making it call
|
||||
// f.InodeAttrs to allow it.
|
||||
func (*DynamicBytesFile) SetStat(*vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
|
||||
func (*DynamicBytesFile) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
|
||||
return syserror.EPERM
|
||||
}
|
||||
|
||||
|
||||
@@ -209,5 +209,5 @@ func (fd *GenericDirectoryFD) SetStat(ctx context.Context, opts vfs.SetStatOptio
|
||||
fs := fd.filesystem()
|
||||
creds := auth.CredentialsFromContext(ctx)
|
||||
inode := fd.vfsfd.VirtualDentry().Dentry().Impl().(*Dentry).inode
|
||||
return inode.SetStat(fs, creds, opts)
|
||||
return inode.SetStat(ctx, fs, creds, opts)
|
||||
}
|
||||
|
||||
@@ -636,7 +636,7 @@ func (fs *Filesystem) SetStatAt(ctx context.Context, rp *vfs.ResolvingPath, opts
|
||||
if opts.Stat.Mask == 0 {
|
||||
return nil
|
||||
}
|
||||
return inode.SetStat(fs.VFSFilesystem(), rp.Credentials(), opts)
|
||||
return inode.SetStat(ctx, fs.VFSFilesystem(), rp.Credentials(), opts)
|
||||
}
|
||||
|
||||
// StatAt implements vfs.FilesystemImpl.StatAt.
|
||||
|
||||
@@ -234,14 +234,14 @@ func (a *InodeAttrs) Stat(*vfs.Filesystem, vfs.StatOptions) (linux.Statx, error)
|
||||
}
|
||||
|
||||
// SetStat implements Inode.SetStat.
|
||||
func (a *InodeAttrs) SetStat(fs *vfs.Filesystem, creds *auth.Credentials, opts vfs.SetStatOptions) error {
|
||||
func (a *InodeAttrs) SetStat(ctx context.Context, fs *vfs.Filesystem, creds *auth.Credentials, opts vfs.SetStatOptions) error {
|
||||
if opts.Stat.Mask == 0 {
|
||||
return nil
|
||||
}
|
||||
if opts.Stat.Mask&^(linux.STATX_MODE|linux.STATX_UID|linux.STATX_GID) != 0 {
|
||||
return syserror.EPERM
|
||||
}
|
||||
if err := vfs.CheckSetStat(creds, &opts.Stat, uint16(a.Mode().Permissions()), auth.KUID(atomic.LoadUint32(&a.uid)), auth.KGID(atomic.LoadUint32(&a.gid))); err != nil {
|
||||
if err := vfs.CheckSetStat(ctx, creds, &opts.Stat, uint16(a.Mode().Permissions()), auth.KUID(atomic.LoadUint32(&a.uid)), auth.KGID(atomic.LoadUint32(&a.gid))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -566,7 +566,7 @@ func (s *StaticDirectory) Open(rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs
|
||||
}
|
||||
|
||||
// SetStat implements Inode.SetStat not allowing inode attributes to be changed.
|
||||
func (*StaticDirectory) SetStat(*vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
|
||||
func (*StaticDirectory) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
|
||||
return syserror.EPERM
|
||||
}
|
||||
|
||||
|
||||
@@ -333,7 +333,7 @@ type inodeMetadata interface {
|
||||
// vfs.FilesystemImpl.SetStatAt. Implementations are responsible for checking
|
||||
// if the operation can be performed (see vfs.CheckSetStat() for common
|
||||
// checks).
|
||||
SetStat(fs *vfs.Filesystem, creds *auth.Credentials, opts vfs.SetStatOptions) error
|
||||
SetStat(ctx context.Context, fs *vfs.Filesystem, creds *auth.Credentials, opts vfs.SetStatOptions) error
|
||||
}
|
||||
|
||||
// Precondition: All methods in this interface may only be called on directory
|
||||
|
||||
@@ -91,7 +91,7 @@ type attrs struct {
|
||||
kernfs.InodeAttrs
|
||||
}
|
||||
|
||||
func (*attrs) SetStat(*vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
|
||||
func (*attrs) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
|
||||
return syserror.EPERM
|
||||
}
|
||||
|
||||
|
||||
@@ -56,6 +56,6 @@ func (s *StaticSymlink) Readlink(_ context.Context) (string, error) {
|
||||
}
|
||||
|
||||
// SetStat implements Inode.SetStat not allowing inode attributes to be changed.
|
||||
func (*StaticSymlink) SetStat(*vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
|
||||
func (*StaticSymlink) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
|
||||
return syserror.EPERM
|
||||
}
|
||||
|
||||
@@ -130,6 +130,6 @@ func (i *subtasksInode) Stat(vsfs *vfs.Filesystem, opts vfs.StatOptions) (linux.
|
||||
}
|
||||
|
||||
// SetStat implements Inode.SetStat not allowing inode attributes to be changed.
|
||||
func (*subtasksInode) SetStat(*vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
|
||||
func (*subtasksInode) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
|
||||
return syserror.EPERM
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ func (i *taskInode) Open(rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenO
|
||||
}
|
||||
|
||||
// SetStat implements Inode.SetStat not allowing inode attributes to be changed.
|
||||
func (*taskInode) SetStat(*vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
|
||||
func (*taskInode) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
|
||||
return syserror.EPERM
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ func (s *selfSymlink) Readlink(ctx context.Context) (string, error) {
|
||||
}
|
||||
|
||||
// SetStat implements Inode.SetStat not allowing inode attributes to be changed.
|
||||
func (*selfSymlink) SetStat(*vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
|
||||
func (*selfSymlink) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
|
||||
return syserror.EPERM
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ func (s *threadSelfSymlink) Readlink(ctx context.Context) (string, error) {
|
||||
}
|
||||
|
||||
// SetStat implements Inode.SetStat not allowing inode attributes to be changed.
|
||||
func (*threadSelfSymlink) SetStat(*vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
|
||||
func (*threadSelfSymlink) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
|
||||
return syserror.EPERM
|
||||
}
|
||||
|
||||
@@ -114,8 +114,8 @@ type dynamicBytesFileSetAttr struct {
|
||||
}
|
||||
|
||||
// SetStat implements Inode.SetStat.
|
||||
func (d *dynamicBytesFileSetAttr) SetStat(fs *vfs.Filesystem, creds *auth.Credentials, opts vfs.SetStatOptions) error {
|
||||
return d.DynamicBytesFile.InodeAttrs.SetStat(fs, creds, opts)
|
||||
func (d *dynamicBytesFileSetAttr) SetStat(ctx context.Context, fs *vfs.Filesystem, creds *auth.Credentials, opts vfs.SetStatOptions) error {
|
||||
return d.DynamicBytesFile.InodeAttrs.SetStat(ctx, fs, creds, opts)
|
||||
}
|
||||
|
||||
// cpuStats contains the breakdown of CPU time for /proc/stat.
|
||||
|
||||
@@ -95,7 +95,7 @@ func (fs *filesystem) newDir(creds *auth.Credentials, mode linux.FileMode, conte
|
||||
}
|
||||
|
||||
// SetStat implements Inode.SetStat not allowing inode attributes to be changed.
|
||||
func (*dir) SetStat(*vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
|
||||
func (*dir) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
|
||||
return syserror.EPERM
|
||||
}
|
||||
|
||||
|
||||
@@ -575,7 +575,7 @@ func (fs *filesystem) SetStatAt(ctx context.Context, rp *vfs.ResolvingPath, opts
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return d.inode.setStat(rp.Credentials(), &opts.Stat)
|
||||
return d.inode.setStat(ctx, rp.Credentials(), &opts.Stat)
|
||||
}
|
||||
|
||||
// StatAt implements vfs.FilesystemImpl.StatAt.
|
||||
|
||||
@@ -308,11 +308,18 @@ func (fd *regularFileFD) PWrite(ctx context.Context, src usermem.IOSequence, off
|
||||
return 0, nil
|
||||
}
|
||||
f := fd.inode().impl.(*regularFile)
|
||||
end := offset + srclen
|
||||
if end < offset {
|
||||
if end := offset + srclen; end < offset {
|
||||
// Overflow.
|
||||
return 0, syserror.EFBIG
|
||||
}
|
||||
|
||||
var err error
|
||||
srclen, err = vfs.CheckLimit(ctx, offset, srclen)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
src = src.TakeFirst64(srclen)
|
||||
|
||||
f.inode.mu.Lock()
|
||||
rw := getRegularFileReadWriter(f, offset)
|
||||
n, err := src.CopyInTo(ctx, rw)
|
||||
|
||||
@@ -299,14 +299,14 @@ func (i *inode) statTo(stat *linux.Statx) {
|
||||
}
|
||||
}
|
||||
|
||||
func (i *inode) setStat(creds *auth.Credentials, stat *linux.Statx) error {
|
||||
func (i *inode) setStat(ctx context.Context, creds *auth.Credentials, stat *linux.Statx) error {
|
||||
if stat.Mask == 0 {
|
||||
return nil
|
||||
}
|
||||
if stat.Mask&^(linux.STATX_MODE|linux.STATX_UID|linux.STATX_GID|linux.STATX_ATIME|linux.STATX_MTIME|linux.STATX_CTIME|linux.STATX_SIZE) != 0 {
|
||||
return syserror.EPERM
|
||||
}
|
||||
if err := vfs.CheckSetStat(creds, stat, uint16(atomic.LoadUint32(&i.mode))&^linux.S_IFMT, auth.KUID(atomic.LoadUint32(&i.uid)), auth.KGID(atomic.LoadUint32(&i.gid))); err != nil {
|
||||
if err := vfs.CheckSetStat(ctx, creds, stat, uint16(atomic.LoadUint32(&i.mode))&^linux.S_IFMT, auth.KUID(atomic.LoadUint32(&i.uid)), auth.KGID(atomic.LoadUint32(&i.gid))); err != nil {
|
||||
return err
|
||||
}
|
||||
i.mu.Lock()
|
||||
@@ -464,5 +464,5 @@ func (fd *fileDescription) Stat(ctx context.Context, opts vfs.StatOptions) (linu
|
||||
// SetStat implements vfs.FileDescriptionImpl.SetStat.
|
||||
func (fd *fileDescription) SetStat(ctx context.Context, opts vfs.SetStatOptions) error {
|
||||
creds := auth.CredentialsFromContext(ctx)
|
||||
return fd.inode().setStat(creds, &opts.Stat)
|
||||
return fd.inode().setStat(ctx, creds, &opts.Stat)
|
||||
}
|
||||
|
||||
@@ -173,12 +173,13 @@ func Truncate(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sysc
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
return 0, nil, setstatat(t, linux.AT_FDCWD, path, disallowEmptyPath, followFinalSymlink, &vfs.SetStatOptions{
|
||||
err = setstatat(t, linux.AT_FDCWD, path, disallowEmptyPath, followFinalSymlink, &vfs.SetStatOptions{
|
||||
Stat: linux.Statx{
|
||||
Mask: linux.STATX_SIZE,
|
||||
Size: uint64(length),
|
||||
},
|
||||
})
|
||||
return 0, nil, handleSetSizeError(t, err)
|
||||
}
|
||||
|
||||
// Ftruncate implements Linux syscall ftruncate(2).
|
||||
@@ -196,12 +197,13 @@ func Ftruncate(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sys
|
||||
}
|
||||
defer file.DecRef()
|
||||
|
||||
return 0, nil, file.SetStat(t, vfs.SetStatOptions{
|
||||
err := file.SetStat(t, vfs.SetStatOptions{
|
||||
Stat: linux.Statx{
|
||||
Mask: linux.STATX_SIZE,
|
||||
Size: uint64(length),
|
||||
},
|
||||
})
|
||||
return 0, nil, handleSetSizeError(t, err)
|
||||
}
|
||||
|
||||
// Utime implements Linux syscall utime(2).
|
||||
@@ -378,3 +380,12 @@ func setstatat(t *kernel.Task, dirfd int32, path fspath.Path, shouldAllowEmptyPa
|
||||
FollowFinalSymlink: bool(shouldFollowFinalSymlink),
|
||||
}, opts)
|
||||
}
|
||||
|
||||
func handleSetSizeError(t *kernel.Task, err error) error {
|
||||
if err == syserror.ErrExceedsFileSizeLimit {
|
||||
// Convert error to EFBIG and send a SIGXFSZ per setrlimit(2).
|
||||
t.SendSignal(kernel.SignalInfoNoInfo(linux.SIGXFSZ, t, t))
|
||||
return syserror.EFBIG
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user