Files
Ayush RanjanandgVisor bot 6b2855f537 gofer: Add full xattr support.
- gofer client: Added an xattr cache on the inode struct. In case the gofer
  mount being used is exclusive (cachedMetadataAuthoritative() == true), we
  cache positive and negative xattr queries.
- Subsequently, we now hold metadataMu for the entire duration of xattr
  operations. This is important to avoid stale updates in the xattr cache due
  to concurrent xattr operations. This is the same approach we take for
  maintaining other inode metadata in the inode struct.
- Added support for setxattr/removexattr/listxattr in runsc/fsgofer and gofer
  client (when using directfs). Consequently the seccomp filters for sandbox
  and gofer processes were expanded to allow these syscalls.
- Added xattr syscall tests to //test/syscalls/BUILD so they are run on
  BuildKite on presubmits. (Also fixed up some tests.)

A note about performance:

The default rootfs configuration for runsc enables rootfs overlay. In that, the
gofer mount is an exclusive mount on the lower layer. fsimpl/overlay issues a
lot of getxattr calls on the lower layer to check for opaque directory xattr.
However, as before, the "trusted" xattr namespace is not supported. So all
those calls continue to fail with EOPNOTSUPP. So this should not regress rootfs
overlay performance.

When using an overlay where gofer is the upper layer or when "userxattr" mount
option is in effect, fsimpl/overlay will similarly issue a lot of getxattr
calls using the "user" xattr namespace. This will be allowed by
checkXattrPermissions(). To optimize the common case where directories are not
opaque, we specially track `overlayOpaqueNegative` in `xattrCache`. This avoids
a map allocation during xattrCache.addNegative().

Updates #12475
Updates #12828

PiperOrigin-RevId: 915097116
2026-05-13 15:42:32 -07:00

151 lines
3.5 KiB
Python

load("//tools:defs.bzl", "go_library", "go_test")
load("//tools/go_generics:defs.bzl", "go_template_instance")
package(default_applicable_licenses = ["//:license"])
licenses(["notice"])
go_template_instance(
name = "inode_refs",
out = "inode_refs.go",
package = "gofer",
prefix = "inode",
template = "//pkg/refs:refs_template",
types = {
"T": "inode",
},
)
go_template_instance(
name = "string_list",
out = "string_list.go",
package = "gofer",
prefix = "string",
template = "//pkg/ilist:generic_list",
types = {
"Element": "*stringListElem",
"Linker": "*stringListElem",
},
)
go_template_instance(
name = "dentry_list",
out = "dentry_list.go",
package = "gofer",
prefix = "dentry",
template = "//pkg/ilist:generic_list",
types = {
"Element": "*dentryListElem",
"Linker": "*dentryListElem",
},
)
go_template_instance(
name = "special_fd_list",
out = "special_fd_list.go",
package = "gofer",
prefix = "specialFD",
template = "//pkg/ilist:generic_list",
types = {
"Element": "*specialFileFD",
"Linker": "*specialFileFD",
},
)
go_template_instance(
name = "fstree",
out = "fstree.go",
package = "gofer",
prefix = "generic",
template = "//pkg/sentry/vfs/genericfstree:generic_fstree",
types = {
"Dentry": "dentry",
"Filesystem": "filesystem",
},
)
go_library(
name = "gofer",
srcs = [
"dentry_list.go",
"directfs_inode.go",
"directory.go",
"filesystem.go",
"fstree.go",
"gofer.go",
"handle.go",
"host_named_pipe.go",
"inode_impl.go",
"inode_refs.go",
"lisafs_inode.go",
"regular_file.go",
"revalidate.go",
"save_restore.go",
"socket.go",
"special_fd_list.go",
"special_file.go",
"string_list.go",
"symlink.go",
"time.go",
"xattr.go",
],
visibility = ["//pkg/sentry:internal"],
deps = [
"//pkg/abi/linux",
"//pkg/atomicbitops",
"//pkg/cleanup",
"//pkg/context",
"//pkg/errors/linuxerr",
"//pkg/fd",
"//pkg/fdnotifier",
"//pkg/fspath",
"//pkg/fsutil",
"//pkg/hostarch",
"//pkg/lisafs",
"//pkg/log",
"//pkg/marshal",
"//pkg/marshal/primitive",
"//pkg/metric",
"//pkg/rand",
"//pkg/refs",
"//pkg/safemem",
"//pkg/sentry/checkpoint",
"//pkg/sentry/fsimpl/host",
"//pkg/sentry/fsimpl/lock",
"//pkg/sentry/fsmetric",
"//pkg/sentry/fsutil",
"//pkg/sentry/hostfd",
"//pkg/sentry/kernel",
"//pkg/sentry/kernel/auth",
"//pkg/sentry/kernel/pipe",
"//pkg/sentry/ktime",
"//pkg/sentry/memmap",
"//pkg/sentry/pgalloc",
"//pkg/sentry/platform",
"//pkg/sentry/socket/control",
"//pkg/sentry/socket/unix",
"//pkg/sentry/socket/unix/transport",
"//pkg/sentry/usage",
"//pkg/sentry/vfs",
"//pkg/sync",
"//pkg/syserr",
"//pkg/unet",
"//pkg/usermem",
"//pkg/waiter",
"@org_golang_x_sys//unix:go_default_library",
],
)
go_test(
name = "gofer_test",
srcs = ["gofer_test.go"],
library = ":gofer",
deps = [
"//pkg/abi/linux",
"//pkg/lisafs",
"//pkg/sentry/contexttest",
"//pkg/sentry/ktime",
"//pkg/sentry/pgalloc",
],
)