mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Support listxattr and removexattr syscalls.
Note that these are only implemented for tmpfs, and other impls will still return EOPNOTSUPP. PiperOrigin-RevId: 293899385
This commit is contained in:
@@ -194,6 +194,39 @@ func (c *clientFile) SetXattr(name, value string, flags uint32) error {
|
||||
return c.client.sendRecv(&Tsetxattr{FID: c.fid, Name: name, Value: value, Flags: flags}, &Rsetxattr{})
|
||||
}
|
||||
|
||||
// ListXattr implements File.ListXattr.
|
||||
func (c *clientFile) ListXattr(size uint64) (map[string]struct{}, error) {
|
||||
if atomic.LoadUint32(&c.closed) != 0 {
|
||||
return nil, syscall.EBADF
|
||||
}
|
||||
if !versionSupportsListRemoveXattr(c.client.version) {
|
||||
return nil, syscall.EOPNOTSUPP
|
||||
}
|
||||
|
||||
rlistxattr := Rlistxattr{}
|
||||
if err := c.client.sendRecv(&Tlistxattr{FID: c.fid, Size: size}, &rlistxattr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
xattrs := make(map[string]struct{}, len(rlistxattr.Xattrs))
|
||||
for _, x := range rlistxattr.Xattrs {
|
||||
xattrs[x] = struct{}{}
|
||||
}
|
||||
return xattrs, nil
|
||||
}
|
||||
|
||||
// RemoveXattr implements File.RemoveXattr.
|
||||
func (c *clientFile) RemoveXattr(name string) error {
|
||||
if atomic.LoadUint32(&c.closed) != 0 {
|
||||
return syscall.EBADF
|
||||
}
|
||||
if !versionSupportsListRemoveXattr(c.client.version) {
|
||||
return syscall.EOPNOTSUPP
|
||||
}
|
||||
|
||||
return c.client.sendRecv(&Tremovexattr{FID: c.fid, Name: name}, &Rremovexattr{})
|
||||
}
|
||||
|
||||
// Allocate implements File.Allocate.
|
||||
func (c *clientFile) Allocate(mode AllocateMode, offset, length uint64) error {
|
||||
if atomic.LoadUint32(&c.closed) != 0 {
|
||||
|
||||
@@ -105,6 +105,22 @@ type File interface {
|
||||
// TODO(b/127675828): Determine concurrency guarantees once implemented.
|
||||
SetXattr(name, value string, flags uint32) error
|
||||
|
||||
// ListXattr lists the names of the extended attributes on this node.
|
||||
//
|
||||
// Size indicates the size of the buffer that has been allocated to hold the
|
||||
// attribute list. If the list would be larger than size, implementations may
|
||||
// return ERANGE to indicate that the buffer is too small, but they are also
|
||||
// free to ignore the hint entirely (i.e. the value returned may be larger
|
||||
// than size). All size checking is done independently at the syscall layer.
|
||||
//
|
||||
// TODO(b/148303075): Determine concurrency guarantees once implemented.
|
||||
ListXattr(size uint64) (map[string]struct{}, error)
|
||||
|
||||
// RemoveXattr removes extended attributes on this node.
|
||||
//
|
||||
// TODO(b/148303075): Determine concurrency guarantees once implemented.
|
||||
RemoveXattr(name string) error
|
||||
|
||||
// Allocate allows the caller to directly manipulate the allocated disk space
|
||||
// for the file. See fallocate(2) for more details.
|
||||
Allocate(mode AllocateMode, offset, length uint64) error
|
||||
|
||||
@@ -941,6 +941,39 @@ func (t *Tsetxattr) handle(cs *connState) message {
|
||||
return &Rsetxattr{}
|
||||
}
|
||||
|
||||
// handle implements handler.handle.
|
||||
func (t *Tlistxattr) handle(cs *connState) message {
|
||||
ref, ok := cs.LookupFID(t.FID)
|
||||
if !ok {
|
||||
return newErr(syscall.EBADF)
|
||||
}
|
||||
defer ref.DecRef()
|
||||
|
||||
xattrs, err := ref.file.ListXattr(t.Size)
|
||||
if err != nil {
|
||||
return newErr(err)
|
||||
}
|
||||
xattrList := make([]string, 0, len(xattrs))
|
||||
for x := range xattrs {
|
||||
xattrList = append(xattrList, x)
|
||||
}
|
||||
return &Rlistxattr{Xattrs: xattrList}
|
||||
}
|
||||
|
||||
// handle implements handler.handle.
|
||||
func (t *Tremovexattr) handle(cs *connState) message {
|
||||
ref, ok := cs.LookupFID(t.FID)
|
||||
if !ok {
|
||||
return newErr(syscall.EBADF)
|
||||
}
|
||||
defer ref.DecRef()
|
||||
|
||||
if err := ref.file.RemoveXattr(t.Name); err != nil {
|
||||
return newErr(err)
|
||||
}
|
||||
return &Rremovexattr{}
|
||||
}
|
||||
|
||||
// handle implements handler.handle.
|
||||
func (t *Treaddir) handle(cs *connState) message {
|
||||
ref, ok := cs.LookupFID(t.Directory)
|
||||
|
||||
+160
-39
@@ -174,11 +174,11 @@ type Rflush struct {
|
||||
}
|
||||
|
||||
// Decode implements encoder.Decode.
|
||||
func (*Rflush) Decode(b *buffer) {
|
||||
func (*Rflush) Decode(*buffer) {
|
||||
}
|
||||
|
||||
// Encode implements encoder.Encode.
|
||||
func (*Rflush) Encode(b *buffer) {
|
||||
func (*Rflush) Encode(*buffer) {
|
||||
}
|
||||
|
||||
// Type implements message.Type.
|
||||
@@ -188,7 +188,7 @@ func (*Rflush) Type() MsgType {
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (r *Rflush) String() string {
|
||||
return fmt.Sprintf("RFlush{}")
|
||||
return "RFlush{}"
|
||||
}
|
||||
|
||||
// Twalk is a walk request.
|
||||
@@ -300,11 +300,11 @@ type Rclunk struct {
|
||||
}
|
||||
|
||||
// Decode implements encoder.Decode.
|
||||
func (*Rclunk) Decode(b *buffer) {
|
||||
func (*Rclunk) Decode(*buffer) {
|
||||
}
|
||||
|
||||
// Encode implements encoder.Encode.
|
||||
func (*Rclunk) Encode(b *buffer) {
|
||||
func (*Rclunk) Encode(*buffer) {
|
||||
}
|
||||
|
||||
// Type implements message.Type.
|
||||
@@ -314,7 +314,7 @@ func (*Rclunk) Type() MsgType {
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (r *Rclunk) String() string {
|
||||
return fmt.Sprintf("Rclunk{}")
|
||||
return "Rclunk{}"
|
||||
}
|
||||
|
||||
// Tremove is a remove request.
|
||||
@@ -350,11 +350,11 @@ type Rremove struct {
|
||||
}
|
||||
|
||||
// Decode implements encoder.Decode.
|
||||
func (*Rremove) Decode(b *buffer) {
|
||||
func (*Rremove) Decode(*buffer) {
|
||||
}
|
||||
|
||||
// Encode implements encoder.Encode.
|
||||
func (*Rremove) Encode(b *buffer) {
|
||||
func (*Rremove) Encode(*buffer) {
|
||||
}
|
||||
|
||||
// Type implements message.Type.
|
||||
@@ -364,7 +364,7 @@ func (*Rremove) Type() MsgType {
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (r *Rremove) String() string {
|
||||
return fmt.Sprintf("Rremove{}")
|
||||
return "Rremove{}"
|
||||
}
|
||||
|
||||
// Rlerror is an error response.
|
||||
@@ -745,16 +745,16 @@ func (*Rlink) Type() MsgType {
|
||||
}
|
||||
|
||||
// Decode implements encoder.Decode.
|
||||
func (*Rlink) Decode(b *buffer) {
|
||||
func (*Rlink) Decode(*buffer) {
|
||||
}
|
||||
|
||||
// Encode implements encoder.Encode.
|
||||
func (*Rlink) Encode(b *buffer) {
|
||||
func (*Rlink) Encode(*buffer) {
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (r *Rlink) String() string {
|
||||
return fmt.Sprintf("Rlink{}")
|
||||
return "Rlink{}"
|
||||
}
|
||||
|
||||
// Trenameat is a rename request.
|
||||
@@ -803,11 +803,11 @@ type Rrenameat struct {
|
||||
}
|
||||
|
||||
// Decode implements encoder.Decode.
|
||||
func (*Rrenameat) Decode(b *buffer) {
|
||||
func (*Rrenameat) Decode(*buffer) {
|
||||
}
|
||||
|
||||
// Encode implements encoder.Encode.
|
||||
func (*Rrenameat) Encode(b *buffer) {
|
||||
func (*Rrenameat) Encode(*buffer) {
|
||||
}
|
||||
|
||||
// Type implements message.Type.
|
||||
@@ -817,7 +817,7 @@ func (*Rrenameat) Type() MsgType {
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (r *Rrenameat) String() string {
|
||||
return fmt.Sprintf("Rrenameat{}")
|
||||
return "Rrenameat{}"
|
||||
}
|
||||
|
||||
// Tunlinkat is an unlink request.
|
||||
@@ -861,11 +861,11 @@ type Runlinkat struct {
|
||||
}
|
||||
|
||||
// Decode implements encoder.Decode.
|
||||
func (*Runlinkat) Decode(b *buffer) {
|
||||
func (*Runlinkat) Decode(*buffer) {
|
||||
}
|
||||
|
||||
// Encode implements encoder.Encode.
|
||||
func (*Runlinkat) Encode(b *buffer) {
|
||||
func (*Runlinkat) Encode(*buffer) {
|
||||
}
|
||||
|
||||
// Type implements message.Type.
|
||||
@@ -875,7 +875,7 @@ func (*Runlinkat) Type() MsgType {
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (r *Runlinkat) String() string {
|
||||
return fmt.Sprintf("Runlinkat{}")
|
||||
return "Runlinkat{}"
|
||||
}
|
||||
|
||||
// Trename is a rename request.
|
||||
@@ -922,11 +922,11 @@ type Rrename struct {
|
||||
}
|
||||
|
||||
// Decode implements encoder.Decode.
|
||||
func (*Rrename) Decode(b *buffer) {
|
||||
func (*Rrename) Decode(*buffer) {
|
||||
}
|
||||
|
||||
// Encode implements encoder.Encode.
|
||||
func (*Rrename) Encode(b *buffer) {
|
||||
func (*Rrename) Encode(*buffer) {
|
||||
}
|
||||
|
||||
// Type implements message.Type.
|
||||
@@ -936,7 +936,7 @@ func (*Rrename) Type() MsgType {
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (r *Rrename) String() string {
|
||||
return fmt.Sprintf("Rrename{}")
|
||||
return "Rrename{}"
|
||||
}
|
||||
|
||||
// Treadlink is a readlink request.
|
||||
@@ -1409,11 +1409,11 @@ type Rsetattr struct {
|
||||
}
|
||||
|
||||
// Decode implements encoder.Decode.
|
||||
func (*Rsetattr) Decode(b *buffer) {
|
||||
func (*Rsetattr) Decode(*buffer) {
|
||||
}
|
||||
|
||||
// Encode implements encoder.Encode.
|
||||
func (*Rsetattr) Encode(b *buffer) {
|
||||
func (*Rsetattr) Encode(*buffer) {
|
||||
}
|
||||
|
||||
// Type implements message.Type.
|
||||
@@ -1423,7 +1423,7 @@ func (*Rsetattr) Type() MsgType {
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (r *Rsetattr) String() string {
|
||||
return fmt.Sprintf("Rsetattr{}")
|
||||
return "Rsetattr{}"
|
||||
}
|
||||
|
||||
// Tallocate is an allocate request. This is an extension to 9P protocol, not
|
||||
@@ -1466,11 +1466,11 @@ type Rallocate struct {
|
||||
}
|
||||
|
||||
// Decode implements encoder.Decode.
|
||||
func (*Rallocate) Decode(b *buffer) {
|
||||
func (*Rallocate) Decode(*buffer) {
|
||||
}
|
||||
|
||||
// Encode implements encoder.Encode.
|
||||
func (*Rallocate) Encode(b *buffer) {
|
||||
func (*Rallocate) Encode(*buffer) {
|
||||
}
|
||||
|
||||
// Type implements message.Type.
|
||||
@@ -1480,7 +1480,71 @@ func (*Rallocate) Type() MsgType {
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (r *Rallocate) String() string {
|
||||
return fmt.Sprintf("Rallocate{}")
|
||||
return "Rallocate{}"
|
||||
}
|
||||
|
||||
// Tlistxattr is a listxattr request.
|
||||
type Tlistxattr struct {
|
||||
// FID refers to the file on which to list xattrs.
|
||||
FID FID
|
||||
|
||||
// Size is the buffer size for the xattr list.
|
||||
Size uint64
|
||||
}
|
||||
|
||||
// Decode implements encoder.Decode.
|
||||
func (t *Tlistxattr) Decode(b *buffer) {
|
||||
t.FID = b.ReadFID()
|
||||
t.Size = b.Read64()
|
||||
}
|
||||
|
||||
// Encode implements encoder.Encode.
|
||||
func (t *Tlistxattr) Encode(b *buffer) {
|
||||
b.WriteFID(t.FID)
|
||||
b.Write64(t.Size)
|
||||
}
|
||||
|
||||
// Type implements message.Type.
|
||||
func (*Tlistxattr) Type() MsgType {
|
||||
return MsgTlistxattr
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (t *Tlistxattr) String() string {
|
||||
return fmt.Sprintf("Tlistxattr{FID: %d, Size: %d}", t.FID, t.Size)
|
||||
}
|
||||
|
||||
// Rlistxattr is a listxattr response.
|
||||
type Rlistxattr struct {
|
||||
// Xattrs is a list of extended attribute names.
|
||||
Xattrs []string
|
||||
}
|
||||
|
||||
// Decode implements encoder.Decode.
|
||||
func (r *Rlistxattr) Decode(b *buffer) {
|
||||
n := b.Read16()
|
||||
r.Xattrs = r.Xattrs[:0]
|
||||
for i := 0; i < int(n); i++ {
|
||||
r.Xattrs = append(r.Xattrs, b.ReadString())
|
||||
}
|
||||
}
|
||||
|
||||
// Encode implements encoder.Encode.
|
||||
func (r *Rlistxattr) Encode(b *buffer) {
|
||||
b.Write16(uint16(len(r.Xattrs)))
|
||||
for _, x := range r.Xattrs {
|
||||
b.WriteString(x)
|
||||
}
|
||||
}
|
||||
|
||||
// Type implements message.Type.
|
||||
func (*Rlistxattr) Type() MsgType {
|
||||
return MsgRlistxattr
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (r *Rlistxattr) String() string {
|
||||
return fmt.Sprintf("Rlistxattr{Xattrs: %v}", r.Xattrs)
|
||||
}
|
||||
|
||||
// Txattrwalk walks extended attributes.
|
||||
@@ -1594,11 +1658,11 @@ type Rxattrcreate struct {
|
||||
}
|
||||
|
||||
// Decode implements encoder.Decode.
|
||||
func (r *Rxattrcreate) Decode(b *buffer) {
|
||||
func (r *Rxattrcreate) Decode(*buffer) {
|
||||
}
|
||||
|
||||
// Encode implements encoder.Encode.
|
||||
func (r *Rxattrcreate) Encode(b *buffer) {
|
||||
func (r *Rxattrcreate) Encode(*buffer) {
|
||||
}
|
||||
|
||||
// Type implements message.Type.
|
||||
@@ -1608,7 +1672,7 @@ func (*Rxattrcreate) Type() MsgType {
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (r *Rxattrcreate) String() string {
|
||||
return fmt.Sprintf("Rxattrcreate{}")
|
||||
return "Rxattrcreate{}"
|
||||
}
|
||||
|
||||
// Tgetxattr is a getxattr request.
|
||||
@@ -1719,11 +1783,11 @@ type Rsetxattr struct {
|
||||
}
|
||||
|
||||
// Decode implements encoder.Decode.
|
||||
func (r *Rsetxattr) Decode(b *buffer) {
|
||||
func (r *Rsetxattr) Decode(*buffer) {
|
||||
}
|
||||
|
||||
// Encode implements encoder.Encode.
|
||||
func (r *Rsetxattr) Encode(b *buffer) {
|
||||
func (r *Rsetxattr) Encode(*buffer) {
|
||||
}
|
||||
|
||||
// Type implements message.Type.
|
||||
@@ -1733,7 +1797,60 @@ func (*Rsetxattr) Type() MsgType {
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (r *Rsetxattr) String() string {
|
||||
return fmt.Sprintf("Rsetxattr{}")
|
||||
return "Rsetxattr{}"
|
||||
}
|
||||
|
||||
// Tremovexattr is a removexattr request.
|
||||
type Tremovexattr struct {
|
||||
// FID refers to the file on which to set xattrs.
|
||||
FID FID
|
||||
|
||||
// Name is the attribute name.
|
||||
Name string
|
||||
}
|
||||
|
||||
// Decode implements encoder.Decode.
|
||||
func (t *Tremovexattr) Decode(b *buffer) {
|
||||
t.FID = b.ReadFID()
|
||||
t.Name = b.ReadString()
|
||||
}
|
||||
|
||||
// Encode implements encoder.Encode.
|
||||
func (t *Tremovexattr) Encode(b *buffer) {
|
||||
b.WriteFID(t.FID)
|
||||
b.WriteString(t.Name)
|
||||
}
|
||||
|
||||
// Type implements message.Type.
|
||||
func (*Tremovexattr) Type() MsgType {
|
||||
return MsgTremovexattr
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (t *Tremovexattr) String() string {
|
||||
return fmt.Sprintf("Tremovexattr{FID: %d, Name: %s}", t.FID, t.Name)
|
||||
}
|
||||
|
||||
// Rremovexattr is a removexattr response.
|
||||
type Rremovexattr struct {
|
||||
}
|
||||
|
||||
// Decode implements encoder.Decode.
|
||||
func (r *Rremovexattr) Decode(*buffer) {
|
||||
}
|
||||
|
||||
// Encode implements encoder.Encode.
|
||||
func (r *Rremovexattr) Encode(*buffer) {
|
||||
}
|
||||
|
||||
// Type implements message.Type.
|
||||
func (*Rremovexattr) Type() MsgType {
|
||||
return MsgRremovexattr
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (r *Rremovexattr) String() string {
|
||||
return "Rremovexattr{}"
|
||||
}
|
||||
|
||||
// Treaddir is a readdir request.
|
||||
@@ -1880,11 +1997,11 @@ type Rfsync struct {
|
||||
}
|
||||
|
||||
// Decode implements encoder.Decode.
|
||||
func (*Rfsync) Decode(b *buffer) {
|
||||
func (*Rfsync) Decode(*buffer) {
|
||||
}
|
||||
|
||||
// Encode implements encoder.Encode.
|
||||
func (*Rfsync) Encode(b *buffer) {
|
||||
func (*Rfsync) Encode(*buffer) {
|
||||
}
|
||||
|
||||
// Type implements message.Type.
|
||||
@@ -1894,7 +2011,7 @@ func (*Rfsync) Type() MsgType {
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (r *Rfsync) String() string {
|
||||
return fmt.Sprintf("Rfsync{}")
|
||||
return "Rfsync{}"
|
||||
}
|
||||
|
||||
// Tstatfs is a stat request.
|
||||
@@ -1980,11 +2097,11 @@ type Rflushf struct {
|
||||
}
|
||||
|
||||
// Decode implements encoder.Decode.
|
||||
func (*Rflushf) Decode(b *buffer) {
|
||||
func (*Rflushf) Decode(*buffer) {
|
||||
}
|
||||
|
||||
// Encode implements encoder.Encode.
|
||||
func (*Rflushf) Encode(b *buffer) {
|
||||
func (*Rflushf) Encode(*buffer) {
|
||||
}
|
||||
|
||||
// Type implements message.Type.
|
||||
@@ -1994,7 +2111,7 @@ func (*Rflushf) Type() MsgType {
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (*Rflushf) String() string {
|
||||
return fmt.Sprintf("Rflushf{}")
|
||||
return "Rflushf{}"
|
||||
}
|
||||
|
||||
// Twalkgetattr is a walk request.
|
||||
@@ -2484,6 +2601,8 @@ func init() {
|
||||
msgRegistry.register(MsgRgetattr, func() message { return &Rgetattr{} })
|
||||
msgRegistry.register(MsgTsetattr, func() message { return &Tsetattr{} })
|
||||
msgRegistry.register(MsgRsetattr, func() message { return &Rsetattr{} })
|
||||
msgRegistry.register(MsgTlistxattr, func() message { return &Tlistxattr{} })
|
||||
msgRegistry.register(MsgRlistxattr, func() message { return &Rlistxattr{} })
|
||||
msgRegistry.register(MsgTxattrwalk, func() message { return &Txattrwalk{} })
|
||||
msgRegistry.register(MsgRxattrwalk, func() message { return &Rxattrwalk{} })
|
||||
msgRegistry.register(MsgTxattrcreate, func() message { return &Txattrcreate{} })
|
||||
@@ -2492,6 +2611,8 @@ func init() {
|
||||
msgRegistry.register(MsgRgetxattr, func() message { return &Rgetxattr{} })
|
||||
msgRegistry.register(MsgTsetxattr, func() message { return &Tsetxattr{} })
|
||||
msgRegistry.register(MsgRsetxattr, func() message { return &Rsetxattr{} })
|
||||
msgRegistry.register(MsgTremovexattr, func() message { return &Tremovexattr{} })
|
||||
msgRegistry.register(MsgRremovexattr, func() message { return &Rremovexattr{} })
|
||||
msgRegistry.register(MsgTreaddir, func() message { return &Treaddir{} })
|
||||
msgRegistry.register(MsgRreaddir, func() message { return &Rreaddir{} })
|
||||
msgRegistry.register(MsgTfsync, func() message { return &Tfsync{} })
|
||||
|
||||
@@ -335,6 +335,8 @@ const (
|
||||
MsgRgetattr = 25
|
||||
MsgTsetattr = 26
|
||||
MsgRsetattr = 27
|
||||
MsgTlistxattr = 28
|
||||
MsgRlistxattr = 29
|
||||
MsgTxattrwalk = 30
|
||||
MsgRxattrwalk = 31
|
||||
MsgTxattrcreate = 32
|
||||
@@ -343,6 +345,8 @@ const (
|
||||
MsgRgetxattr = 35
|
||||
MsgTsetxattr = 36
|
||||
MsgRsetxattr = 37
|
||||
MsgTremovexattr = 38
|
||||
MsgRremovexattr = 39
|
||||
MsgTreaddir = 40
|
||||
MsgRreaddir = 41
|
||||
MsgTfsync = 50
|
||||
|
||||
+7
-1
@@ -26,7 +26,7 @@ const (
|
||||
//
|
||||
// Clients are expected to start requesting this version number and
|
||||
// to continuously decrement it until a Tversion request succeeds.
|
||||
highestSupportedVersion uint32 = 10
|
||||
highestSupportedVersion uint32 = 11
|
||||
|
||||
// lowestSupportedVersion is the lowest supported version X in a
|
||||
// version string of the format 9P2000.L.Google.X.
|
||||
@@ -167,3 +167,9 @@ func VersionSupportsOpenTruncateFlag(v uint32) bool {
|
||||
func versionSupportsGetSetXattr(v uint32) bool {
|
||||
return v >= 10
|
||||
}
|
||||
|
||||
// versionSupportsListRemoveXattr returns true if version v supports
|
||||
// the Tlistxattr and Tremovexattr messages.
|
||||
func versionSupportsListRemoveXattr(v uint32) bool {
|
||||
return v >= 11
|
||||
}
|
||||
|
||||
@@ -401,7 +401,7 @@ func copyAttributesLocked(ctx context.Context, upper *Inode, lower *Inode) error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lowerXattr, err := lower.ListXattr(ctx)
|
||||
lowerXattr, err := lower.ListXattr(ctx, linux.XATTR_SIZE_MAX)
|
||||
if err != nil && err != syserror.EOPNOTSUPP {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -247,7 +247,7 @@ func (i *InodeSimpleExtendedAttributes) SetXattr(_ context.Context, _ *fs.Inode,
|
||||
}
|
||||
|
||||
// ListXattr implements fs.InodeOperations.ListXattr.
|
||||
func (i *InodeSimpleExtendedAttributes) ListXattr(context.Context, *fs.Inode) (map[string]struct{}, error) {
|
||||
func (i *InodeSimpleExtendedAttributes) ListXattr(context.Context, *fs.Inode, uint64) (map[string]struct{}, error) {
|
||||
i.mu.RLock()
|
||||
names := make(map[string]struct{}, len(i.xattrs))
|
||||
for name := range i.xattrs {
|
||||
@@ -257,6 +257,17 @@ func (i *InodeSimpleExtendedAttributes) ListXattr(context.Context, *fs.Inode) (m
|
||||
return names, nil
|
||||
}
|
||||
|
||||
// RemoveXattr implements fs.InodeOperations.RemoveXattr.
|
||||
func (i *InodeSimpleExtendedAttributes) RemoveXattr(_ context.Context, _ *fs.Inode, name string) error {
|
||||
i.mu.RLock()
|
||||
defer i.mu.RUnlock()
|
||||
if _, ok := i.xattrs[name]; ok {
|
||||
delete(i.xattrs, name)
|
||||
return nil
|
||||
}
|
||||
return syserror.ENOATTR
|
||||
}
|
||||
|
||||
// staticFile is a file with static contents. It is returned by
|
||||
// InodeStaticFileGetter.GetFile.
|
||||
//
|
||||
@@ -460,10 +471,15 @@ func (InodeNoExtendedAttributes) SetXattr(context.Context, *fs.Inode, string, st
|
||||
}
|
||||
|
||||
// ListXattr implements fs.InodeOperations.ListXattr.
|
||||
func (InodeNoExtendedAttributes) ListXattr(context.Context, *fs.Inode) (map[string]struct{}, error) {
|
||||
func (InodeNoExtendedAttributes) ListXattr(context.Context, *fs.Inode, uint64) (map[string]struct{}, error) {
|
||||
return nil, syserror.EOPNOTSUPP
|
||||
}
|
||||
|
||||
// RemoveXattr implements fs.InodeOperations.RemoveXattr.
|
||||
func (InodeNoExtendedAttributes) RemoveXattr(context.Context, *fs.Inode, string) error {
|
||||
return syserror.EOPNOTSUPP
|
||||
}
|
||||
|
||||
// InodeNoopRelease implements fs.InodeOperations.Release as a noop.
|
||||
type InodeNoopRelease struct{}
|
||||
|
||||
|
||||
@@ -73,6 +73,20 @@ func (c *contextFile) setXattr(ctx context.Context, name, value string, flags ui
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *contextFile) listXattr(ctx context.Context, size uint64) (map[string]struct{}, error) {
|
||||
ctx.UninterruptibleSleepStart(false)
|
||||
xattrs, err := c.file.ListXattr(size)
|
||||
ctx.UninterruptibleSleepFinish(false)
|
||||
return xattrs, err
|
||||
}
|
||||
|
||||
func (c *contextFile) removeXattr(ctx context.Context, name string) error {
|
||||
ctx.UninterruptibleSleepStart(false)
|
||||
err := c.file.RemoveXattr(name)
|
||||
ctx.UninterruptibleSleepFinish(false)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *contextFile) allocate(ctx context.Context, mode p9.AllocateMode, offset, length uint64) error {
|
||||
ctx.UninterruptibleSleepStart(false)
|
||||
err := c.file.Allocate(mode, offset, length)
|
||||
|
||||
@@ -604,18 +604,23 @@ func (i *inodeOperations) Truncate(ctx context.Context, inode *fs.Inode, length
|
||||
}
|
||||
|
||||
// GetXattr implements fs.InodeOperations.GetXattr.
|
||||
func (i *inodeOperations) GetXattr(ctx context.Context, inode *fs.Inode, name string, size uint64) (string, error) {
|
||||
func (i *inodeOperations) GetXattr(ctx context.Context, _ *fs.Inode, name string, size uint64) (string, error) {
|
||||
return i.fileState.file.getXattr(ctx, name, size)
|
||||
}
|
||||
|
||||
// SetXattr implements fs.InodeOperations.SetXattr.
|
||||
func (i *inodeOperations) SetXattr(ctx context.Context, inode *fs.Inode, name string, value string, flags uint32) error {
|
||||
func (i *inodeOperations) SetXattr(ctx context.Context, _ *fs.Inode, name string, value string, flags uint32) error {
|
||||
return i.fileState.file.setXattr(ctx, name, value, flags)
|
||||
}
|
||||
|
||||
// ListXattr implements fs.InodeOperations.ListXattr.
|
||||
func (i *inodeOperations) ListXattr(context.Context, *fs.Inode) (map[string]struct{}, error) {
|
||||
return nil, syscall.EOPNOTSUPP
|
||||
func (i *inodeOperations) ListXattr(ctx context.Context, _ *fs.Inode, size uint64) (map[string]struct{}, error) {
|
||||
return i.fileState.file.listXattr(ctx, size)
|
||||
}
|
||||
|
||||
// RemoveXattr implements fs.InodeOperations.RemoveXattr.
|
||||
func (i *inodeOperations) RemoveXattr(ctx context.Context, _ *fs.Inode, name string) error {
|
||||
return i.fileState.file.removeXattr(ctx, name)
|
||||
}
|
||||
|
||||
// Allocate implements fs.InodeOperations.Allocate.
|
||||
|
||||
+11
-3
@@ -278,11 +278,19 @@ func (i *Inode) SetXattr(ctx context.Context, d *Dirent, name, value string, fla
|
||||
}
|
||||
|
||||
// ListXattr calls i.InodeOperations.ListXattr with i as the Inode.
|
||||
func (i *Inode) ListXattr(ctx context.Context) (map[string]struct{}, error) {
|
||||
func (i *Inode) ListXattr(ctx context.Context, size uint64) (map[string]struct{}, error) {
|
||||
if i.overlay != nil {
|
||||
return overlayListXattr(ctx, i.overlay)
|
||||
return overlayListXattr(ctx, i.overlay, size)
|
||||
}
|
||||
return i.InodeOperations.ListXattr(ctx, i)
|
||||
return i.InodeOperations.ListXattr(ctx, i, size)
|
||||
}
|
||||
|
||||
// RemoveXattr calls i.InodeOperations.RemoveXattr with i as the Inode.
|
||||
func (i *Inode) RemoveXattr(ctx context.Context, d *Dirent, name string) error {
|
||||
if i.overlay != nil {
|
||||
return overlayRemoveXattr(ctx, i.overlay, d, name)
|
||||
}
|
||||
return i.InodeOperations.RemoveXattr(ctx, i, name)
|
||||
}
|
||||
|
||||
// CheckPermission will check if the caller may access this file in the
|
||||
|
||||
@@ -190,7 +190,18 @@ type InodeOperations interface {
|
||||
// ListXattr returns the set of all extended attributes names that
|
||||
// have values. Inodes that do not support extended attributes return
|
||||
// EOPNOTSUPP.
|
||||
ListXattr(ctx context.Context, inode *Inode) (map[string]struct{}, error)
|
||||
//
|
||||
// If this is called through the listxattr(2) syscall, size indicates the
|
||||
// size of the buffer that the application has allocated to hold the
|
||||
// attribute list. If the list would be larger than size, implementations may
|
||||
// return ERANGE to indicate that the buffer is too small, but they are also
|
||||
// free to ignore the hint entirely. All size checking is done independently
|
||||
// at the syscall layer.
|
||||
ListXattr(ctx context.Context, inode *Inode, size uint64) (map[string]struct{}, error)
|
||||
|
||||
// RemoveXattr removes an extended attribute specified by name. Inodes that
|
||||
// do not support extended attributes return EOPNOTSUPP.
|
||||
RemoveXattr(ctx context.Context, inode *Inode, name string) error
|
||||
|
||||
// Check determines whether an Inode can be accessed with the
|
||||
// requested permission mask using the context (which gives access
|
||||
|
||||
@@ -564,15 +564,15 @@ func overlaySetxattr(ctx context.Context, o *overlayEntry, d *Dirent, name, valu
|
||||
return o.upper.SetXattr(ctx, d, name, value, flags)
|
||||
}
|
||||
|
||||
func overlayListXattr(ctx context.Context, o *overlayEntry) (map[string]struct{}, error) {
|
||||
func overlayListXattr(ctx context.Context, o *overlayEntry, size uint64) (map[string]struct{}, error) {
|
||||
o.copyMu.RLock()
|
||||
defer o.copyMu.RUnlock()
|
||||
var names map[string]struct{}
|
||||
var err error
|
||||
if o.upper != nil {
|
||||
names, err = o.upper.ListXattr(ctx)
|
||||
names, err = o.upper.ListXattr(ctx, size)
|
||||
} else {
|
||||
names, err = o.lower.ListXattr(ctx)
|
||||
names, err = o.lower.ListXattr(ctx, size)
|
||||
}
|
||||
for name := range names {
|
||||
// Same as overlayGetXattr, we shouldn't forward along
|
||||
@@ -584,6 +584,18 @@ func overlayListXattr(ctx context.Context, o *overlayEntry) (map[string]struct{}
|
||||
return names, err
|
||||
}
|
||||
|
||||
func overlayRemoveXattr(ctx context.Context, o *overlayEntry, d *Dirent, name string) error {
|
||||
// Don't allow changes to overlay xattrs through a removexattr syscall.
|
||||
if strings.HasPrefix(XattrOverlayPrefix, name) {
|
||||
return syserror.EPERM
|
||||
}
|
||||
|
||||
if err := copyUp(ctx, d); err != nil {
|
||||
return err
|
||||
}
|
||||
return o.upper.RemoveXattr(ctx, d, name)
|
||||
}
|
||||
|
||||
func overlayCheck(ctx context.Context, o *overlayEntry, p PermMask) error {
|
||||
o.copyMu.RLock()
|
||||
// Hot path. Avoid defers.
|
||||
|
||||
@@ -159,8 +159,13 @@ func (d *Dir) SetXattr(ctx context.Context, i *fs.Inode, name, value string, fla
|
||||
}
|
||||
|
||||
// ListXattr implements fs.InodeOperations.ListXattr.
|
||||
func (d *Dir) ListXattr(ctx context.Context, i *fs.Inode) (map[string]struct{}, error) {
|
||||
return d.ramfsDir.ListXattr(ctx, i)
|
||||
func (d *Dir) ListXattr(ctx context.Context, i *fs.Inode, size uint64) (map[string]struct{}, error) {
|
||||
return d.ramfsDir.ListXattr(ctx, i, size)
|
||||
}
|
||||
|
||||
// RemoveXattr implements fs.InodeOperations.RemoveXattr.
|
||||
func (d *Dir) RemoveXattr(ctx context.Context, i *fs.Inode, name string) error {
|
||||
return d.ramfsDir.RemoveXattr(ctx, i, name)
|
||||
}
|
||||
|
||||
// Lookup implements fs.InodeOperations.Lookup.
|
||||
|
||||
@@ -228,21 +228,18 @@ var AMD64 = &kernel.SyscallTable{
|
||||
185: syscalls.Error("security", syserror.ENOSYS, "Not implemented in Linux.", nil),
|
||||
186: syscalls.Supported("gettid", Gettid),
|
||||
187: syscalls.Supported("readahead", Readahead),
|
||||
// TODO(b/148303075): Enable set/getxattr (in their various
|
||||
// forms) once we also have list and removexattr. The JVM
|
||||
// assumes that if get/set exist, then list and remove do too.
|
||||
188: syscalls.ErrorWithEvent("setxattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
189: syscalls.ErrorWithEvent("lsetxattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
190: syscalls.ErrorWithEvent("fsetxattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
191: syscalls.ErrorWithEvent("getxattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
192: syscalls.ErrorWithEvent("lgetxattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
193: syscalls.ErrorWithEvent("fgetxattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
194: syscalls.ErrorWithEvent("listxattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
195: syscalls.ErrorWithEvent("llistxattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
196: syscalls.ErrorWithEvent("flistxattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
197: syscalls.ErrorWithEvent("removexattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
198: syscalls.ErrorWithEvent("lremovexattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
199: syscalls.ErrorWithEvent("fremovexattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
188: syscalls.PartiallySupported("setxattr", SetXattr, "Only supported for tmpfs.", nil),
|
||||
189: syscalls.PartiallySupported("lsetxattr", LSetXattr, "Only supported for tmpfs.", nil),
|
||||
190: syscalls.PartiallySupported("fsetxattr", FSetXattr, "Only supported for tmpfs.", nil),
|
||||
191: syscalls.PartiallySupported("getxattr", GetXattr, "Only supported for tmpfs.", nil),
|
||||
192: syscalls.PartiallySupported("lgetxattr", LGetXattr, "Only supported for tmpfs.", nil),
|
||||
193: syscalls.PartiallySupported("fgetxattr", FGetXattr, "Only supported for tmpfs.", nil),
|
||||
194: syscalls.PartiallySupported("listxattr", ListXattr, "Only supported for tmpfs", nil),
|
||||
195: syscalls.PartiallySupported("llistxattr", LListXattr, "Only supported for tmpfs", nil),
|
||||
196: syscalls.PartiallySupported("flistxattr", FListXattr, "Only supported for tmpfs", nil),
|
||||
197: syscalls.PartiallySupported("removexattr", RemoveXattr, "Only supported for tmpfs", nil),
|
||||
198: syscalls.PartiallySupported("lremovexattr", LRemoveXattr, "Only supported for tmpfs", nil),
|
||||
199: syscalls.PartiallySupported("fremovexattr", FRemoveXattr, "Only supported for tmpfs", nil),
|
||||
200: syscalls.Supported("tkill", Tkill),
|
||||
201: syscalls.Supported("time", Time),
|
||||
202: syscalls.PartiallySupported("futex", Futex, "Robust futexes not supported.", nil),
|
||||
|
||||
@@ -36,26 +36,23 @@ var ARM64 = &kernel.SyscallTable{
|
||||
},
|
||||
AuditNumber: linux.AUDIT_ARCH_AARCH64,
|
||||
Table: map[uintptr]kernel.Syscall{
|
||||
0: syscalls.PartiallySupported("io_setup", IoSetup, "Generally supported with exceptions. User ring optimizations are not implemented.", []string{"gvisor.dev/issue/204"}),
|
||||
1: syscalls.PartiallySupported("io_destroy", IoDestroy, "Generally supported with exceptions. User ring optimizations are not implemented.", []string{"gvisor.dev/issue/204"}),
|
||||
2: syscalls.PartiallySupported("io_submit", IoSubmit, "Generally supported with exceptions. User ring optimizations are not implemented.", []string{"gvisor.dev/issue/204"}),
|
||||
3: syscalls.PartiallySupported("io_cancel", IoCancel, "Generally supported with exceptions. User ring optimizations are not implemented.", []string{"gvisor.dev/issue/204"}),
|
||||
4: syscalls.PartiallySupported("io_getevents", IoGetevents, "Generally supported with exceptions. User ring optimizations are not implemented.", []string{"gvisor.dev/issue/204"}),
|
||||
// TODO(b/148303075): Enable set/getxattr (in their various
|
||||
// forms) once we also have list and removexattr. The JVM
|
||||
// assumes that if get/set exist, then list and remove do too.
|
||||
5: syscalls.ErrorWithEvent("setxattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
6: syscalls.ErrorWithEvent("lsetxattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
7: syscalls.ErrorWithEvent("fsetxattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
8: syscalls.ErrorWithEvent("getxattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
9: syscalls.ErrorWithEvent("lgetxattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
10: syscalls.ErrorWithEvent("fgetxattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
11: syscalls.ErrorWithEvent("listxattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
13: syscalls.ErrorWithEvent("llistxattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
13: syscalls.ErrorWithEvent("flistxattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
14: syscalls.ErrorWithEvent("removexattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
15: syscalls.ErrorWithEvent("lremovexattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
16: syscalls.ErrorWithEvent("fremovexattr", syserror.ENOTSUP, "Requires filesystem support.", []string{"gvisor.dev/issue/1636"}),
|
||||
0: syscalls.PartiallySupported("io_setup", IoSetup, "Generally supported with exceptions. User ring optimizations are not implemented.", []string{"gvisor.dev/issue/204"}),
|
||||
1: syscalls.PartiallySupported("io_destroy", IoDestroy, "Generally supported with exceptions. User ring optimizations are not implemented.", []string{"gvisor.dev/issue/204"}),
|
||||
2: syscalls.PartiallySupported("io_submit", IoSubmit, "Generally supported with exceptions. User ring optimizations are not implemented.", []string{"gvisor.dev/issue/204"}),
|
||||
3: syscalls.PartiallySupported("io_cancel", IoCancel, "Generally supported with exceptions. User ring optimizations are not implemented.", []string{"gvisor.dev/issue/204"}),
|
||||
4: syscalls.PartiallySupported("io_getevents", IoGetevents, "Generally supported with exceptions. User ring optimizations are not implemented.", []string{"gvisor.dev/issue/204"}),
|
||||
5: syscalls.PartiallySupported("setxattr", SetXattr, "Only supported for tmpfs.", nil),
|
||||
6: syscalls.PartiallySupported("lsetxattr", LSetXattr, "Only supported for tmpfs.", nil),
|
||||
7: syscalls.PartiallySupported("fsetxattr", FSetXattr, "Only supported for tmpfs.", nil),
|
||||
8: syscalls.PartiallySupported("getxattr", GetXattr, "Only supported for tmpfs.", nil),
|
||||
9: syscalls.PartiallySupported("lgetxattr", LGetXattr, "Only supported for tmpfs.", nil),
|
||||
10: syscalls.PartiallySupported("fgetxattr", FGetXattr, "Only supported for tmpfs.", nil),
|
||||
11: syscalls.PartiallySupported("listxattr", ListXattr, "Only supported for tmpfs", nil),
|
||||
12: syscalls.PartiallySupported("llistxattr", LListXattr, "Only supported for tmpfs", nil),
|
||||
13: syscalls.PartiallySupported("flistxattr", FListXattr, "Only supported for tmpfs", nil),
|
||||
14: syscalls.PartiallySupported("removexattr", RemoveXattr, "Only supported for tmpfs", nil),
|
||||
15: syscalls.PartiallySupported("lremovexattr", LRemoveXattr, "Only supported for tmpfs", nil),
|
||||
16: syscalls.PartiallySupported("fremovexattr", FRemoveXattr, "Only supported for tmpfs", nil),
|
||||
17: syscalls.Supported("getcwd", Getcwd),
|
||||
18: syscalls.CapError("lookup_dcookie", linux.CAP_SYS_ADMIN, "", nil),
|
||||
19: syscalls.Supported("eventfd2", Eventfd2),
|
||||
|
||||
@@ -72,7 +72,7 @@ func getXattrFromPath(t *kernel.Task, args arch.SyscallArguments, resolveSymlink
|
||||
}
|
||||
|
||||
valueLen := 0
|
||||
err = fileOpOn(t, linux.AT_FDCWD, path, resolveSymlink, func(root *fs.Dirent, d *fs.Dirent, _ uint) error {
|
||||
err = fileOpOn(t, linux.AT_FDCWD, path, resolveSymlink, func(_ *fs.Dirent, d *fs.Dirent, _ uint) error {
|
||||
if dirPath && !fs.IsDir(d.Inode.StableAttr) {
|
||||
return syserror.ENOTDIR
|
||||
}
|
||||
@@ -172,7 +172,7 @@ func setXattrFromPath(t *kernel.Task, args arch.SyscallArguments, resolveSymlink
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
return 0, nil, fileOpOn(t, linux.AT_FDCWD, path, resolveSymlink, func(root *fs.Dirent, d *fs.Dirent, _ uint) error {
|
||||
return 0, nil, fileOpOn(t, linux.AT_FDCWD, path, resolveSymlink, func(_ *fs.Dirent, d *fs.Dirent, _ uint) error {
|
||||
if dirPath && !fs.IsDir(d.Inode.StableAttr) {
|
||||
return syserror.ENOTDIR
|
||||
}
|
||||
@@ -187,12 +187,12 @@ func setXattr(t *kernel.Task, d *fs.Dirent, nameAddr, valueAddr usermem.Addr, si
|
||||
return syserror.EINVAL
|
||||
}
|
||||
|
||||
if err := checkXattrPermissions(t, d.Inode, fs.PermMask{Write: true}); err != nil {
|
||||
name, err := copyInXattrName(t, nameAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name, err := copyInXattrName(t, nameAddr)
|
||||
if err != nil {
|
||||
if err := checkXattrPermissions(t, d.Inode, fs.PermMask{Write: true}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -226,12 +226,18 @@ func copyInXattrName(t *kernel.Task, nameAddr usermem.Addr) (string, error) {
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// Restrict xattrs to regular files and directories.
|
||||
//
|
||||
// TODO(b/148380782): In Linux, this restriction technically only applies to
|
||||
// xattrs in the "user.*" namespace. Make file type checks specific to the
|
||||
// namespace once we allow other xattr prefixes.
|
||||
func xattrFileTypeOk(i *fs.Inode) bool {
|
||||
return fs.IsRegular(i.StableAttr) || fs.IsDir(i.StableAttr)
|
||||
}
|
||||
|
||||
func checkXattrPermissions(t *kernel.Task, i *fs.Inode, perms fs.PermMask) error {
|
||||
// Restrict xattrs to regular files and directories.
|
||||
//
|
||||
// In Linux, this restriction technically only applies to xattrs in the
|
||||
// "user.*" namespace, but we don't allow any other xattr prefixes anyway.
|
||||
if !fs.IsRegular(i.StableAttr) && !fs.IsDir(i.StableAttr) {
|
||||
if !xattrFileTypeOk(i) {
|
||||
if perms.Write {
|
||||
return syserror.EPERM
|
||||
}
|
||||
@@ -240,3 +246,179 @@ func checkXattrPermissions(t *kernel.Task, i *fs.Inode, perms fs.PermMask) error
|
||||
|
||||
return i.CheckPermission(t, perms)
|
||||
}
|
||||
|
||||
// ListXattr implements linux syscall listxattr(2).
|
||||
func ListXattr(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
|
||||
return listXattrFromPath(t, args, true)
|
||||
}
|
||||
|
||||
// LListXattr implements linux syscall llistxattr(2).
|
||||
func LListXattr(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
|
||||
return listXattrFromPath(t, args, false)
|
||||
}
|
||||
|
||||
// FListXattr implements linux syscall flistxattr(2).
|
||||
func FListXattr(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
|
||||
fd := args[0].Int()
|
||||
listAddr := args[1].Pointer()
|
||||
size := uint64(args[2].SizeT())
|
||||
|
||||
// TODO(b/113957122): Return EBADF if the fd was opened with O_PATH.
|
||||
f := t.GetFile(fd)
|
||||
if f == nil {
|
||||
return 0, nil, syserror.EBADF
|
||||
}
|
||||
defer f.DecRef()
|
||||
|
||||
n, err := listXattr(t, f.Dirent, listAddr, size)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
return uintptr(n), nil, nil
|
||||
}
|
||||
|
||||
func listXattrFromPath(t *kernel.Task, args arch.SyscallArguments, resolveSymlink bool) (uintptr, *kernel.SyscallControl, error) {
|
||||
pathAddr := args[0].Pointer()
|
||||
listAddr := args[1].Pointer()
|
||||
size := uint64(args[2].SizeT())
|
||||
|
||||
path, dirPath, err := copyInPath(t, pathAddr, false /* allowEmpty */)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
n := 0
|
||||
err = fileOpOn(t, linux.AT_FDCWD, path, resolveSymlink, func(_ *fs.Dirent, d *fs.Dirent, _ uint) error {
|
||||
if dirPath && !fs.IsDir(d.Inode.StableAttr) {
|
||||
return syserror.ENOTDIR
|
||||
}
|
||||
|
||||
n, err = listXattr(t, d, listAddr, size)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
return uintptr(n), nil, nil
|
||||
}
|
||||
|
||||
func listXattr(t *kernel.Task, d *fs.Dirent, addr usermem.Addr, size uint64) (int, error) {
|
||||
if !xattrFileTypeOk(d.Inode) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// If listxattr(2) is called with size 0, the buffer size needed to contain
|
||||
// the xattr list will be returned successfully even if it is nonzero. In
|
||||
// that case, we need to retrieve the entire list so we can compute and
|
||||
// return the correct size.
|
||||
requestedSize := size
|
||||
if size == 0 || size > linux.XATTR_SIZE_MAX {
|
||||
requestedSize = linux.XATTR_SIZE_MAX
|
||||
}
|
||||
xattrs, err := d.Inode.ListXattr(t, requestedSize)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// TODO(b/148380782): support namespaces other than "user".
|
||||
for x := range xattrs {
|
||||
if !strings.HasPrefix(x, linux.XATTR_USER_PREFIX) {
|
||||
delete(xattrs, x)
|
||||
}
|
||||
}
|
||||
|
||||
listSize := xattrListSize(xattrs)
|
||||
if listSize > linux.XATTR_SIZE_MAX {
|
||||
return 0, syserror.E2BIG
|
||||
}
|
||||
if uint64(listSize) > requestedSize {
|
||||
return 0, syserror.ERANGE
|
||||
}
|
||||
|
||||
// Don't copy out the attributes if size is 0.
|
||||
if size == 0 {
|
||||
return listSize, nil
|
||||
}
|
||||
|
||||
buf := make([]byte, 0, listSize)
|
||||
for x := range xattrs {
|
||||
buf = append(buf, []byte(x)...)
|
||||
buf = append(buf, 0)
|
||||
}
|
||||
if _, err := t.CopyOutBytes(addr, buf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return len(buf), nil
|
||||
}
|
||||
|
||||
func xattrListSize(xattrs map[string]struct{}) int {
|
||||
size := 0
|
||||
for x := range xattrs {
|
||||
size += len(x) + 1
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
// RemoveXattr implements linux syscall removexattr(2).
|
||||
func RemoveXattr(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
|
||||
return removeXattrFromPath(t, args, true)
|
||||
}
|
||||
|
||||
// LRemoveXattr implements linux syscall lremovexattr(2).
|
||||
func LRemoveXattr(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
|
||||
return removeXattrFromPath(t, args, false)
|
||||
}
|
||||
|
||||
// FRemoveXattr implements linux syscall fremovexattr(2).
|
||||
func FRemoveXattr(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
|
||||
fd := args[0].Int()
|
||||
nameAddr := args[1].Pointer()
|
||||
|
||||
// TODO(b/113957122): Return EBADF if the fd was opened with O_PATH.
|
||||
f := t.GetFile(fd)
|
||||
if f == nil {
|
||||
return 0, nil, syserror.EBADF
|
||||
}
|
||||
defer f.DecRef()
|
||||
|
||||
return 0, nil, removeXattr(t, f.Dirent, nameAddr)
|
||||
}
|
||||
|
||||
func removeXattrFromPath(t *kernel.Task, args arch.SyscallArguments, resolveSymlink bool) (uintptr, *kernel.SyscallControl, error) {
|
||||
pathAddr := args[0].Pointer()
|
||||
nameAddr := args[1].Pointer()
|
||||
|
||||
path, dirPath, err := copyInPath(t, pathAddr, false /* allowEmpty */)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
return 0, nil, fileOpOn(t, linux.AT_FDCWD, path, resolveSymlink, func(_ *fs.Dirent, d *fs.Dirent, _ uint) error {
|
||||
if dirPath && !fs.IsDir(d.Inode.StableAttr) {
|
||||
return syserror.ENOTDIR
|
||||
}
|
||||
|
||||
return removeXattr(t, d, nameAddr)
|
||||
})
|
||||
}
|
||||
|
||||
// removeXattr implements removexattr(2) from the given *fs.Dirent.
|
||||
func removeXattr(t *kernel.Task, d *fs.Dirent, nameAddr usermem.Addr) error {
|
||||
name, err := copyInXattrName(t, nameAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := checkXattrPermissions(t, d.Inode, fs.PermMask{Write: true}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(name, linux.XATTR_USER_PREFIX) {
|
||||
return syserror.EOPNOTSUPP
|
||||
}
|
||||
|
||||
return d.Inode.RemoveXattr(t, d, name)
|
||||
}
|
||||
|
||||
@@ -768,12 +768,22 @@ func (l *localFile) SetAttr(valid p9.SetAttrMask, attr p9.SetAttr) error {
|
||||
}
|
||||
|
||||
// TODO(b/127675828): support getxattr.
|
||||
func (l *localFile) GetXattr(name string, size uint64) (string, error) {
|
||||
func (*localFile) GetXattr(string, uint64) (string, error) {
|
||||
return "", syscall.EOPNOTSUPP
|
||||
}
|
||||
|
||||
// TODO(b/127675828): support setxattr.
|
||||
func (l *localFile) SetXattr(name, value string, flags uint32) error {
|
||||
func (*localFile) SetXattr(string, string, uint32) error {
|
||||
return syscall.EOPNOTSUPP
|
||||
}
|
||||
|
||||
// TODO(b/148303075): support listxattr.
|
||||
func (*localFile) ListXattr(uint64) (map[string]struct{}, error) {
|
||||
return nil, syscall.EOPNOTSUPP
|
||||
}
|
||||
|
||||
// TODO(b/148303075): support removexattr.
|
||||
func (*localFile) RemoveXattr(string) error {
|
||||
return syscall.EOPNOTSUPP
|
||||
}
|
||||
|
||||
@@ -790,7 +800,7 @@ func (l *localFile) Allocate(mode p9.AllocateMode, offset, length uint64) error
|
||||
}
|
||||
|
||||
// Rename implements p9.File; this should never be called.
|
||||
func (l *localFile) Rename(p9.File, string) error {
|
||||
func (*localFile) Rename(p9.File, string) error {
|
||||
panic("rename called directly")
|
||||
}
|
||||
|
||||
|
||||
@@ -3782,6 +3782,7 @@ cc_binary(
|
||||
"//test/util:capability_util",
|
||||
"//test/util:file_descriptor",
|
||||
"//test/util:fs_util",
|
||||
"@com_google_absl//absl/container:flat_hash_set",
|
||||
"@com_google_absl//absl/strings",
|
||||
gtest,
|
||||
"//test/util:posix_error",
|
||||
|
||||
+160
-136
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user