Age | Commit message (Collapse) | Author |
|
Our current reference leak checker uses finalizers to verify whether an object
has reached zero references before it is garbage collected. There are multiple
problems with this mechanism, so a rewrite is in order.
With finalizers, there is no way to guarantee that a finalizer will run before
the program exits. When an unreachable object with a finalizer is garbage
collected, its finalizer will be added to a queue and run asynchronously. The
best we can do is run garbage collection upon sandbox exit to make sure that
all finalizers are enqueued.
Furthermore, if there is a chain of finalized objects, e.g. A points to B
points to C, garbage collection needs to run multiple times before all of the
finalizers are enqueued. The first GC run will register the finalizer for A but
not free it. It takes another GC run to free A, at which point B's finalizer
can be registered. As a result, we need to run GC as many times as the length
of the longest such chain to have a somewhat reliable leak checker.
Finally, a cyclical chain of structs pointing to one another will never be
garbage collected if a finalizer is set. This is a well-known issue with Go
finalizers (https://github.com/golang/go/issues/7358). Using leak checking on
filesystem objects that produce cycles will not work and even result in memory
leaks.
The new leak checker stores reference counted objects in a global map when
leak check is enabled and removes them once they are destroyed. At sandbox
exit, any remaining objects in the map are considered as leaked. This provides
a deterministic way of detecting leaks without relying on the complexities of
finalizers and garbage collection.
This approach has several benefits over the former, including:
- Always detects leaks of objects that should be destroyed very close to
sandbox exit. The old checker very rarely detected these leaks, because it
relied on garbage collection to be run in a short window of time.
- Panics if we forgot to enable leak check on a ref-counted object (we will try
to remove it from the map when it is destroyed, but it will never have been
added).
- Can store extra logging information in the map values without adding to the
size of the ref count struct itself. With the size of just an int64, the ref
count object remains compact, meaning frequent operations like IncRef/DecRef
are more cache-efficient.
- Can aggregate leak results in a single report after the sandbox exits.
Instead of having warnings littered in the log, which were
non-deterministically triggered by garbage collection, we can print all
warning messages at once. Note that this could also be a limitation--the
sandbox must exit properly for leaks to be detected.
Some basic benchmarking indicates that this change does not significantly
affect performance when leak checking is enabled, which is understandable
since registering/unregistering is only done once for each filesystem object.
Updates #1486.
PiperOrigin-RevId: 338685972
|
|
Reported-by: syzbot+078580ce5dd6d607fcd8@syzkaller.appspotmail.com
Reported-by: syzbot+2096681f6891e7bf8aed@syzkaller.appspotmail.com
PiperOrigin-RevId: 337973519
|
|
- Check the sticky bit in overlay.filesystem.UnlinkAt(). Fixes
StickyTest.StickyBitPermDenied.
- When configuring a VFS2 overlay in runsc, copy the lower layer's root
owner/group/mode to the upper layer's root (as in the VFS1 equivalent,
boot.addOverlay()). This makes the overlay root owned by UID/GID 65534 with
mode 0755 rather than owned by UID/GID 0 with mode 01777. Fixes
CreateTest.CreateFailsOnUnpermittedDir, which assumes that the test cannot
create files in /.
- MknodTest.UnimplementedTypesReturnError assumes that the creation of device
special files is not supported. However, while the VFS2 gofer client still
doesn't support device special files, VFS2 tmpfs does, and in the overlay
test dimension mknod() targets a tmpfs upper layer. The test initially has
all capabilities, including CAP_MKNOD, so its creation of these files
succeeds. Constrain these tests to VFS1.
- Rename overlay.nonDirectoryFD to overlay.regularFileFD and only use it for
regular files, using the original FD for pipes and device special files. This
is more consistent with Linux (which gets the original inode_operations, and
therefore file_operations, for these file types from ovl_fill_inode() =>
init_special_inode()) and fixes remaining mknod and pipe tests.
- Read/write 1KB at a time in PipeTest.Streaming, rather than 4 bytes. This
isn't strictly necessary, but it makes the test less obnoxiously slow on
ptrace.
Fixes #4407
PiperOrigin-RevId: 337971042
|
|
PiperOrigin-RevId: 337919424
|
|
PiperOrigin-RevId: 337384146
|
|
The sentry page cache stores file contents at page granularity; this is
necessary for memory mappings. Thus file offset ranges passed to
fsutil.FileRangeSet.Fill() must be page-aligned. If the read callback passed to
Fill() returns (partial read, nil error) when reading up to EOF (which is the
case for p9.ClientFile.ReadAt() since 9P's Rread cannot convey both a partial
read and EOF), Fill() will re-invoke the read callback to try to read from EOF
to the end of the containing page, which is harmless but needlessly expensive.
Fix this by handling file size explicitly in fsutil.FileRangeSet.Fill().
PiperOrigin-RevId: 336934075
|
|
This fixes reference leaks related to accidentally forgetting to DecRef()
after calling one or the other.
PiperOrigin-RevId: 336918922
|
|
In addition to fixing reference leaks, this change also releases memory used
by regular tmpfs files once the containing filesystem is released.
PiperOrigin-RevId: 336833111
|
|
Singleton filesystem like devpts and devtmpfs have a single filesystem shared
among all mounts, so they acquire a "self-reference" when initialized that
must be released when the entire virtual filesystem is released at sandbox
exit.
PiperOrigin-RevId: 336828852
|
|
verity Mu should be per file system instead of global, so that enabling
and verifying in different file systems won't block each other.
Also Lock verity Mu in PRead.
PiperOrigin-RevId: 336779356
|
|
Merkle tree library was originally using Read/Seek to access data and
tree, since the parameters are io.ReadSeeker. This could cause race
conditions if multiple threads accesses the same fd to read. Here we
change to use ReaderAt, and implement it with PRead to make it thread
safe.
PiperOrigin-RevId: 336779260
|
|
This change aims to fix the memory leak issue reported inĀ #3933.
Background:
VFS2 kernfs kept accumulating invalid dentries if those dentries were not
walked on. After substantial consideration of the problem by our team, we
decided to have an LRU cache solution. This change is the first part to that
solution, where we don't cache anything. The LRU cache can be added on top of
this.
What has changed:
- Introduced the concept of an inode tree in kernfs.OrderedChildren.
This is helpful is cases where the lifecycle of an inode is different from
that of a dentry.
- OrderedChildren now deals with initialized inodes instead of initialized
dentries. It now implements Lookup() where it constructs a new dentry
using the inode.
- OrderedChildren holds a ref on all its children inodes. With this change,
now an inode can "outlive" a dentry pointing to it. See comments in
kernfs.OrderedChildren.
- The kernfs dentry tree is solely maintained by kernfs only. Inode
implementations can not modify the dentry tree.
- Dentries that reach ref count 0 are removed from the dentry tree.
- revalidateChildLocked now defer-DecRefs the newly created dentry from
Inode.Lookup(), limiting its life to the current filesystem operation. If
refs are picked on the dentry during the FS op (via an FD or something),
then it will stick around and will be removed when the FD is closed. So there
is essentially _no caching_ for Look()ed up dentries.
- kernfs.DecRef does not have the precondition that fs.mu must be locked.
Fixes #3933
PiperOrigin-RevId: 336768576
|
|
PiperOrigin-RevId: 336395445
|
|
- When the KCOV_ENABLE_TRACE ioctl is called with the trace kind KCOV_TRACE_PC,
the kcov mode should be set to KCOV_*MODE*_TRACE_PC.
- When the owning task of kcov exits, the memory mapping should not be cleared
so it can be used by other tasks.
- Add more tests (also tested on native Linux kcov).
PiperOrigin-RevId: 335202585
|
|
PiperOrigin-RevId: 335077195
|
|
When a child's root hash or its Merkle path is modified in its parent's
Merkle tree file, opening the file should fail, provided the directory
is verity enabled. The test for this behavior is added.
PiperOrigin-RevId: 334963690
|
|
PiperOrigin-RevId: 334721453
|
|
PiperOrigin-RevId: 334682753
|
|
PiperOrigin-RevId: 334678513
|
|
PiperOrigin-RevId: 334656292
|
|
The tests confirms that when a file is opened in verity, the
corresponding Merkle trees are generated. Also a normal read succeeds on
verity enabled files, but fails if either the verity file or the Merkle
tree file is modified.
PiperOrigin-RevId: 334640331
|
|
PiperOrigin-RevId: 334478850
|
|
Fixes #1479, #317.
PiperOrigin-RevId: 334258052
|
|
Do not release dirMu between checking whether to create a child and actually
inserting it.
Also fixes a bug in fusefs which was causing it to deadlock under the new
lock ordering. We do not need to call kernfs.Dentry.InsertChild from newEntry
because it will always be called at the kernfs filesystem layer.
Updates #1193.
PiperOrigin-RevId: 334049264
|
|
The FD should hold a reference on the dentry they were opened on which in turn
holds a reference on the inode it points to.
PiperOrigin-RevId: 333589223
|
|
Update signatures for:
- All methods in inodeDirectory
- deferDecRef() and Filesystem.droppedDentries
- newSyntheticDirectory()
- `slot`s used in OrderedChildren and subsequent methods like
replaceChildLocked() and checkExistingLocked()
- stepExistingLocked(), walkParentDirLocked(), checkCreateLocked()
Updates #1193
PiperOrigin-RevId: 333558866
|
|
Updates #1663
PiperOrigin-RevId: 333539293
|
|
It is called from the kernfs code (OpenAt and revalidateChildLocked()).
For RemoveChildLocked, it is opposed. We need to call it from fuse.RmDir and
fuse.Unlink.
PiperOrigin-RevId: 333453218
|
|
There were some instances where we were not enabling leak checking.
PiperOrigin-RevId: 333418571
|
|
PiperOrigin-RevId: 333412836
|
|
PiperOrigin-RevId: 333404727
|
|
Update signatures for:
- walkExistingLocked
- checkDeleteLocked
- Inode.Open
Updates #1193
PiperOrigin-RevId: 333163381
|
|
Originally, we avoided partial writes in case it caused us to write a partial
packet to a socket-backed specialFileFD. However, this check causes splicing
from a pipe to specialFileFD to fail if we hit EOF on the pipe.
PiperOrigin-RevId: 333016216
|
|
Updates #1193.
PiperOrigin-RevId: 332939026
|
|
PiperOrigin-RevId: 332760843
|
|
Updates #1199
PiperOrigin-RevId: 332539197
|
|
This is more consistent with Linux (see comment on MM.NewSharedAnonMappable()).
We don't do the same thing on VFS1 for reasons documented by the updated
comment.
PiperOrigin-RevId: 332514849
|
|
PiperOrigin-RevId: 332486111
|
|
This fixes a use-after-free in fuse.DeviceFD.Release.
PiperOrigin-RevId: 332394146
|
|
This constant is used to represent int32 stored in file xattrs. The
integers are stored as strings there, so the real size should be the
string size (number of digits) instead of an int size (4 bytes).
PiperOrigin-RevId: 332353217
|
|
PiperOrigin-RevId: 332340342
|
|
This change includes overlay, special regular gofer files, and hostfs.
Fixes #3589.
PiperOrigin-RevId: 332330860
|
|
|
|
As noticed by @ayushr2, the "implements" comments are not
consistent, e.g.
// IterDirents implements kernfs.inodeDynamicLookup.
// Generate implements vfs.DynamicBytesSource.Generate.
This patch improves this by making the comments like this
consistently include the package name (when the interface
and struct are not in the same package) and method name.
Signed-off-by: Tiwei Bie <tiwei.btw@antgroup.com>
|
|
PiperOrigin-RevId: 332122081
|
|
OpenAt() for verity fs is implemented by opening both the target file or
directory and the corresponding Merkle tree file in the underlying file
system. Generally they are only open for read. In allowRuntimeEnable
mode, the Merkle tree file is also open for write.
PiperOrigin-RevId: 332116423
|
|
PRead is implemented by read from the underlying file in blocks, and
verify each block. The verified contents are saved into the output
buffer.
PiperOrigin-RevId: 332092267
|
|
fix #3956
|
|
fix #3963
|
|
|