mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Add option to panic gofer if writes are attempted over RO mounts
This is used when '--overlay=true' to guarantee writes are not sent to gofer. PiperOrigin-RevId: 210116288 Change-Id: I7616008c4c0e8d3668e07a205207f46e2144bf30
This commit is contained in:
committed by
Shentubot
parent
64403265a0
commit
a81a4402a2
+6
-1
@@ -38,6 +38,8 @@ type Gofer struct {
|
||||
// controllerFD is the file descriptor of a stream socket for the
|
||||
// control server that is donated to this process.
|
||||
controllerFD int
|
||||
|
||||
panicOnWrite bool
|
||||
}
|
||||
|
||||
// Name implements subcommands.Command.
|
||||
@@ -61,6 +63,7 @@ func (g *Gofer) SetFlags(f *flag.FlagSet) {
|
||||
f.Var(&g.ioFDs, "io-fds", "list of FDs to connect 9P servers. They must follow this order: root first, then mounts as defined in the spec")
|
||||
f.BoolVar(&g.applyCaps, "apply-caps", true, "if true, apply capabilities to restrict what the Gofer process can do")
|
||||
f.IntVar(&g.controllerFD, "controller-fd", -1, "required FD of a stream socket for the control server that must be donated to this process")
|
||||
f.BoolVar(&g.panicOnWrite, "panic-on-write", false, "if true, panics on attempts to write to RO mounts. RW mounts are unnaffected")
|
||||
}
|
||||
|
||||
// Execute implements subcommands.Command.
|
||||
@@ -110,7 +113,8 @@ func (g *Gofer) Execute(_ context.Context, f *flag.FlagSet, args ...interface{})
|
||||
ats := make([]p9.Attacher, 0, len(spec.Mounts)+1)
|
||||
p := absPath(g.bundleDir, spec.Root.Path)
|
||||
ats = append(ats, fsgofer.NewAttachPoint(p, fsgofer.Config{
|
||||
ROMount: spec.Root.Readonly,
|
||||
ROMount: spec.Root.Readonly,
|
||||
PanicOnWrite: g.panicOnWrite,
|
||||
// Docker uses overlay2 by default for the root mount, and overlay2 does a copy-up when
|
||||
// each file is opened as writable. Thus, we open files lazily to avoid copy-up.
|
||||
LazyOpenForWrite: true,
|
||||
@@ -123,6 +127,7 @@ func (g *Gofer) Execute(_ context.Context, f *flag.FlagSet, args ...interface{})
|
||||
p = absPath(g.bundleDir, m.Source)
|
||||
ats = append(ats, fsgofer.NewAttachPoint(p, fsgofer.Config{
|
||||
ROMount: isReadonlyMount(m.Options),
|
||||
PanicOnWrite: g.panicOnWrite,
|
||||
LazyOpenForWrite: false,
|
||||
}))
|
||||
|
||||
|
||||
@@ -76,6 +76,9 @@ type Config struct {
|
||||
// ROMount is set to true if this is a readonly mount.
|
||||
ROMount bool
|
||||
|
||||
// PanicOnWrite panics on attempts to write to RO mounts.
|
||||
PanicOnWrite bool
|
||||
|
||||
// LazyOpenForWrite makes the underlying file to be opened in RDONLY
|
||||
// mode initially and be reopened in case write access is desired.
|
||||
// This is done to workaround the behavior in 'overlay2' that
|
||||
@@ -375,6 +378,9 @@ func (l *localFile) Open(mode p9.OpenFlags) (*fd.FD, p9.QID, uint32, error) {
|
||||
// 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) {
|
||||
if l.conf.ROMount {
|
||||
if l.conf.PanicOnWrite {
|
||||
panic("attempt to write to RO mount")
|
||||
}
|
||||
return nil, nil, p9.QID{}, 0, syscall.EBADF
|
||||
}
|
||||
if !isNameValid(name) {
|
||||
@@ -429,6 +435,9 @@ 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) {
|
||||
if l.conf.ROMount {
|
||||
if l.conf.PanicOnWrite {
|
||||
panic("attempt to write to RO mount")
|
||||
}
|
||||
return p9.QID{}, syscall.EBADF
|
||||
}
|
||||
|
||||
@@ -585,6 +594,9 @@ func (l *localFile) GetAttr(_ p9.AttrMask) (p9.QID, p9.AttrMask, p9.Attr, error)
|
||||
// an error happens.
|
||||
func (l *localFile) SetAttr(valid p9.SetAttrMask, attr p9.SetAttr) error {
|
||||
if l.conf.ROMount {
|
||||
if l.conf.PanicOnWrite {
|
||||
panic("attempt to write to RO mount")
|
||||
}
|
||||
return syscall.EBADF
|
||||
}
|
||||
|
||||
@@ -722,6 +734,9 @@ func (*localFile) Remove() error {
|
||||
// Rename implements p9.File.
|
||||
func (l *localFile) Rename(directory p9.File, name string) error {
|
||||
if l.conf.ROMount {
|
||||
if l.conf.PanicOnWrite {
|
||||
panic("attempt to write to RO mount")
|
||||
}
|
||||
return syscall.EBADF
|
||||
}
|
||||
if !isNameValid(name) {
|
||||
@@ -789,6 +804,9 @@ 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) {
|
||||
if l.conf.ROMount {
|
||||
if l.conf.PanicOnWrite {
|
||||
panic("attempt to write to RO mount")
|
||||
}
|
||||
return p9.QID{}, syscall.EBADF
|
||||
}
|
||||
if !isNameValid(newName) {
|
||||
@@ -819,6 +837,9 @@ 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 {
|
||||
if l.conf.ROMount {
|
||||
if l.conf.PanicOnWrite {
|
||||
panic("attempt to write to RO mount")
|
||||
}
|
||||
return syscall.EBADF
|
||||
}
|
||||
if !isNameValid(newName) {
|
||||
@@ -842,6 +863,9 @@ func (*localFile) Mknod(_ string, _ p9.FileMode, _ uint32, _ uint32, _ p9.UID, _
|
||||
// UnlinkAt implements p9.File.
|
||||
func (l *localFile) UnlinkAt(name string, flags uint32) error {
|
||||
if l.conf.ROMount {
|
||||
if l.conf.PanicOnWrite {
|
||||
panic("attempt to write to RO mount")
|
||||
}
|
||||
return syscall.EBADF
|
||||
}
|
||||
if !isNameValid(name) {
|
||||
|
||||
@@ -34,6 +34,15 @@ func init() {
|
||||
allConfs = append(allConfs, roConfs...)
|
||||
}
|
||||
|
||||
func assertPanic(t *testing.T, f func()) {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Errorf("function did not panic")
|
||||
}
|
||||
}()
|
||||
f()
|
||||
}
|
||||
|
||||
var (
|
||||
allTypes = []fileType{regular, directory, symlink}
|
||||
|
||||
@@ -434,6 +443,22 @@ 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) {
|
||||
assertPanic(t, func() { s.file.Create("..", p9.ReadWrite, 0777, p9.UID(os.Getuid()), p9.GID(os.Getgid())) })
|
||||
assertPanic(t, func() { s.file.Mkdir("..", 0777, p9.UID(os.Getuid()), p9.GID(os.Getgid())) })
|
||||
assertPanic(t, func() { s.file.Rename(s.file, "..") })
|
||||
assertPanic(t, func() { s.file.Symlink("some_place", "..", p9.UID(os.Getuid()), p9.GID(os.Getgid())) })
|
||||
assertPanic(t, func() { s.file.UnlinkAt("..", 0) })
|
||||
assertPanic(t, func() { s.file.Link(s.file, "..") })
|
||||
|
||||
valid := p9.SetAttrMask{Size: true}
|
||||
attr := p9.SetAttr{Size: 0}
|
||||
assertPanic(t, func() { s.file.SetAttr(valid, attr) })
|
||||
})
|
||||
}
|
||||
|
||||
func TestInvalidName(t *testing.T) {
|
||||
runCustom(t, []fileType{regular}, rwConfs, func(t *testing.T, s state) {
|
||||
if _, _, _, _, err := s.file.Create("..", p9.ReadWrite, 0777, p9.UID(os.Getuid()), p9.GID(os.Getgid())); err != syscall.EINVAL {
|
||||
|
||||
@@ -345,6 +345,10 @@ func (s *Sandbox) createGoferProcess(spec *specs.Spec, conf *boot.Config, bundle
|
||||
setUIDGIDMappings(cmd, spec)
|
||||
nss := filterNS([]specs.LinuxNamespaceType{specs.UserNamespace}, spec)
|
||||
|
||||
if conf.Overlay {
|
||||
args = append(args, "--panic-on-write=true")
|
||||
}
|
||||
|
||||
// Start the gofer in the given namespace.
|
||||
log.Debugf("Starting gofer: %s %v", binPath, args)
|
||||
if err := startInNS(cmd, nss); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user