summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fs/attr.go
diff options
context:
space:
mode:
authorgVisor bot <gvisor-bot@google.com>2019-06-02 06:44:55 +0000
committergVisor bot <gvisor-bot@google.com>2019-06-02 06:44:55 +0000
commitceb0d792f328d1fc0692197d8856a43c3936a571 (patch)
tree83155f302eff44a78bcc30a3a08f4efe59a79379 /pkg/sentry/fs/attr.go
parentdeb7ecf1e46862d54f4b102f2d163cfbcfc37f3b (diff)
parent216da0b733dbed9aad9b2ab92ac75bcb906fd7ee (diff)
Merge 216da0b7 (automated)
Diffstat (limited to 'pkg/sentry/fs/attr.go')
-rw-r--r--pkg/sentry/fs/attr.go422
1 files changed, 422 insertions, 0 deletions
diff --git a/pkg/sentry/fs/attr.go b/pkg/sentry/fs/attr.go
new file mode 100644
index 000000000..591e35e6a
--- /dev/null
+++ b/pkg/sentry/fs/attr.go
@@ -0,0 +1,422 @@
+// Copyright 2018 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package fs
+
+import (
+ "fmt"
+ "os"
+ "syscall"
+
+ "gvisor.googlesource.com/gvisor/pkg/abi/linux"
+ "gvisor.googlesource.com/gvisor/pkg/p9"
+ "gvisor.googlesource.com/gvisor/pkg/sentry/context"
+ "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/auth"
+ ktime "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/time"
+)
+
+// InodeType enumerates types of Inodes.
+type InodeType int
+
+const (
+ // RegularFile is a regular file.
+ RegularFile InodeType = iota
+
+ // SpecialFile is a file that doesn't support SeekEnd. It is used for
+ // things like proc files.
+ SpecialFile
+
+ // Directory is a directory.
+ Directory
+
+ // SpecialDirectory is a directory that *does* support SeekEnd. It's
+ // the opposite of the SpecialFile scenario above. It similarly
+ // supports proc files.
+ SpecialDirectory
+
+ // Symlink is a symbolic link.
+ Symlink
+
+ // Pipe is a pipe (named or regular).
+ Pipe
+
+ // Socket is a socket.
+ Socket
+
+ // CharacterDevice is a character device.
+ CharacterDevice
+
+ // BlockDevice is a block device.
+ BlockDevice
+
+ // Anonymous is an anonymous type when none of the above apply.
+ // Epoll fds and event-driven fds fit this category.
+ Anonymous
+)
+
+// String returns a human-readable representation of the InodeType.
+func (n InodeType) String() string {
+ switch n {
+ case RegularFile, SpecialFile:
+ return "file"
+ case Directory, SpecialDirectory:
+ return "directory"
+ case Symlink:
+ return "symlink"
+ case Pipe:
+ return "pipe"
+ case Socket:
+ return "socket"
+ case CharacterDevice:
+ return "character-device"
+ case BlockDevice:
+ return "block-device"
+ case Anonymous:
+ return "anonymous"
+ default:
+ return "unknown"
+ }
+}
+
+// StableAttr contains Inode attributes that will be stable throughout the
+// lifetime of the Inode.
+//
+// +stateify savable
+type StableAttr struct {
+ // Type is the InodeType of a InodeOperations.
+ Type InodeType
+
+ // DeviceID is the device on which a InodeOperations resides.
+ DeviceID uint64
+
+ // InodeID uniquely identifies InodeOperations on its device.
+ InodeID uint64
+
+ // BlockSize is the block size of data backing this InodeOperations.
+ BlockSize int64
+
+ // DeviceFileMajor is the major device number of this Node, if it is a
+ // device file.
+ DeviceFileMajor uint16
+
+ // DeviceFileMinor is the minor device number of this Node, if it is a
+ // device file.
+ DeviceFileMinor uint32
+}
+
+// IsRegular returns true if StableAttr.Type matches a regular file.
+func IsRegular(s StableAttr) bool {
+ return s.Type == RegularFile
+}
+
+// IsFile returns true if StableAttr.Type matches any type of file.
+func IsFile(s StableAttr) bool {
+ return s.Type == RegularFile || s.Type == SpecialFile
+}
+
+// IsDir returns true if StableAttr.Type matches any type of directory.
+func IsDir(s StableAttr) bool {
+ return s.Type == Directory || s.Type == SpecialDirectory
+}
+
+// IsSymlink returns true if StableAttr.Type matches a symlink.
+func IsSymlink(s StableAttr) bool {
+ return s.Type == Symlink
+}
+
+// IsPipe returns true if StableAttr.Type matches any type of pipe.
+func IsPipe(s StableAttr) bool {
+ return s.Type == Pipe
+}
+
+// IsSocket returns true if StableAttr.Type matches any type of socket.
+func IsSocket(s StableAttr) bool {
+ return s.Type == Socket
+}
+
+// IsCharDevice returns true if StableAttr.Type matches a character device.
+func IsCharDevice(s StableAttr) bool {
+ return s.Type == CharacterDevice
+}
+
+// UnstableAttr contains Inode attributes that may change over the lifetime
+// of the Inode.
+//
+// +stateify savable
+type UnstableAttr struct {
+ // Size is the file size in bytes.
+ Size int64
+
+ // Usage is the actual data usage in bytes.
+ Usage int64
+
+ // Perms is the protection (read/write/execute for user/group/other).
+ Perms FilePermissions
+
+ // Owner describes the ownership of this file.
+ Owner FileOwner
+
+ // AccessTime is the time of last access
+ AccessTime ktime.Time
+
+ // ModificationTime is the time of last modification.
+ ModificationTime ktime.Time
+
+ // StatusChangeTime is the time of last attribute modification.
+ StatusChangeTime ktime.Time
+
+ // Links is the number of hard links.
+ Links uint64
+}
+
+// SetOwner sets the owner and group if they are valid.
+//
+// This method is NOT thread-safe. Callers must prevent concurrent calls.
+func (ua *UnstableAttr) SetOwner(ctx context.Context, owner FileOwner) {
+ if owner.UID.Ok() {
+ ua.Owner.UID = owner.UID
+ }
+ if owner.GID.Ok() {
+ ua.Owner.GID = owner.GID
+ }
+ ua.StatusChangeTime = ktime.NowFromContext(ctx)
+}
+
+// SetPermissions sets the permissions.
+//
+// This method is NOT thread-safe. Callers must prevent concurrent calls.
+func (ua *UnstableAttr) SetPermissions(ctx context.Context, p FilePermissions) {
+ ua.Perms = p
+ ua.StatusChangeTime = ktime.NowFromContext(ctx)
+}
+
+// SetTimestamps sets the timestamps according to the TimeSpec.
+//
+// This method is NOT thread-safe. Callers must prevent concurrent calls.
+func (ua *UnstableAttr) SetTimestamps(ctx context.Context, ts TimeSpec) {
+ if ts.ATimeOmit && ts.MTimeOmit {
+ return
+ }
+
+ now := ktime.NowFromContext(ctx)
+ if !ts.ATimeOmit {
+ if ts.ATimeSetSystemTime {
+ ua.AccessTime = now
+ } else {
+ ua.AccessTime = ts.ATime
+ }
+ }
+ if !ts.MTimeOmit {
+ if ts.MTimeSetSystemTime {
+ ua.ModificationTime = now
+ } else {
+ ua.ModificationTime = ts.MTime
+ }
+ }
+ ua.StatusChangeTime = now
+}
+
+// WithCurrentTime returns u with AccessTime == ModificationTime == current time.
+func WithCurrentTime(ctx context.Context, u UnstableAttr) UnstableAttr {
+ t := ktime.NowFromContext(ctx)
+ u.AccessTime = t
+ u.ModificationTime = t
+ u.StatusChangeTime = t
+ return u
+}
+
+// AttrMask contains fields to mask StableAttr and UnstableAttr.
+//
+// +stateify savable
+type AttrMask struct {
+ Type bool
+ DeviceID bool
+ InodeID bool
+ BlockSize bool
+ Size bool
+ Usage bool
+ Perms bool
+ UID bool
+ GID bool
+ AccessTime bool
+ ModificationTime bool
+ StatusChangeTime bool
+ Links bool
+}
+
+// Empty returns true if all fields in AttrMask are false.
+func (a AttrMask) Empty() bool {
+ return a == AttrMask{}
+}
+
+// PermMask are file access permissions.
+//
+// +stateify savable
+type PermMask struct {
+ // Read indicates reading is permitted.
+ Read bool
+
+ // Write indicates writing is permitted.
+ Write bool
+
+ // Execute indicates execution is permitted.
+ Execute bool
+}
+
+// OnlyRead returns true when only the read bit is set.
+func (p PermMask) OnlyRead() bool {
+ return p.Read && !p.Write && !p.Execute
+}
+
+// String implements the fmt.Stringer interface for PermMask.
+func (p PermMask) String() string {
+ return fmt.Sprintf("PermMask{Read: %v, Write: %v, Execute: %v}", p.Read, p.Write, p.Execute)
+}
+
+// Mode returns the system mode (syscall.S_IXOTH, etc.) for these permissions
+// in the "other" bits.
+func (p PermMask) Mode() (mode os.FileMode) {
+ if p.Read {
+ mode |= syscall.S_IROTH
+ }
+ if p.Write {
+ mode |= syscall.S_IWOTH
+ }
+ if p.Execute {
+ mode |= syscall.S_IXOTH
+ }
+ return
+}
+
+// SupersetOf returns true iff the permissions in p are a superset of the
+// permissions in other.
+func (p PermMask) SupersetOf(other PermMask) bool {
+ if !p.Read && other.Read {
+ return false
+ }
+ if !p.Write && other.Write {
+ return false
+ }
+ if !p.Execute && other.Execute {
+ return false
+ }
+ return true
+}
+
+// FilePermissions represents the permissions of a file, with
+// Read/Write/Execute bits for user, group, and other.
+//
+// +stateify savable
+type FilePermissions struct {
+ User PermMask
+ Group PermMask
+ Other PermMask
+
+ // Sticky, if set on directories, restricts renaming and deletion of
+ // files in those directories to the directory owner, file owner, or
+ // CAP_FOWNER. The sticky bit is ignored when set on other files.
+ Sticky bool
+
+ // SetUID executables can call UID-setting syscalls without CAP_SETUID.
+ SetUID bool
+
+ // SetGID executables can call GID-setting syscalls without CAP_SETGID.
+ SetGID bool
+}
+
+// PermsFromMode takes the Other permissions (last 3 bits) of a FileMode and
+// returns a set of PermMask.
+func PermsFromMode(mode linux.FileMode) (perms PermMask) {
+ perms.Read = mode&linux.ModeOtherRead != 0
+ perms.Write = mode&linux.ModeOtherWrite != 0
+ perms.Execute = mode&linux.ModeOtherExec != 0
+ return
+}
+
+// FilePermsFromP9 converts a p9.FileMode to a FilePermissions struct.
+func FilePermsFromP9(mode p9.FileMode) FilePermissions {
+ return FilePermsFromMode(linux.FileMode(mode))
+}
+
+// FilePermsFromMode converts a system file mode to a FilePermissions struct.
+func FilePermsFromMode(mode linux.FileMode) (fp FilePermissions) {
+ perm := mode.Permissions()
+ fp.Other = PermsFromMode(perm)
+ fp.Group = PermsFromMode(perm >> 3)
+ fp.User = PermsFromMode(perm >> 6)
+ fp.Sticky = mode&linux.ModeSticky == linux.ModeSticky
+ fp.SetUID = mode&linux.ModeSetUID == linux.ModeSetUID
+ fp.SetGID = mode&linux.ModeSetGID == linux.ModeSetGID
+ return
+}
+
+// LinuxMode returns the linux mode_t representation of these permissions.
+func (f FilePermissions) LinuxMode() linux.FileMode {
+ m := linux.FileMode(f.User.Mode()<<6 | f.Group.Mode()<<3 | f.Other.Mode())
+ if f.SetUID {
+ m |= linux.ModeSetUID
+ }
+ if f.SetGID {
+ m |= linux.ModeSetGID
+ }
+ if f.Sticky {
+ m |= linux.ModeSticky
+ }
+ return m
+}
+
+// OSMode returns the Go runtime's OS independent os.FileMode representation of
+// these permissions.
+func (f FilePermissions) OSMode() os.FileMode {
+ m := os.FileMode(f.User.Mode()<<6 | f.Group.Mode()<<3 | f.Other.Mode())
+ if f.SetUID {
+ m |= os.ModeSetuid
+ }
+ if f.SetGID {
+ m |= os.ModeSetgid
+ }
+ if f.Sticky {
+ m |= os.ModeSticky
+ }
+ return m
+}
+
+// AnyExecute returns true if any of U/G/O have the execute bit set.
+func (f FilePermissions) AnyExecute() bool {
+ return f.User.Execute || f.Group.Execute || f.Other.Execute
+}
+
+// AnyWrite returns true if any of U/G/O have the write bit set.
+func (f FilePermissions) AnyWrite() bool {
+ return f.User.Write || f.Group.Write || f.Other.Write
+}
+
+// AnyRead returns true if any of U/G/O have the read bit set.
+func (f FilePermissions) AnyRead() bool {
+ return f.User.Read || f.Group.Read || f.Other.Read
+}
+
+// FileOwner represents ownership of a file.
+//
+// +stateify savable
+type FileOwner struct {
+ UID auth.KUID
+ GID auth.KGID
+}
+
+// RootOwner corresponds to KUID/KGID 0/0.
+var RootOwner = FileOwner{
+ UID: auth.RootKUID,
+ GID: auth.RootKGID,
+}