Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions pkg/abi/linux/xattr.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@

package linux

import (
"encoding/binary"
"structs"
)

// Constants for extended attributes.
const (
XATTR_NAME_MAX = 255
Expand All @@ -37,3 +42,112 @@ const (
XATTR_USER_PREFIX = "user."
XATTR_USER_PREFIX_LEN = len(XATTR_USER_PREFIX)
)

// Constants for POSIX ACL extended attributes.
const (
// Extended attribute names for POSIX ACLs.
XATTR_NAME_POSIX_ACL_ACCESS = XATTR_SYSTEM_PREFIX + "posix_acl_access"
XATTR_NAME_POSIX_ACL_DEFAULT = XATTR_SYSTEM_PREFIX + "posix_acl_default"

POSIX_ACL_XATTR_VERSION = 2

// ACL_UNDEFINED_ID is the ID for entries that do not contain a
// named user or group.
ACL_UNDEFINED_ID = 0xffffffff

// ACL entry tags.
ACL_USER_OBJ = 0x01
ACL_USER = 0x02
ACL_GROUP_OBJ = 0x04
ACL_GROUP = 0x08
ACL_MASK = 0x10
ACL_OTHER = 0x20

// ACL entry permission bits.
ACL_READ = 0x04
ACL_WRITE = 0x02
ACL_EXECUTE = 0x01
)

// PosixACLXattrEntry is a single entry in the userspace representation
// of a POSIX ACL. It corresponds to Linux's struct posix_acl_xattr_entry.
//
// All fields in PosixACLXattrEntry are stored as little-endian.
//
// +marshal dynamic
type PosixACLXattrEntry struct {
_ structs.HostLayout
Tag uint16
Perm uint16
ID uint32
}

// SizeBytes implements marshal.Marshallable.SizeBytes.
func (a *PosixACLXattrEntry) SizeBytes() int {
return 8
}

// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (a *PosixACLXattrEntry) MarshalBytes(dst []byte) []byte {
binary.LittleEndian.PutUint16(dst[0:], a.Tag)
binary.LittleEndian.PutUint16(dst[2:], a.Perm)
binary.LittleEndian.PutUint32(dst[4:], a.ID)

return dst[8:]
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (a *PosixACLXattrEntry) UnmarshalBytes(src []byte) []byte {
a.Tag = binary.LittleEndian.Uint16(src[0:])
a.Perm = binary.LittleEndian.Uint16(src[2:])
a.ID = binary.LittleEndian.Uint32(src[4:])

return src[8:]
}

// PosixACLXattr is the userspace representation of a POSIX ACL.
//
// +marshal dynamic
type PosixACLXattr struct {
_ structs.HostLayout

// Version is the POSIX ACL version, stored as little-endian.
Version uint32

// Entries contains the ACL entries.
Entries []PosixACLXattrEntry `hostlayout:"ignore"`
}

// posixACLXattrHeaderSize is the size in bytes of the header.
const posixACLXattrHeaderSize = 4

// SizeBytes implements marshal.Marshallable.SizeBytes.
func (a *PosixACLXattr) SizeBytes() int {
return posixACLXattrHeaderSize + len(a.Entries)*(*PosixACLXattrEntry)(nil).SizeBytes()
}

// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (a *PosixACLXattr) MarshalBytes(dst []byte) []byte {
binary.LittleEndian.PutUint32(dst, a.Version)

dst = dst[posixACLXattrHeaderSize:]
for _, entry := range a.Entries {
dst = entry.MarshalBytes(dst)
}

return dst
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (a *PosixACLXattr) UnmarshalBytes(src []byte) []byte {
a.Version = binary.LittleEndian.Uint32(src)

src = src[posixACLXattrHeaderSize:]
for len(src) >= (*PosixACLXattrEntry)(nil).SizeBytes() {
var entry PosixACLXattrEntry
src = entry.UnmarshalBytes(src)
a.Entries = append(a.Entries, entry)
}

return src
}
2 changes: 1 addition & 1 deletion pkg/sentry/fsimpl/erofs/erofs.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ func (i *inode) DecRef(ctx context.Context) {
}

func (i *inode) checkPermissions(creds *auth.Credentials, ats vfs.AccessTypes) error {
return vfs.GenericCheckPermissions(creds, ats, linux.FileMode(i.Mode()), auth.KUID(i.UID()), auth.KGID(i.GID()))
return vfs.GenericCheckPermissions(creds, ats, linux.FileMode(i.Mode()), nil, auth.KUID(i.UID()), auth.KGID(i.GID()))
}

func (i *inode) statTo(stat *linux.Statx) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/sentry/fsimpl/fuse/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ func (fd *fileDescription) SetStat(ctx context.Context, opts vfs.SetStatOptions)
inode := fd.inode()
inode.attrMu.Lock()
defer inode.attrMu.Unlock()
if err := vfs.CheckSetStat(ctx, creds, &opts, inode.filemode(), auth.KUID(inode.uid.Load()), auth.KGID(inode.gid.Load())); err != nil {
if err := vfs.CheckSetStat(ctx, creds, &opts, inode.filemode(), nil, auth.KUID(inode.uid.Load()), auth.KGID(inode.gid.Load())); err != nil {
return err
}
return inode.setAttr(ctx, fs, creds, opts, fhOptions{useFh: true, fh: fd.Fh})
Expand Down
6 changes: 3 additions & 3 deletions pkg/sentry/fsimpl/fuse/inode.go
Original file line number Diff line number Diff line change
Expand Up @@ -476,12 +476,12 @@ func (i *inode) CheckPermissions(ctx context.Context, creds *auth.Credentials, a
}

if i.fs.opts.defaultPermissions || (ats.MayExec() && i.filemode().FileType() == linux.S_IFREG) {
err := vfs.GenericCheckPermissions(creds, ats, linux.FileMode(i.mode.Load()), auth.KUID(i.uid.Load()), auth.KGID(i.gid.Load()))
err := vfs.GenericCheckPermissions(creds, ats, linux.FileMode(i.mode.Load()), nil, auth.KUID(i.uid.Load()), auth.KGID(i.gid.Load()))
if linuxerr.Equals(linuxerr.EACCES, err) && !refreshed {
if _, err := i.getAttr(ctx, creds, i.fs.VFSFilesystem(), opts, 0, 0); err != nil {
return err
}
return vfs.GenericCheckPermissions(creds, ats, linux.FileMode(i.mode.Load()), auth.KUID(i.uid.Load()), auth.KGID(i.gid.Load()))
return vfs.GenericCheckPermissions(creds, ats, linux.FileMode(i.mode.Load()), nil, auth.KUID(i.uid.Load()), auth.KGID(i.gid.Load()))
}
return err
}
Expand Down Expand Up @@ -854,7 +854,7 @@ func (i *inode) SetStat(ctx context.Context, fs *vfs.Filesystem, creds *auth.Cre

i.attrMu.Lock()
defer i.attrMu.Unlock()
if err := vfs.CheckSetStat(ctx, creds, &opts, i.filemode(), auth.KUID(i.uid.Load()), auth.KGID(i.gid.Load())); err != nil {
if err := vfs.CheckSetStat(ctx, creds, &opts, i.filemode(), nil, auth.KUID(i.uid.Load()), auth.KGID(i.gid.Load())); err != nil {
return err
}
if opts.Stat.Mask == 0 {
Expand Down
3 changes: 2 additions & 1 deletion pkg/sentry/fsimpl/gofer/filesystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"sync"

"golang.org/x/sys/unix"

"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/atomicbitops"
"gvisor.dev/gvisor/pkg/context"
Expand Down Expand Up @@ -828,7 +829,7 @@ func (fs *filesystem) LinkAt(ctx context.Context, rp *vfs.ResolvingPath, vd vfs.
gid := auth.KGID(d.inode.gid.Load())
uid := auth.KUID(d.inode.uid.Load())
mode := linux.FileMode(d.inode.mode.Load())
if err := vfs.MayLink(rp.Credentials(), mode, uid, gid); err != nil {
if err := vfs.MayLink(rp.Credentials(), mode, nil, uid, gid); err != nil {
return nil, err
}
if d.inode.nlink.Load() == 0 {
Expand Down
7 changes: 4 additions & 3 deletions pkg/sentry/fsimpl/gofer/gofer.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import (
"sync/atomic"

"golang.org/x/sys/unix"

"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/atomicbitops"
"gvisor.dev/gvisor/pkg/cleanup"
Expand Down Expand Up @@ -1292,7 +1293,7 @@ func (d *dentry) setStat(ctx context.Context, creds *auth.Credentials, opts *vfs
return linuxerr.EPERM
}
mode := linux.FileMode(d.inode.mode.Load())
if err := vfs.CheckSetStat(ctx, creds, opts, mode, auth.KUID(d.inode.uid.Load()), auth.KGID(d.inode.gid.Load())); err != nil {
if err := vfs.CheckSetStat(ctx, creds, opts, mode, nil, auth.KUID(d.inode.uid.Load()), auth.KGID(d.inode.gid.Load())); err != nil {
return err
}
if err := mnt.CheckBeginWrite(); err != nil {
Expand Down Expand Up @@ -1505,7 +1506,7 @@ func (i *inode) updateSizeAndUnlockDataMuLocked(newSize uint64) {
}

func (d *dentry) checkPermissions(creds *auth.Credentials, ats vfs.AccessTypes) error {
return vfs.GenericCheckPermissions(creds, ats, linux.FileMode(d.inode.mode.Load()), auth.KUID(d.inode.uid.Load()), auth.KGID(d.inode.gid.Load()))
return vfs.GenericCheckPermissions(creds, ats, linux.FileMode(d.inode.mode.Load()), nil, auth.KUID(d.inode.uid.Load()), auth.KGID(d.inode.gid.Load()))
}

// Preconditions: d.inode.metadataMu must be locked.
Expand All @@ -1529,7 +1530,7 @@ func (d *dentry) checkXattrPermissions(creds *auth.Credentials, name string, ats
mode := linux.FileMode(d.inode.mode.RacyLoad())
kuid := auth.KUID(d.inode.uid.RacyLoad())
kgid := auth.KGID(d.inode.gid.RacyLoad())
if err := vfs.GenericCheckPermissions(creds, ats, mode, kuid, kgid); err != nil {
if err := vfs.GenericCheckPermissions(creds, ats, mode, nil, kuid, kgid); err != nil {
return err
}
return vfs.CheckXattrPermissions(creds, ats, mode, kuid, name)
Expand Down
5 changes: 3 additions & 2 deletions pkg/sentry/fsimpl/host/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"math"

"golang.org/x/sys/unix"

"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/atomicbitops"
"gvisor.dev/gvisor/pkg/context"
Expand Down Expand Up @@ -412,7 +413,7 @@ func (i *inode) CheckPermissions(ctx context.Context, creds *auth.Credentials, a
if err := i.stat(&s); err != nil {
return err
}
return vfs.GenericCheckPermissions(creds, ats, linux.FileMode(s.Mode), auth.KUID(s.Uid), auth.KGID(s.Gid))
return vfs.GenericCheckPermissions(creds, ats, linux.FileMode(s.Mode), nil, auth.KUID(s.Uid), auth.KGID(s.Gid))
}

// Mode implements kernfs.Inode.Mode.
Expand Down Expand Up @@ -607,7 +608,7 @@ func (i *inode) SetStat(ctx context.Context, fs *vfs.Filesystem, creds *auth.Cre
if err := i.stat(&hostStat); err != nil {
return err
}
if err := vfs.CheckSetStat(ctx, creds, &opts, linux.FileMode(hostStat.Mode), auth.KUID(hostStat.Uid), auth.KGID(hostStat.Gid)); err != nil {
if err := vfs.CheckSetStat(ctx, creds, &opts, linux.FileMode(hostStat.Mode), nil, auth.KUID(hostStat.Uid), auth.KGID(hostStat.Gid)); err != nil {
return err
}

Expand Down
8 changes: 4 additions & 4 deletions pkg/sentry/fsimpl/kernfs/filesystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ func (fs *Filesystem) LinkAt(ctx context.Context, rp *vfs.ResolvingPath, vd vfs.
if inode.Mode().IsDir() {
return linuxerr.EPERM
}
if err := vfs.MayLink(rp.Credentials(), inode.Mode(), inode.UID(), inode.GID()); err != nil {
if err := vfs.MayLink(rp.Credentials(), inode.Mode(), nil, inode.UID(), inode.GID()); err != nil {
return err
}
parent.dirMu.Lock()
Expand Down Expand Up @@ -1129,7 +1129,7 @@ func (fs *Filesystem) GetXattrAt(ctx context.Context, rp *vfs.ResolvingPath, opt
mode := d.inode.Mode()
kuid := d.inode.UID()
kgid := d.inode.GID()
if err := vfs.GenericCheckPermissions(creds, vfs.MayRead, mode, kuid, kgid); err != nil {
if err := vfs.GenericCheckPermissions(creds, vfs.MayRead, mode, nil, kuid, kgid); err != nil {
return "", err
}
if err := vfs.CheckXattrPermissions(creds, vfs.MayRead, mode, kuid, opts.Name); err != nil {
Expand All @@ -1155,7 +1155,7 @@ func (fs *Filesystem) SetXattrAt(ctx context.Context, rp *vfs.ResolvingPath, opt
mode := d.inode.Mode()
kuid := d.inode.UID()
kgid := d.inode.GID()
if err := vfs.GenericCheckPermissions(creds, vfs.MayWrite, mode, kuid, kgid); err != nil {
if err := vfs.GenericCheckPermissions(creds, vfs.MayWrite, mode, nil, kuid, kgid); err != nil {
return err
}
if err := vfs.CheckXattrPermissions(creds, vfs.MayWrite, mode, kuid, opts.Name); err != nil {
Expand All @@ -1181,7 +1181,7 @@ func (fs *Filesystem) RemoveXattrAt(ctx context.Context, rp *vfs.ResolvingPath,
mode := d.inode.Mode()
kuid := d.inode.UID()
kgid := d.inode.GID()
if err := vfs.GenericCheckPermissions(creds, vfs.MayWrite, mode, kuid, kgid); err != nil {
if err := vfs.GenericCheckPermissions(creds, vfs.MayWrite, mode, nil, kuid, kgid); err != nil {
return err
}
if err := vfs.CheckXattrPermissions(creds, vfs.MayWrite, mode, kuid, name); err != nil {
Expand Down
3 changes: 2 additions & 1 deletion pkg/sentry/fsimpl/kernfs/inode_impl_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ func (a *InodeAttrs) SetStat(ctx context.Context, fs *vfs.Filesystem, creds *aut
if opts.Stat.Mask&linux.STATX_SIZE != 0 && a.Mode().IsDir() {
return linuxerr.EISDIR
}
if err := vfs.CheckSetStat(ctx, creds, &opts, a.Mode(), auth.KUID(a.uid.Load()), auth.KGID(a.gid.Load())); err != nil {
if err := vfs.CheckSetStat(ctx, creds, &opts, a.Mode(), nil, auth.KUID(a.uid.Load()), auth.KGID(a.gid.Load())); err != nil {
return err
}

Expand Down Expand Up @@ -373,6 +373,7 @@ func (a *InodeAttrs) CheckPermissions(_ context.Context, creds *auth.Credentials
creds,
ats,
a.Mode(),
nil,
auth.KUID(a.uid.Load()),
auth.KGID(a.gid.Load()),
)
Expand Down
2 changes: 1 addition & 1 deletion pkg/sentry/fsimpl/overlay/filesystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -1500,7 +1500,7 @@ func (fs *filesystem) SetStatAt(ctx context.Context, rp *vfs.ResolvingPath, opts
// Precondition: d.fs.renameMu must be held for reading.
func (d *dentry) setStatLocked(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.SetStatOptions) error {
mode := linux.FileMode(d.mode.Load())
if err := vfs.CheckSetStat(ctx, rp.Credentials(), &opts, mode, auth.KUID(d.uid.Load()), auth.KGID(d.gid.Load())); err != nil {
if err := vfs.CheckSetStat(ctx, rp.Credentials(), &opts, mode, nil, auth.KUID(d.uid.Load()), auth.KGID(d.gid.Load())); err != nil {
return err
}
mnt := rp.Mount()
Expand Down
4 changes: 2 additions & 2 deletions pkg/sentry/fsimpl/overlay/overlay.go
Original file line number Diff line number Diff line change
Expand Up @@ -872,14 +872,14 @@ func (d *dentry) topLookupLayer() lookupLayer {
}

func (d *dentry) checkPermissions(creds *auth.Credentials, ats vfs.AccessTypes) error {
return vfs.GenericCheckPermissions(creds, ats, linux.FileMode(d.mode.Load()), auth.KUID(d.uid.Load()), auth.KGID(d.gid.Load()))
return vfs.GenericCheckPermissions(creds, ats, linux.FileMode(d.mode.Load()), nil, auth.KUID(d.uid.Load()), auth.KGID(d.gid.Load()))
}

func (d *dentry) checkXattrPermissions(creds *auth.Credentials, name string, ats vfs.AccessTypes) error {
mode := linux.FileMode(d.mode.Load())
kuid := auth.KUID(d.uid.Load())
kgid := auth.KGID(d.gid.Load())
if err := vfs.GenericCheckPermissions(creds, ats, mode, kuid, kgid); err != nil {
if err := vfs.GenericCheckPermissions(creds, ats, mode, nil, kuid, kgid); err != nil {
return err
}
return vfs.CheckXattrPermissions(creds, ats, mode, kuid, name)
Expand Down
2 changes: 1 addition & 1 deletion pkg/sentry/fsimpl/overlay/regular_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ func (fd *regularFileFD) Allocate(ctx context.Context, mode, offset, length uint
func (fd *regularFileFD) SetStat(ctx context.Context, opts vfs.SetStatOptions) error {
d := fd.dentry()
mode := linux.FileMode(d.mode.Load())
if err := vfs.CheckSetStat(ctx, auth.CredentialsFromContext(ctx), &opts, mode, auth.KUID(d.uid.Load()), auth.KGID(d.gid.Load())); err != nil {
if err := vfs.CheckSetStat(ctx, auth.CredentialsFromContext(ctx), &opts, mode, nil, auth.KUID(d.uid.Load()), auth.KGID(d.gid.Load())); err != nil {
return err
}
mnt := fd.vfsfd.Mount()
Expand Down
4 changes: 2 additions & 2 deletions pkg/sentry/fsimpl/pipefs/pipefs.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ const pipeMode = 0600 | linux.S_IFIFO
func (i *inode) CheckPermissions(ctx context.Context, creds *auth.Credentials, ats vfs.AccessTypes) error {
i.attrMu.Lock()
defer i.attrMu.Unlock()
return vfs.GenericCheckPermissions(creds, ats, pipeMode, i.uid, i.gid)
return vfs.GenericCheckPermissions(creds, ats, pipeMode, nil, i.uid, i.gid)
}

// Mode implements kernfs.Inode.Mode.
Expand Down Expand Up @@ -177,7 +177,7 @@ func (i *inode) SetStat(ctx context.Context, vfsfs *vfs.Filesystem, creds *auth.
}
i.attrMu.Lock()
defer i.attrMu.Unlock()
if err := vfs.CheckSetStat(ctx, creds, &opts, pipeMode, auth.KUID(i.uid), auth.KGID(i.gid)); err != nil {
if err := vfs.CheckSetStat(ctx, creds, &opts, pipeMode, nil, auth.KUID(i.uid), auth.KGID(i.gid)); err != nil {
return err
}
if opts.Stat.Mask&linux.STATX_UID != 0 {
Expand Down
2 changes: 1 addition & 1 deletion pkg/sentry/fsimpl/proc/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ func (i *taskOwnedInode) Stat(ctx context.Context, fs *vfs.Filesystem, opts vfs.
func (i *taskOwnedInode) CheckPermissions(ctx context.Context, creds *auth.Credentials, ats vfs.AccessTypes) error {
mode := i.Mode()
uid, gid := i.getOwner(mode)
return vfs.GenericCheckPermissions(creds, ats, mode, uid, gid)
return vfs.GenericCheckPermissions(creds, ats, mode, nil, uid, gid)
}

func (i *taskOwnedInode) getOwner(mode linux.FileMode) (auth.KUID, auth.KGID) {
Expand Down
1 change: 1 addition & 0 deletions pkg/sentry/fsimpl/tmpfs/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ go_library(
],
imports = [
"gvisor.dev/gvisor/pkg/sentry/checkpoint",
"gvisor.dev/gvisor/pkg/sentry/vfs",
],
marshal = True,
visibility = ["//pkg/sentry:internal"],
Expand Down
2 changes: 1 addition & 1 deletion pkg/sentry/fsimpl/tmpfs/filesystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ func (fs *filesystem) LinkAt(ctx context.Context, rp *vfs.ResolvingPath, vd vfs.
if i.isDir() {
return linuxerr.EPERM
}
if err := vfs.MayLink(auth.CredentialsFromContext(ctx), linux.FileMode(i.mode.Load()), auth.KUID(i.uid.Load()), auth.KGID(i.gid.Load())); err != nil {
if err := vfs.MayLink(auth.CredentialsFromContext(ctx), linux.FileMode(i.mode.Load()), i.acl.Load(), auth.KUID(i.uid.Load()), auth.KGID(i.gid.Load())); err != nil {
return err
}
if i.nlink.Load() == 0 {
Expand Down
Loading
Loading