Fix mknod and inotify syscall test

This change fixes a few things:
- creating sockets using mknod(2) is supported via vfs2
- fsgofer can create regular files via mknod(2)
- mode = 0 for mknod(2) will be interpreted as regular file in vfs2 as well

Updates #2923

PiperOrigin-RevId: 320074267
This commit is contained in:
Ayush Ranjan
2020-07-07 15:35:01 -07:00
committed by gVisor bot
parent c8aab5cbee
commit 10930189c3
6 changed files with 84 additions and 20 deletions
+1 -1
View File
@@ -277,7 +277,7 @@ func (fs *filesystem) MknodAt(ctx context.Context, rp *vfs.ResolvingPath, opts v
creds := rp.Credentials()
var childInode *inode
switch opts.Mode.FileType() {
case 0, linux.S_IFREG:
case linux.S_IFREG:
childInode = fs.newRegularFile(creds.EffectiveKUID, creds.EffectiveKGID, opts.Mode)
case linux.S_IFIFO:
childInode = fs.newNamedPipe(creds.EffectiveKUID, creds.EffectiveKGID, opts.Mode)
+9 -4
View File
@@ -107,7 +107,7 @@ func Mknod(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
addr := args[0].Pointer()
mode := args[1].ModeT()
dev := args[2].Uint()
return 0, nil, mknodat(t, linux.AT_FDCWD, addr, mode, dev)
return 0, nil, mknodat(t, linux.AT_FDCWD, addr, linux.FileMode(mode), dev)
}
// Mknodat implements Linux syscall mknodat(2).
@@ -116,10 +116,10 @@ func Mknodat(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sysca
addr := args[1].Pointer()
mode := args[2].ModeT()
dev := args[3].Uint()
return 0, nil, mknodat(t, dirfd, addr, mode, dev)
return 0, nil, mknodat(t, dirfd, addr, linux.FileMode(mode), dev)
}
func mknodat(t *kernel.Task, dirfd int32, addr usermem.Addr, mode uint, dev uint32) error {
func mknodat(t *kernel.Task, dirfd int32, addr usermem.Addr, mode linux.FileMode, dev uint32) error {
path, err := copyInPath(t, addr)
if err != nil {
return err
@@ -129,9 +129,14 @@ func mknodat(t *kernel.Task, dirfd int32, addr usermem.Addr, mode uint, dev uint
return err
}
defer tpop.Release()
// "Zero file type is equivalent to type S_IFREG." - mknod(2)
if mode.FileType() == 0 {
mode |= linux.ModeRegular
}
major, minor := linux.DecodeDeviceID(dev)
return t.Kernel().VFS().MknodAt(t, t.Credentials(), &tpop.pop, &vfs.MknodOptions{
Mode: linux.FileMode(mode &^ t.FSContext().Umask()),
Mode: mode &^ linux.FileMode(t.FSContext().Umask()),
DevMajor: uint32(major),
DevMinor: minor,
})
+1
View File
@@ -128,6 +128,7 @@ var allowedSyscalls = seccomp.SyscallRules{
syscall.SYS_MADVISE: {},
unix.SYS_MEMFD_CREATE: {}, /// Used by flipcall.PacketWindowAllocator.Init().
syscall.SYS_MKDIRAT: {},
syscall.SYS_MKNODAT: {},
// Used by the Go runtime as a temporarily workaround for a Linux
// 5.2-5.4 bug.
//
+47 -13
View File
@@ -139,7 +139,7 @@ func (a *attachPoint) Attach() (p9.File, error) {
return nil, fmt.Errorf("unable to open %q: %v", a.prefix, err)
}
stat, err := stat(f.FD())
stat, err := fstat(f.FD())
if err != nil {
return nil, fmt.Errorf("unable to stat %q: %v", a.prefix, err)
}
@@ -352,7 +352,7 @@ func newFDMaybe(file *fd.FD) *fd.FD {
return dup
}
func stat(fd int) (syscall.Stat_t, error) {
func fstat(fd int) (syscall.Stat_t, error) {
var stat syscall.Stat_t
if err := syscall.Fstat(fd, &stat); err != nil {
return syscall.Stat_t{}, err
@@ -360,6 +360,14 @@ func stat(fd int) (syscall.Stat_t, error) {
return stat, nil
}
func stat(path string) (syscall.Stat_t, error) {
var stat syscall.Stat_t
if err := syscall.Stat(path, &stat); err != nil {
return syscall.Stat_t{}, err
}
return stat, nil
}
func fchown(fd int, uid p9.UID, gid p9.GID) error {
return syscall.Fchownat(fd, "", int(uid), int(gid), linux.AT_EMPTY_PATH|unix.AT_SYMLINK_NOFOLLOW)
}
@@ -388,7 +396,7 @@ func (l *localFile) Open(flags p9.OpenFlags) (*fd.FD, p9.QID, uint32, error) {
}
}
stat, err := stat(newFile.FD())
stat, err := fstat(newFile.FD())
if err != nil {
if newFile != l.file {
newFile.Close()
@@ -449,7 +457,7 @@ func (l *localFile) Create(name string, mode p9.OpenFlags, perm p9.FileMode, uid
if err := fchown(child.FD(), uid, gid); err != nil {
return nil, nil, p9.QID{}, 0, extractErrno(err)
}
stat, err := stat(child.FD())
stat, err := fstat(child.FD())
if err != nil {
return nil, nil, p9.QID{}, 0, extractErrno(err)
}
@@ -497,7 +505,7 @@ func (l *localFile) Mkdir(name string, perm p9.FileMode, uid p9.UID, gid p9.GID)
if err := fchown(f.FD(), uid, gid); err != nil {
return p9.QID{}, extractErrno(err)
}
stat, err := stat(f.FD())
stat, err := fstat(f.FD())
if err != nil {
return p9.QID{}, extractErrno(err)
}
@@ -517,7 +525,7 @@ func (l *localFile) Walk(names []string) ([]p9.QID, p9.File, error) {
return nil, nil, extractErrno(err)
}
stat, err := stat(newFile.FD())
stat, err := fstat(newFile.FD())
if err != nil {
newFile.Close()
return nil, nil, extractErrno(err)
@@ -542,7 +550,7 @@ func (l *localFile) Walk(names []string) ([]p9.QID, p9.File, error) {
if err != nil {
return nil, nil, extractErrno(err)
}
stat, err := stat(f.FD())
stat, err := fstat(f.FD())
if err != nil {
f.Close()
return nil, nil, extractErrno(err)
@@ -592,7 +600,7 @@ func (l *localFile) FSync() error {
// GetAttr implements p9.File.
func (l *localFile) GetAttr(_ p9.AttrMask) (p9.QID, p9.AttrMask, p9.Attr, error) {
stat, err := stat(l.file.FD())
stat, err := fstat(l.file.FD())
if err != nil {
return p9.QID{}, p9.AttrMask{}, p9.Attr{}, extractErrno(err)
}
@@ -880,7 +888,7 @@ func (l *localFile) Symlink(target, newName string, uid p9.UID, gid p9.GID) (p9.
if err := fchown(f.FD(), uid, gid); err != nil {
return p9.QID{}, extractErrno(err)
}
stat, err := stat(f.FD())
stat, err := fstat(f.FD())
if err != nil {
return p9.QID{}, extractErrno(err)
}
@@ -907,13 +915,39 @@ func (l *localFile) Link(target p9.File, newName string) error {
}
// Mknod implements p9.File.
//
// Not implemented.
func (*localFile) Mknod(_ string, _ p9.FileMode, _ uint32, _ uint32, _ p9.UID, _ p9.GID) (p9.QID, error) {
func (l *localFile) Mknod(name string, mode p9.FileMode, _ uint32, _ uint32, uid p9.UID, gid p9.GID) (p9.QID, error) {
conf := l.attachPoint.conf
if conf.ROMount {
if conf.PanicOnWrite {
panic("attempt to write to RO mount")
}
return p9.QID{}, syscall.EROFS
}
hostPath := path.Join(l.hostPath, name)
// Return EEXIST if the file already exists.
if _, err := stat(hostPath); err == nil {
return p9.QID{}, syscall.EEXIST
}
// From mknod(2) man page:
// "EPERM: [...] if the filesystem containing pathname does not support
// the type of node requested."
return p9.QID{}, syscall.EPERM
if mode.FileType() != p9.ModeRegular {
return p9.QID{}, syscall.EPERM
}
// Allow Mknod to create regular files.
if err := syscall.Mknod(hostPath, uint32(mode), 0); err != nil {
return p9.QID{}, err
}
stat, err := stat(hostPath)
if err != nil {
return p9.QID{}, extractErrno(err)
}
return l.attachPoint.makeQID(stat), nil
}
// UnlinkAt implements p9.File.
+2
View File
@@ -283,6 +283,7 @@ syscall_test(
size = "medium",
add_overlay = False, # TODO(gvisor.dev/issue/317): enable when fixed.
test = "//test/syscalls/linux:inotify_test",
vfs2 = "True",
)
syscall_test(
@@ -351,6 +352,7 @@ syscall_test(
syscall_test(
add_overlay = True,
test = "//test/syscalls/linux:mknod_test",
vfs2 = "True",
)
syscall_test(
+24 -2
View File
@@ -15,6 +15,7 @@
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
@@ -39,7 +40,28 @@ TEST(MknodTest, RegularFile) {
EXPECT_THAT(mknod(node1.c_str(), 0, 0), SyscallSucceeds());
}
TEST(MknodTest, MknodAtRegularFile) {
TEST(MknodTest, RegularFilePermissions) {
const std::string node = NewTempAbsPath();
mode_t newUmask = 0077;
umask(newUmask);
// Attempt to open file with mode 0777. Not specifying file type should create
// a regualar file.
mode_t perms = S_IRWXU | S_IRWXG | S_IRWXO;
EXPECT_THAT(mknod(node.c_str(), perms, 0), SyscallSucceeds());
// In the absence of a default ACL, the permissions of the created node are
// (mode & ~umask). -- mknod(2)
mode_t wantPerms = perms & ~newUmask;
struct stat st;
ASSERT_THAT(stat(node.c_str(), &st), SyscallSucceeds());
ASSERT_EQ(st.st_mode & 0777, wantPerms);
// "Zero file type is equivalent to type S_IFREG." - mknod(2)
ASSERT_EQ(st.st_mode & S_IFMT, S_IFREG);
}
TEST(MknodTest, MknodAtFIFO) {
const TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
const std::string fifo_relpath = NewTempRelPath();
const std::string fifo = JoinPath(dir.path(), fifo_relpath);
@@ -72,7 +94,7 @@ TEST(MknodTest, MknodOnExistingPathFails) {
TEST(MknodTest, UnimplementedTypesReturnError) {
const std::string path = NewTempAbsPath();
if (IsRunningOnGvisor()) {
if (IsRunningWithVFS1()) {
ASSERT_THAT(mknod(path.c_str(), S_IFSOCK, 0),
SyscallFailsWithErrno(EOPNOTSUPP));
}