Add ENAMETOOLONG checks in overlayfs.

Linux overlayfs uses the max of all layers' filename length limit. Do the same
in gVisor.

This is needed to get PHP runtime test ext/standard/tests/strings/007.phpt to
pass with overlayfs.

PiperOrigin-RevId: 493942515
This commit is contained in:
Ayush Ranjan
2022-12-08 11:04:37 -08:00
committed by gVisor bot
parent f14b4bb3ca
commit d17af25336
4 changed files with 60 additions and 0 deletions
+9
View File
@@ -161,6 +161,9 @@ afterSymlink:
rp.Advance()
return d.parent, d.parent.topLookupLayer(), nil
}
if uint64(len(name)) > fs.maxFilenameLen {
return nil, lookupLayerNone, linuxerr.ENAMETOOLONG
}
child, topLookupLayer, err := fs.getChildLocked(ctx, d, name, ds)
if err != nil {
return nil, topLookupLayer, err
@@ -504,6 +507,9 @@ func (fs *filesystem) doCreateAt(ctx context.Context, rp *vfs.ResolvingPath, ct
if name == "." || name == ".." {
return linuxerr.EEXIST
}
if uint64(len(name)) > fs.maxFilenameLen {
return linuxerr.ENAMETOOLONG
}
if parent.vfsd.IsDead() {
return linuxerr.ENOENT
}
@@ -1090,6 +1096,9 @@ func (fs *filesystem) RenameAt(ctx context.Context, rp *vfs.ResolvingPath, oldPa
}
return linuxerr.EBUSY
}
if uint64(len(newName)) > fs.maxFilenameLen {
return linuxerr.ENAMETOOLONG
}
// Do not check for newName length, since different filesystem
// implementations impose different name limits. upperfs.RenameAt() will fail
// appropriately if it has to.
+32
View File
@@ -125,6 +125,9 @@ type filesystem struct {
// lastDirIno is the last inode number assigned to a directory. lastDirIno
// is protected by dirInoCacheMu.
lastDirIno uint64
// MaxFilenameLen is the maximum filename length allowed by the overlayfs.
maxFilenameLen uint64
}
// +stateify savable
@@ -264,9 +267,23 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
dirDevMinor: dirDevMinor,
lowerDevMinors: make(map[layerDevNumber]uint32),
dirInoCache: make(map[layerDevNoAndIno]uint64),
maxFilenameLen: linux.NAME_MAX,
}
fs.vfsfs.Init(vfsObj, &fstype, fs)
// Configure max filename length. Similar to what Linux does in
// fs/overlayfs/super.c:ovl_fill_super() -> ... -> ovl_check_namelen().
if fsopts.UpperRoot.Ok() {
if err := fs.updateMaxNameLen(ctx, creds, vfsObj, fs.opts.UpperRoot); err != nil {
ctx.Debugf("overlay.FilesystemType.GetFilesystem: failed to StatFSAt on upper layer root: %v", err)
}
}
for _, lowerRoot := range fsopts.LowerRoots {
if err := fs.updateMaxNameLen(ctx, creds, vfsObj, lowerRoot); err != nil {
ctx.Debugf("overlay.FilesystemType.GetFilesystem: failed to StatFSAt on lower layer root: %v", err)
}
}
// Construct the root dentry.
root := fs.newDentry()
root.refs = atomicbitops.FromInt64(1)
@@ -368,6 +385,21 @@ func (fs *filesystem) Release(ctx context.Context) {
}
}
// updateMaxNameLen is analogous to fs/overlayfs/super.c:ovl_check_namelen().
func (fs *filesystem) updateMaxNameLen(ctx context.Context, creds *auth.Credentials, vfsObj *vfs.VirtualFilesystem, vd vfs.VirtualDentry) error {
statfs, err := vfsObj.StatFSAt(ctx, creds, &vfs.PathOperation{
Root: vd,
Start: vd,
})
if err != nil {
return err
}
if statfs.NameLength > fs.maxFilenameLen {
fs.maxFilenameLen = statfs.NameLength
}
return nil
}
func (fs *filesystem) statFS(ctx context.Context) (linux.Statfs, error) {
// Always statfs the root of the topmost layer. Compare Linux's
// fs/overlayfs/super.c:ovl_statfs().