mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Return EROFS if mount is read-only
PiperOrigin-RevId: 327300635
This commit is contained in:
committed by
gVisor bot
parent
4141dc0d2c
commit
760c131da1
+47
-57
@@ -46,6 +46,8 @@ const (
|
||||
invalidMode = p9.OpenFlags(math.MaxUint32)
|
||||
|
||||
openFlags = syscall.O_NOFOLLOW | syscall.O_CLOEXEC
|
||||
|
||||
allowedOpenFlags = unix.O_TRUNC
|
||||
)
|
||||
|
||||
// Config sets configuration options for each attach point.
|
||||
@@ -357,10 +359,16 @@ func (l *localFile) Open(flags p9.OpenFlags) (*fd.FD, p9.QID, uint32, error) {
|
||||
if l.isOpen() {
|
||||
panic(fmt.Sprintf("attempting to open already opened file: %q", l.hostPath))
|
||||
}
|
||||
mode := flags & p9.OpenFlagsModeMask
|
||||
if mode == p9.WriteOnly || mode == p9.ReadWrite || flags&p9.OpenTruncate != 0 {
|
||||
if err := l.checkROMount(); err != nil {
|
||||
return nil, p9.QID{}, 0, err
|
||||
}
|
||||
}
|
||||
|
||||
// Check if control file can be used or if a new open must be created.
|
||||
var newFile *fd.FD
|
||||
if flags == p9.ReadOnly && l.controlReadable {
|
||||
if mode == p9.ReadOnly && l.controlReadable && flags.OSFlags()&allowedOpenFlags == 0 {
|
||||
log.Debugf("Open reusing control file, flags: %v, %q", flags, l.hostPath)
|
||||
newFile = l.file
|
||||
} else {
|
||||
@@ -369,8 +377,8 @@ func (l *localFile) Open(flags p9.OpenFlags) (*fd.FD, p9.QID, uint32, error) {
|
||||
// name_to_handle_at and open_by_handle_at aren't supported by overlay2.
|
||||
log.Debugf("Open reopening file, flags: %v, %q", flags, l.hostPath)
|
||||
var err error
|
||||
// Constrain open flags to the open mode and O_TRUNC.
|
||||
newFile, err = reopenProcFd(l.file, openFlags|(flags.OSFlags()&(syscall.O_ACCMODE|syscall.O_TRUNC)))
|
||||
osFlags := flags.OSFlags() & (syscall.O_ACCMODE | allowedOpenFlags)
|
||||
newFile, err = reopenProcFd(l.file, openFlags|osFlags)
|
||||
if err != nil {
|
||||
return nil, p9.QID{}, 0, extractErrno(err)
|
||||
}
|
||||
@@ -389,31 +397,31 @@ func (l *localFile) Open(flags p9.OpenFlags) (*fd.FD, p9.QID, uint32, error) {
|
||||
}
|
||||
l.file = newFile
|
||||
}
|
||||
l.mode = flags & p9.OpenFlagsModeMask
|
||||
l.mode = mode
|
||||
return fd, l.qid, 0, nil
|
||||
}
|
||||
|
||||
// Create implements p9.File.
|
||||
func (l *localFile) Create(name string, mode p9.OpenFlags, perm p9.FileMode, uid p9.UID, gid p9.GID) (*fd.FD, p9.File, p9.QID, uint32, error) {
|
||||
conf := l.attachPoint.conf
|
||||
if conf.ROMount {
|
||||
if conf.PanicOnWrite {
|
||||
panic("attempt to write to RO mount")
|
||||
}
|
||||
return nil, nil, p9.QID{}, 0, syscall.EBADF
|
||||
func (l *localFile) Create(name string, p9Flags p9.OpenFlags, perm p9.FileMode, uid p9.UID, gid p9.GID) (*fd.FD, p9.File, p9.QID, uint32, error) {
|
||||
if err := l.checkROMount(); err != nil {
|
||||
return nil, nil, p9.QID{}, 0, err
|
||||
}
|
||||
|
||||
// Set file creation flags, plus allowed open flags from caller.
|
||||
osFlags := openFlags | syscall.O_CREAT | syscall.O_EXCL
|
||||
osFlags |= p9Flags.OSFlags() & allowedOpenFlags
|
||||
|
||||
// 'file' may be used for other operations (e.g. Walk), so read access is
|
||||
// always added to flags. Note that resulting file might have a wider mode
|
||||
// than needed for each particular case.
|
||||
flags := openFlags | syscall.O_CREAT | syscall.O_EXCL
|
||||
mode := p9Flags & p9.OpenFlagsModeMask
|
||||
if mode == p9.WriteOnly {
|
||||
flags |= syscall.O_RDWR
|
||||
osFlags |= syscall.O_RDWR
|
||||
} else {
|
||||
flags |= mode.OSFlags()
|
||||
osFlags |= mode.OSFlags() & unix.O_ACCMODE
|
||||
}
|
||||
|
||||
child, err := fd.OpenAt(l.file, name, flags, uint32(perm.Permissions()))
|
||||
child, err := fd.OpenAt(l.file, name, osFlags, uint32(perm.Permissions()))
|
||||
if err != nil {
|
||||
return nil, nil, p9.QID{}, 0, extractErrno(err)
|
||||
}
|
||||
@@ -449,12 +457,8 @@ func (l *localFile) Create(name string, mode p9.OpenFlags, perm p9.FileMode, uid
|
||||
|
||||
// Mkdir implements p9.File.
|
||||
func (l *localFile) Mkdir(name string, perm p9.FileMode, 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.EBADF
|
||||
if err := l.checkROMount(); err != nil {
|
||||
return p9.QID{}, err
|
||||
}
|
||||
|
||||
if err := syscall.Mkdirat(l.file.FD(), name, uint32(perm.Permissions())); err != nil {
|
||||
@@ -637,12 +641,8 @@ func (l *localFile) fillAttr(stat syscall.Stat_t) (p9.AttrMask, p9.Attr) {
|
||||
// cannot be changed atomically and user may see partial changes when
|
||||
// an error happens.
|
||||
func (l *localFile) SetAttr(valid p9.SetAttrMask, attr p9.SetAttr) error {
|
||||
conf := l.attachPoint.conf
|
||||
if conf.ROMount {
|
||||
if conf.PanicOnWrite {
|
||||
panic("attempt to write to RO mount")
|
||||
}
|
||||
return syscall.EBADF
|
||||
if err := l.checkROMount(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
allowed := p9.SetAttrMask{
|
||||
@@ -804,12 +804,8 @@ func (*localFile) Rename(p9.File, string) error {
|
||||
|
||||
// RenameAt implements p9.File.RenameAt.
|
||||
func (l *localFile) RenameAt(oldName string, directory p9.File, newName string) error {
|
||||
conf := l.attachPoint.conf
|
||||
if conf.ROMount {
|
||||
if conf.PanicOnWrite {
|
||||
panic("attempt to write to RO mount")
|
||||
}
|
||||
return syscall.EBADF
|
||||
if err := l.checkROMount(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newParent := directory.(*localFile)
|
||||
@@ -855,12 +851,8 @@ func (l *localFile) WriteAt(p []byte, offset uint64) (int, error) {
|
||||
|
||||
// Symlink implements p9.File.
|
||||
func (l *localFile) Symlink(target, newName string, 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.EBADF
|
||||
if err := l.checkROMount(); err != nil {
|
||||
return p9.QID{}, err
|
||||
}
|
||||
|
||||
if err := unix.Symlinkat(target, l.file.FD(), newName); err != nil {
|
||||
@@ -895,12 +887,8 @@ func (l *localFile) Symlink(target, newName string, uid p9.UID, gid p9.GID) (p9.
|
||||
|
||||
// Link implements p9.File.
|
||||
func (l *localFile) Link(target p9.File, newName string) error {
|
||||
conf := l.attachPoint.conf
|
||||
if conf.ROMount {
|
||||
if conf.PanicOnWrite {
|
||||
panic("attempt to write to RO mount")
|
||||
}
|
||||
return syscall.EBADF
|
||||
if err := l.checkROMount(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
targetFile := target.(*localFile)
|
||||
@@ -912,12 +900,8 @@ func (l *localFile) Link(target p9.File, newName string) error {
|
||||
|
||||
// Mknod implements p9.File.
|
||||
func (l *localFile) Mknod(name string, mode p9.FileMode, _ uint32, _ uint32, _ p9.UID, _ 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
|
||||
if err := l.checkROMount(); err != nil {
|
||||
return p9.QID{}, err
|
||||
}
|
||||
|
||||
hostPath := path.Join(l.hostPath, name)
|
||||
@@ -948,12 +932,8 @@ func (l *localFile) Mknod(name string, mode p9.FileMode, _ uint32, _ uint32, _ p
|
||||
|
||||
// UnlinkAt implements p9.File.
|
||||
func (l *localFile) UnlinkAt(name string, flags uint32) error {
|
||||
conf := l.attachPoint.conf
|
||||
if conf.ROMount {
|
||||
if conf.PanicOnWrite {
|
||||
panic("attempt to write to RO mount")
|
||||
}
|
||||
return syscall.EBADF
|
||||
if err := l.checkROMount(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := unix.Unlinkat(l.file.FD(), name, int(flags)); err != nil {
|
||||
@@ -1178,3 +1158,13 @@ func extractErrno(err error) syscall.Errno {
|
||||
log.Debugf("Unknown error: %v, defaulting to EIO", err)
|
||||
return syscall.EIO
|
||||
}
|
||||
|
||||
func (l *localFile) checkROMount() error {
|
||||
if conf := l.attachPoint.conf; conf.ROMount {
|
||||
if conf.PanicOnWrite {
|
||||
panic("attempt to write to RO mount")
|
||||
}
|
||||
return syscall.EROFS
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -491,30 +491,50 @@ func TestLink(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestROMountChecks(t *testing.T) {
|
||||
const want = syscall.EROFS
|
||||
runCustom(t, allTypes, roConfs, func(t *testing.T, s state) {
|
||||
if _, _, _, _, err := s.file.Create("some_file", p9.ReadWrite, 0777, p9.UID(os.Getuid()), p9.GID(os.Getgid())); err != syscall.EBADF {
|
||||
t.Errorf("%v: Create() should have failed, got: %v, expected: syscall.EBADF", s, err)
|
||||
if s.fileType != syscall.S_IFLNK {
|
||||
if _, _, _, err := s.file.Open(p9.WriteOnly); err != want {
|
||||
t.Errorf("Open() should have failed, got: %v, expected: %v", err, want)
|
||||
}
|
||||
if _, _, _, err := s.file.Open(p9.ReadWrite); err != want {
|
||||
t.Errorf("Open() should have failed, got: %v, expected: %v", err, want)
|
||||
}
|
||||
if _, _, _, err := s.file.Open(p9.ReadOnly | p9.OpenTruncate); err != want {
|
||||
t.Errorf("Open() should have failed, got: %v, expected: %v", err, want)
|
||||
}
|
||||
f, _, _, err := s.file.Open(p9.ReadOnly)
|
||||
if err != nil {
|
||||
t.Errorf("Open() failed: %v", err)
|
||||
}
|
||||
if f != nil {
|
||||
_ = f.Close()
|
||||
}
|
||||
}
|
||||
if _, err := s.file.Mkdir("some_dir", 0777, p9.UID(os.Getuid()), p9.GID(os.Getgid())); err != syscall.EBADF {
|
||||
t.Errorf("%v: MkDir() should have failed, got: %v, expected: syscall.EBADF", s, err)
|
||||
|
||||
if _, _, _, _, err := s.file.Create("some_file", p9.ReadWrite, 0777, p9.UID(os.Getuid()), p9.GID(os.Getgid())); err != want {
|
||||
t.Errorf("Create() should have failed, got: %v, expected: %v", err, want)
|
||||
}
|
||||
if err := s.file.RenameAt("some_file", s.file, "other_file"); err != syscall.EBADF {
|
||||
t.Errorf("%v: Rename() should have failed, got: %v, expected: syscall.EBADF", s, err)
|
||||
if _, err := s.file.Mkdir("some_dir", 0777, p9.UID(os.Getuid()), p9.GID(os.Getgid())); err != want {
|
||||
t.Errorf("MkDir() should have failed, got: %v, expected: %v", err, want)
|
||||
}
|
||||
if _, err := s.file.Symlink("some_place", "some_symlink", p9.UID(os.Getuid()), p9.GID(os.Getgid())); err != syscall.EBADF {
|
||||
t.Errorf("%v: Symlink() should have failed, got: %v, expected: syscall.EBADF", s, err)
|
||||
if err := s.file.RenameAt("some_file", s.file, "other_file"); err != want {
|
||||
t.Errorf("Rename() should have failed, got: %v, expected: %v", err, want)
|
||||
}
|
||||
if err := s.file.UnlinkAt("some_file", 0); err != syscall.EBADF {
|
||||
t.Errorf("%v: UnlinkAt() should have failed, got: %v, expected: syscall.EBADF", s, err)
|
||||
if _, err := s.file.Symlink("some_place", "some_symlink", p9.UID(os.Getuid()), p9.GID(os.Getgid())); err != want {
|
||||
t.Errorf("Symlink() should have failed, got: %v, expected: %v", err, want)
|
||||
}
|
||||
if err := s.file.Link(s.file, "some_link"); err != syscall.EBADF {
|
||||
t.Errorf("%v: Link() should have failed, got: %v, expected: syscall.EBADF", s, err)
|
||||
if err := s.file.UnlinkAt("some_file", 0); err != want {
|
||||
t.Errorf("UnlinkAt() should have failed, got: %v, expected: %v", err, want)
|
||||
}
|
||||
if err := s.file.Link(s.file, "some_link"); err != want {
|
||||
t.Errorf("Link() should have failed, got: %v, expected: %v", err, want)
|
||||
}
|
||||
|
||||
valid := p9.SetAttrMask{Size: true}
|
||||
attr := p9.SetAttr{Size: 0}
|
||||
if err := s.file.SetAttr(valid, attr); err != syscall.EBADF {
|
||||
t.Errorf("%v: SetAttr() should have failed, got: %v, expected: syscall.EBADF", s, err)
|
||||
if err := s.file.SetAttr(valid, attr); err != want {
|
||||
t.Errorf("SetAttr() should have failed, got: %v, expected: %v", err, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -522,6 +542,9 @@ func TestROMountChecks(t *testing.T) {
|
||||
func TestROMountPanics(t *testing.T) {
|
||||
conf := Config{ROMount: true, PanicOnWrite: true}
|
||||
runCustom(t, allTypes, []Config{conf}, func(t *testing.T, s state) {
|
||||
if s.fileType != syscall.S_IFLNK {
|
||||
assertPanic(t, func() { s.file.Open(p9.WriteOnly) })
|
||||
}
|
||||
assertPanic(t, func() { s.file.Create("some_file", p9.ReadWrite, 0777, p9.UID(os.Getuid()), p9.GID(os.Getgid())) })
|
||||
assertPanic(t, func() { s.file.Mkdir("some_dir", 0777, p9.UID(os.Getuid()), p9.GID(os.Getgid())) })
|
||||
assertPanic(t, func() { s.file.RenameAt("some_file", s.file, "other_file") })
|
||||
@@ -741,3 +764,36 @@ func TestDoubleAttachError(t *testing.T) {
|
||||
t.Fatalf("Attach should have failed, got %v want non-nil", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTruncate(t *testing.T) {
|
||||
runCustom(t, []uint32{syscall.S_IFDIR}, rwConfs, func(t *testing.T, s state) {
|
||||
child, err := createFile(s.file, "test")
|
||||
if err != nil {
|
||||
t.Fatalf("createFile() failed, err: %v", err)
|
||||
}
|
||||
defer child.Close()
|
||||
want := []byte("foobar")
|
||||
w, err := child.WriteAt(want, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("Write() failed, err: %v", err)
|
||||
}
|
||||
if w != len(want) {
|
||||
t.Fatalf("Write() was partial, got: %d, expected: %d", w, len(want))
|
||||
}
|
||||
|
||||
_, l, err := s.file.Walk([]string{"test"})
|
||||
if err != nil {
|
||||
t.Fatalf("Walk(%s) failed, err: %v", "test", err)
|
||||
}
|
||||
if _, _, _, err := l.Open(p9.ReadOnly | p9.OpenTruncate); err != nil {
|
||||
t.Fatalf("Open() failed, err: %v", err)
|
||||
}
|
||||
_, mask, attr, err := l.GetAttr(p9.AttrMask{Size: true})
|
||||
if !mask.Size {
|
||||
t.Fatalf("GetAttr() didn't return size: %+v", mask)
|
||||
}
|
||||
if attr.Size != 0 {
|
||||
t.Fatalf("truncate didn't work, want: 0, got: %d", attr.Size)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user