- Add type parameter Filesystem to vfs/genericfstree, which is required to
provide `ancestryMu sync.RWMutex`, and add such a RWMutex to all FSImpls that
use genericfstree.
- Modify genericfstree.PrependPath() and genericfstree.IsDescendant() to use
ancestryMu to ensure atomicity. For callers of genericfstree.PrependPath(),
this means that (broader) FSImpl locks no longer need to be held during the
call. For callers of genericfstree.IsDescendant(), this means that we can
remove documentation warnings about its non-atomicity.
- Minor cleanup: Remove useless variable `start`, which is always 0, from
MM.ReadMaps/SmapsDataInto().
PiperOrigin-RevId: 696713993
fchdir(2) was only needed to support connect(2) and bind(2), which are the
only filesystem operations that force host path traversal. The sandbox process
does not have the container filesystem in its mount namespace. It does not even
have procfs, so we can't use a path like /proc/self/fd/{socket-fd}. So earlier
we were using fchdir(2) to go into the socket's parent directory and use a
relative path.
However, allowing fchdir(2) makes it harder to reason about the sandbox process
state because it modifies the process's CWD. Directfs seccomp filters today do
not allow the usage of AT_FDCWD, but that could change in the future.
Operations that rely on the sandbox CWD need to synchronize using
pkg/sentry/fsutil/chdir package, like directfs does today. If they don't then
we could have nasty bugs.
Now we fallback to using LISAFS in such scenarios. This makes bind(2) and
connect(2) a little slower because now directfs has to perform a LISAFS walk
to get a LISAFS FD to the socket and then make the Connect/Bind RPC. But this
allows us to remove fchdir, socket, connect, bind, listen and accept from the
directfs seccomp filters. The rationale is that if making 2 relatively-rare
operations slightly slower helps us avoid chdir(2) and these other socket-based
syscalls, then it is overall a win.
Reported-by: Etienne Perot <eperot@google.com>
PiperOrigin-RevId: 516931050
We can achieve this by opening the current working directory for the sandbox
process right before the application starts. We use this cached FD to restore
CWD after DoInDir() operations.
Since the package which provides DoInDir() has to be aware of the sandbox
process and requirements around initializing the CWD, I have moved this to
pkg/sentry/fsutil - which can contain sentry aware code.
This will be used by directfs. This helps because this allows us to block
AT_FDCWD in directfs seccomp filters.
PiperOrigin-RevId: 513409592
Directfs accesses host filesystem directly, without going through the gofer
server. This change basically adds runsc fsgofer functionality into the gofer
client. We use the gofer dentry impl abstraction to make direct host syscalls
instead of making LISAFS RPCs. It works on a donated FD to the root of the
mount. All other relevant mount options supported in gofer client are also
supported here.
Directfs is also a lisafs user. Directfs client makes a Mount RPC. The server
is expected to donate a host FD to the mount point that the client can use to
perform all necessary filesystem operations. Directfs client does not set up
any flipcall channels, because it (mostly) doesn't make any RPCs.
Note however that we can not avoid LISAFS RPCs in certain cases. Certain
operations like bind(2) and connect(2) require host paths. But the container
filesystem is not mounted inside the sandbox's mount namespace. The sandbox
just has an FD to the filesystem root. Furthermore, procfs is also not mounted
in the sandbox process for security reasons. Otherwise we could have used host
paths like `/proc/self/fd/<sockFD>`. The only viable option is to use fchdir(2)
to change working directory to the socket's parent directory and use a relative
host path from there. But in certain situations, we don't even have access to
a socket's parent directory (in case of a socket mount point). The parent lives
in a different gofer mount in the sentry. There is no clean way of fetching
that. In these extreme corner cases, directfs falls back to using LISAFS RPCs.
These corner cases are:
- chmod(2) on mount point socket.
- utimensat(2) on mount point symlink.
- connect(2) on mount point socket.
PiperOrigin-RevId: 510465837
This introduces a new gofer.dentry.impl field which can hold dentry
implementation specific details. For now there exists only one implementation,
which is a lisafs dentry.
This work is in preparation for adding a direct host dentry implementation,
which will make host syscalls instead of making RPCs.
This change should have no change in behavior or performance.
PiperOrigin-RevId: 503203994
fs.syncableDentries saves all non-synthetic dentries. This requires a map insert
operation every time a new dentry is created and map removal operation when a
dentry is destroyed. This can be expensive there can be a very large number of
non-synthetic dentries.
Using a map does not provide any additional benefits. We do not require lookup.
Instead use a linked list, as insert and remove are really fast and it allows us
to iterate on the list. It also saves the heap allocations to maintain the map.
Also simplify pkg/state to not use a custom ElementMapper. There is no need to.
PiperOrigin-RevId: 476145150
When the server does not provide these values, they should be
initialized to something sensible. This is consistent with VFS1.
PiperOrigin-RevId: 464433106
All atomic 64 bit ints are changed to atomicbitops.(Ui|I)nt64. A nogo checker
enforces that sync/atomic 64 bit functions are not called.
For reviewers: the interesting changes are in the atomicbitops and checkaligned
packages.
Why do this?
- It is very easy to accidentally use atomic values without sync/atomic funcs.
- We have checkatomics, but this is optional and is forgotten in several places.
- Using a type+checker to enforce this seems less error prone and simpler.
- We get NoCopy protection.
- Use of 64 bit atomics can break 32 bit builds. We have types to handle this
without any runtime cost, so we might as well use them.
PiperOrigin-RevId: 440473398
Introduces RPC methods in lisafs. Makes that gofer client use lisafs RPCs
instead of p9 when lisafs is enabled.
Implements the handlers for those methods in fsgofer.
Fixes#5465
PiperOrigin-RevId: 398080310
Removes package syserror and moves still relevant code to either linuxerr
or to syserr (to be later removed).
Internal errors are converted from random types to *errors.Error types used
in linuxerr. Internal errors are in linuxerr/internal.go.
PiperOrigin-RevId: 390724202
Add Equals method to compare syserror and unix.Errno errors to linuxerr errors.
This will facilitate removal of syserror definitions in a followup, and
finding needed conversions from unix.Errno to linuxerr.
PiperOrigin-RevId: 380909667
While using remote-validation, the vast majority of time spent during
FS operations is re-walking the path to check for modifications and
then closing the file given that in most cases it has not been
modified externally.
This change introduces a new 9P message called MultiGetAttr which bulks
query attributes of several files in one shot. The returned attributes are
then used to update cached dentries before they are walked. File attributes
are updated for files that still exist. Dentries that have been deleted are
removed from the cache. And negative cache entries are removed if a new
file/directory was created externally. Similarly, synthetic dentries are
replaced if a file/directory is created externally.
The bulk update needs to be carefull not to follow symlinks, cross mount
points, because the gofer doesn't know how to resolve symlinks and where
mounts points are located. It also doesn't walk to the parent ("..") to
avoid deadlocks.
Here are the results:
Workload VFS1 VFS2 Change
bazel action 115s 70s 28.8s
Stat/100 11,043us 7,623us 974us
Updates #1638
PiperOrigin-RevId: 369325957