Commit Graph
44 Commits
Author SHA1 Message Date
Andrei VaginandgVisor bot 890a66acd4 fdtable: avoid large arrays
FDTable.descriptorTable is a slice of unsafe.Pointer-s and its maximum length
is MaxInt32. It requires up to 16GB of memory. A process can use just a few
descriptors but sets one or more of them to high numbers. In this case,
FDTable.descriptorTable is extended to the maximum size.

The problem here is that go-runtime zeros memory regions when they are reused.
In the case of fdtable, the memory region is 16GB, so it is a time consuming
operation. Second, it forces the kernel to allocate physical pages to
the entire region.

This change adds another level to descriptorTable, so the first level is
a slice of buckets where each bucket is a slice of descriptors. The bucket
size is fixed to 512 entries to fit one page.

Before:
BenchmarkFDLookupAndDecRef-12              	50834290	        23.70 ns/op
BenchmarkCreateWithMaxFD-12                	       2	7194873988 ns/op
BenchmarkFDLookupAndDecRefConcurrent-12    	23775555	        49.68 ns/op
BenchmarkTableLookup-12                    	412888780	         2.835 ns/op
BenchmarkTableMapLookup-12                 	87944782	        12.84 ns/op

After:
BenchmarkFDLookupAndDecRef-12              	46229940	        25.03 ns/op
BenchmarkCreateWithMaxFD-12                	      13	  82573899 ns/op
BenchmarkFDLookupAndDecRefConcurrent-12    	21889380	        54.13 ns/op
BenchmarkTableLookup-12                    	415851230	         2.821 ns/op
BenchmarkTableMapLookup-12                 	97236267	        11.89 ns/op

Reported-by: [email protected]
PiperOrigin-RevId: 539138632
2023-06-09 11:49:28 -07:00
Fabricio VoznikaandgVisor bot 11154ce7f1 Fix crash with large FD value
There were 2 problems when trying to allocate a high FD value:
- Rlimit is stored as uint64 and could be truncated when converting to int32
  to calculate the max value allowed for the FD.
- While trying to double the FD table size, the new length for the table could
  end up short due to invalid type convertion again.

Reported-by: [email protected]
PiperOrigin-RevId: 518362257
2023-03-21 13:21:27 -07:00
Kevin KrakauerandgVisor bot f5c38f9275 don't take an unnecessary reference in proc.fdSymlink.Valid()
Reported-by: [email protected]
PiperOrigin-RevId: 510454946
2023-02-17 09:51:21 -08:00
Ayush RanjanandgVisor bot 1003ae8e93 Delete VFS1 completely.
- Delete pkg/sentry/fs/*.
- Move pkg/sentry/fs/fsutil out of VFS1 directory and remove VFS1 components.
- Remove remaining unused references to VFS1 from remaining codebase.
- Rename/refactor code to avoid even referencing VFS2, unless necessary.
- Rewrite VFS1-only tests to VFS2.

Updates #1624

PiperOrigin-RevId: 490064269
2022-11-21 13:57:52 -08:00
Ayush RanjanandgVisor bot ee523cfbc7 Delete VFS1 filesystem implementations.
Updates #1624

PiperOrigin-RevId: 488986080
2022-11-16 11:05:10 -08:00
Ayush RanjanandgVisor bot 3948850b0b Update fd_table_test to use VFS2.
This unit test had been using VFS1.
Updates #1624

PiperOrigin-RevId: 488740255
2022-11-15 13:15:15 -08:00
Andrei VaginandgVisor bot e7e65a9436 kernel: use lockdep mutexes
PiperOrigin-RevId: 449877248
2022-05-19 18:33:59 -07:00
Andrei Vagin ff350b6154 kernel: release FDTable lock before calling file methods
This change breaks dependency of FDTable.mu and kernfs.filesystemRWMutex.

panic: WARNING: circular locking detected: kernel.taskMutex -> kernel.fdTableMutex:

gvisor.dev/gvisor/pkg/sentry/kernel.(*fdTableMutex).Lock(0xc00491a110)
        bazel-out/k8-fastbuild-ST-1a50d7a562c6/bin/pkg/sentry/kernel/fd_table_mutex.go:16 +0x34
gvisor.dev/gvisor/pkg/sentry/kernel.(*FDTable).Fork(0xc00491a100, {0x158ef70, 0xc005fdb500}, 0x2073b60)
        pkg/sentry/kernel/fd_table.go:637 +0xca
gvisor.dev/gvisor/pkg/sentry/kernel.(*Task).Unshare(0xc005fdb500, 0x4040400)
        pkg/sentry/kernel/task_clone.go:483 +0x72d

known lock chain: kernel.fdTableMutex -> kernfs.filesystemRWMutex -> kernel.taskSetRWMutex -> kernel.signalHandlersMutex -> kernel.taskMutex

gvisor.dev/gvisor/pkg/sentry/kernel.(*FDTable).String(0xc000cd36c0)
        pkg/sentry/kernel/fd_table.go:245 +0x139

====== kernfs.filesystemRWMutex -> kernel.taskSetRWMutex =====
gvisor.dev/gvisor/pkg/sentry/kernel.(*PIDNamespace).IDOfThreadGroup(0xc00019ce40, 0xc0004a2800)
        pkg/sentry/kernel/threads.go:264 +0x35
gvisor.dev/gvisor/pkg/sentry/fsimpl/proc.(*selfSymlink).Readlink(0xc000074460, {0x158ef70, 0xc00027e000}, 0xc0003ba510)
        pkg/sentry/fsimpl/proc/tasks_files.go:58 +0x6d
gvisor.dev/gvisor/pkg/sentry/fsimpl/proc.(*selfSymlink).Getlink(0xc0004b5500, {0x158ef70, 0xc00027e000}, 0x4)
        pkg/sentry/fsimpl/proc/tasks_files.go:66 +0x2d

====== kernel.taskSetRWMutex -> kernel.signalHandlersMutex =====
gvisor.dev/gvisor/pkg/sentry/kernel.(*TaskSet).newTask(0xc00019cea0, 0xc0004f1570)
        pkg/sentry/kernel/task_start.go:177 +0x656
gvisor.dev/gvisor/pkg/sentry/kernel.(*TaskSet).NewTask(0xc00014f180, {0x158eff8, 0xc000436640}, 0xc0004f1570)
        pkg/sentry/kernel/task_start.go:122 +0xa5

====== kernel.signalHandlersMutex -> kernel.taskMutex =====
gvisor.dev/gvisor/pkg/sentry/kernel.(*TaskSet).newTask(0xc00019cea0, 0xc0004f1570)
        pkg/sentry/kernel/task_start.go:228 +0x9a8
gvisor.dev/gvisor/pkg/sentry/kernel.(*TaskSet).NewTask(0xc00014f180, {0x158eff8, 0xc000436640}, 0xc0004f1570)
        pkg/sentry/kernel/task_start.go:122 +0xa5
gvisor.dev/gvisor/pkg/sentry/kernel.(*Kernel).CreateProcess(0xc00014f180, {{0xc00039bf70, 0x5}, {0x0, 0x0}, {0xc00037d440, 0x1, 0x4}, {0xc000436620, 0x2, ...}, ...})
        pkg/sentry/kernel/kernel.go:1069 +0x147d
gvisor.dev/gvisor/runsc/boot.(*Loader).createContainerProcess(0xc0003f2000, 0x1, {0x7fff0a092fb9, 0x8}, 0xc0003f2010)
        runsc/boot/loader.go:809 +0x445
gvisor.dev/gvisor/runsc/boot.(*Loader).run(0xc0003f2000)
        runsc/boot/loader.go:630 +0x1ad
gvisor.dev/gvisor/runsc/boot.(*Loader).Run(0xc0003f2000)
        runsc/boot/loader.go:581 +0x25
2022-04-14 23:08:13 -07:00
Konstantin BogomolovandgVisor bot be6bfe5598 Fix data race when using UNSHARE in close_range.
Also add test that fails under gotsan without the fix.

PiperOrigin-RevId: 433857741
2022-03-10 14:53:45 -08:00
Konstantin BogomolovandgVisor bot 03113543e2 Implement close_range.
Fixes #5500

PiperOrigin-RevId: 431454836
2022-02-28 09:37:03 -08:00
gVisor bot f6878c663e Merge pull request #6257 from zhlhahaha:2193-1
PiperOrigin-RevId: 387885663
2021-07-30 14:43:13 -07:00
Andrei VaginandHoward Zhang a09e50f45c Don't create an extra fd bitmap to allocate a new fd. 2021-07-27 13:16:02 +08:00
Howard Zhang 46ae7dfb17 apply bitmap for fd_table
Apply bitmap in fd_table to record open file fd. It can
accelerate the speed of allocating or removing fd from
fdtable.

Signed-off-by: Howard Zhang <[email protected]>
2021-07-13 14:16:07 +08:00
Zach KoopmansandgVisor bot 45b64220cb [syserror] Add conversions to linuxerr with temporary Equals method.
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
2021-06-22 15:53:32 -07:00
Dean DengandgVisor bot 025d055287 Resolve remaining O_PATH TODOs.
O_PATH is now implemented in vfs2.

Fixes #2782.

PiperOrigin-RevId: 373861410
2021-05-14 14:04:46 -07:00
Ayush RanjanandgVisor bot c3ff9f93bc [op] Replace syscall package usage with golang.org/x/sys/unix in pkg/.
The syscall package has been deprecated in favor of golang.org/x/sys.

Note that syscall is still used in the following places:
- pkg/sentry/socket/hostinet/stack.go: some netlink related functionalities
  are not yet available in golang.org/x/sys.
- syscall.Stat_t is still used in some places because os.FileInfo.Sys() still
  returns it and not unix.Stat_t.

Updates #214

PiperOrigin-RevId: 360701387
2021-03-03 10:25:58 -08:00
Dean DengandgVisor bot 3f8fd704cb Do not generate extraneous IN_CLOSE inotify events.
IN_CLOSE should only be generated when a file description loses its last
reference; not when a file descriptor is closed.

See fs/file_table.c:__fput.

Updates #5348.

PiperOrigin-RevId: 353810697
2021-01-26 00:02:52 -08:00
Dean DengandgVisor bot fe181d34f9 Move Lock/UnlockPOSIX into LockFD util.
PiperOrigin-RevId: 352904728
2021-01-20 16:55:07 -08:00
Jamie LiuandgVisor bot 114d68adb8 Support VFS2 save/restore.
Inode number consistency checks are now skipped in save/restore tests for
reasons described in greatest detail in StatTest.StateDoesntChangeAfterRename.
They pass in VFS1 due to the bug described in new test case
SimpleStatTest.DifferentFilesHaveDifferentDeviceInodeNumberPairs.

Fixes #1663

PiperOrigin-RevId: 338776148
2020-10-23 17:48:33 -07:00
Dean DengandgVisor bot f6aa673ece Rewrite reference leak checker without finalizers.
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
2020-10-23 09:17:02 -07:00
Nayana BidariandgVisor bot 187395c6e8 Release FDTable lock before dropping the fds.
This is needed for SO_LINGER, where close() is blocked for linger timeout and
we are holding the FDTable lock for the entire timeout which will not allow
us to create/delete other fds. We have to release the locks and then drop the
fds.

PiperOrigin-RevId: 331844185
2020-09-15 13:43:50 -07:00
Jamie LiuandgVisor bot a6156e40d0 Correct FDSize in /proc/[pid]/status.
In Linux, FDSize is fs/proc/array.c:task_state() => struct fdtable::max_fds,
which is set to the underlying array's length in fs/file.c:alloc_fdtable().

Follow-up changes:

- Remove FDTable.GetRefs() and FDTable.GetRefsVFS2(), which are unused.

- Reset FDTable.used to 0 during restore, since the subsequent calls to
  FDTable.setAll() increment it again, causing its value to be doubled. (After
  this CL, FDTable.used is only used to avoid reallocation in FDTable.GetFDs(),
  so this fix is not very visible.)

PiperOrigin-RevId: 331588190
2020-09-14 11:34:50 -07:00
Nayana BidariandgVisor bot f4d7d0e8b3 Fix panic when calling dup2().
PiperOrigin-RevId: 329572337
2020-09-01 13:41:01 -07:00
Dean DengandgVisor bot eba7cf3392 Use new reference count utility throughout gvisor.
This uses the refs_vfs2 template in vfs2 as well as objects common to vfs1 and
vfs2. Note that vfs1-only refcounts are not replaced, since vfs1 will be deleted
soon anyway.

The following structs now use the new tool, with leak check enabled:
devpts:rootInode
fuse:inode
kernfs:Dentry
kernfs:dir
kernfs:readonlyDir
kernfs:StaticDirectory
proc:fdDirInode
proc:fdInfoDirInode
proc:subtasksInode
proc:taskInode
proc:tasksInode
vfs:FileDescription
vfs:MountNamespace
vfs:Filesystem
sys:dir
kernel:FSContext
kernel:ProcessGroup
kernel:Session
shm:Shm
mm:aioMappable
mm:SpecialMappable
transport:queue

And the following use the template, but because they currently are not leak
checked, a TODO is left instead of enabling leak check in this patch:
kernel:FDTable
tun:tunEndpoint

Updates #1486.

PiperOrigin-RevId: 328460377
2020-08-25 21:04:04 -07:00
Nayana BidariandgVisor bot 4a8d0d3f20 Plumbing context.Context to DecRef() and Release().
context is passed to DecRef() and Release() which is
needed for SO_LINGER implementation.

PiperOrigin-RevId: 324672584
2020-08-03 13:36:05 -07:00
Fabricio VoznikaandgVisor bot ed5436e082 Implement POSIX locks
- Change FileDescriptionImpl Lock/UnlockPOSIX signature to
  take {start,length,whence}, so the correct offset can be
  calculated in the implementations.
- Create PosixLocker interface to make it possible to share
  the same locking code from different implementations.

Closes #1480

PiperOrigin-RevId: 316910286
2020-06-17 10:04:26 -07:00
Andrei VaginandgVisor bot adfe745d70 vfs2: implement fcntl(fd, F_SETFL, flags)
PiperOrigin-RevId: 316148074
2020-06-12 11:58:15 -07:00
Fabricio VoznikaandgVisor bot d12598b851 Implement flock(2) in VFS2
LockFD is the generic implementation that can be embedded in
FileDescriptionImpl implementations. Unique lock ID is
maintained in vfs.FileDescription and is created on demand.

Updates #1480

PiperOrigin-RevId: 315604825
2020-06-09 18:46:42 -07:00
Dean DengandgVisor bot a1ccbf51c3 Implement IN_EXCL_UNLINK inotify option in vfs2.
Limited to tmpfs. Inotify support in other filesystem implementations to
follow.

Updates #1479

PiperOrigin-RevId: 313828648
2020-05-29 12:28:49 -07:00
Dean DengandgVisor bot 2ea5dbdcd0 Port inotify to vfs2, with support in tmpfs.
Support in other filesystem impls is still needed. Unlike in Linux and vfs1, we
need to plumb inotify down to each filesystem implementation in order to keep
track of links/inode structures properly.

IN_EXCL_UNLINK still needs to be implemented, as well as a few inotify hooks
that are not present in either vfs1 or vfs2. Those will be addressed in
subsequent changes.

Updates #1479.

PiperOrigin-RevId: 313781995
2020-05-29 08:09:14 -07:00
Dean DengandgVisor bot 33ecf251a5 Port socket-related syscalls to VFS2.
Note that most kinds of sockets are not yet supported in VFS2
(only Unix sockets are partially supported at the moment), so
these syscalls will still generally fail. Enabling them allows
us to begin running socket tests for VFS2 as more features are
ported over.

Updates #1476, #1478, #1484, #1485.

PiperOrigin-RevId: 306292294
2020-04-13 13:02:34 -07:00
Fabricio VoznikaandgVisor bot ec588ef53f Fix FDTable.NewFDVFS2
It was looking at VFS1 table to determine where to
allocate the next FD from.

Updates #1035

PiperOrigin-RevId: 301678858
2020-03-18 15:13:42 -07:00
Andrei VaginandgVisor bot 27e3e2b927 fdtable: don't try to zap fdtable entry if close is called for non-existing fd
FDTable.setAll is used to zap entries, but it grows the table up to
a specified fd.

Reported-by: [email protected]
PiperOrigin-RevId: 301280000
2020-03-16 18:29:58 -07:00
Fabricio VoznikaandgVisor bot a222766a71 Add remaining procfs files
Closes #1195

PiperOrigin-RevId: 300867055
2020-03-13 18:57:07 -07:00
Fabricio VoznikaandgVisor bot a114101118 Panic if file in FDTable has been destroyed
This will give more information about the file to
identify where possibly the extra DecRef()
would be.

PiperOrigin-RevId: 300855874
2020-03-13 17:18:10 -07:00
Jamie LiuandgVisor bot 11e08c4ab3 Port most syscalls to VFS2.
pipe and pipe2 aren't ported, pending a slight rework of pipe FDs for VFS2.
mount and umount2 aren't ported out of temporary laziness. access and faccessat
need additional FSImpl methods to implement properly, but are stubbed to
prevent googletest from CHECK-failing. Other syscalls require additional
plumbing.

Updates #1623

PiperOrigin-RevId: 297188448
2020-02-25 13:37:34 -08:00
Fabricio VoznikaandgVisor bot 9583cf1be8 Changes missing in last submit
Updates #1487
Updates #1623

PiperOrigin-RevId: 292040835
2020-01-28 16:53:55 -08:00
Fabricio VoznikaandgVisor bot 561e23dec4 Add vfs.FileDescription to FD table
FD table now holds both VFS1 and VFS2 types and uses the correct
one based on what's set.

Parts of this CL are just initial changes (e.g. sys_read.go,
runsc/main.go) to serve as a template for the remaining changes.

Updates #1487
Updates #1623

PiperOrigin-RevId: 292023223
2020-01-28 15:31:03 -08:00
Adin ScannellandgVisor bot 4368058004 Update package locations.
Because the abi will depend on the core types for marshalling (usermem,
context, safemem, safecopy), these need to be flattened from the sentry
directory. These packages contain no sentry-specific details.

PiperOrigin-RevId: 291811289
2020-01-27 15:31:32 -08:00
Adin ScannellandgVisor bot ca925fc495 Fix licenses.
The preferred Copyright holder is "The gVisor Authors".

PiperOrigin-RevId: 291786657
2020-01-27 13:23:57 -08:00
Ian GudgerandgVisor bot ee0336e6f1 New sync package.
* Rename syncutil to sync.
* Add aliases to sync types.
* Replace existing usage of standard library sync package.

This will make it easier to swap out synchronization primitives. For example,
this will allow us to use primitives from github.com/sasha-s/go-deadlock to
check for lock ordering violations.

Updates #1472

PiperOrigin-RevId: 289033387
2020-01-09 22:02:24 -08:00
DarcySailandgVisor bot 39059e449d Keep minimal available fd to accelerate fd allocation
Use fd.next to store the iteration start position, which can be used to accelerate allocating new FDs.
And adding the corresponding gtest benchmark to measure performance.
@tanjianfeng

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/gvisor/pull/758 from DarcySail:master 96685ec7886dfe1a64988406831d3bc002b438cc
PiperOrigin-RevId: 276351250
2019-10-23 14:27:53 -07:00
Bhasker HariharanandgVisor bot 72d14b49ec Fix race in FDTable.GetFDs().
PiperOrigin-RevId: 258635459
2019-07-17 13:56:49 -07:00
Adin ScannellandgVisor bot 753da9604e Remove map from fd_map, change to fd_table.
This renames FDMap to FDTable and drops the kernel.FD type, which had an entire
package to itself and didn't serve much use (it was freely cast between types,
and served as more of an annoyance than providing any protection.)

Based on BenchmarkFDLookupAndDecRef-12, we can expect 5-10 ns per lookup
operation, and 10-15 ns per concurrent lookup operation of savings.

This also fixes two tangential usage issues with the FDMap. Namely, non-atomic
use of NewFDFrom and associated calls to Remove (that are both racy and fail to
drop the reference on the underlying file.)

PiperOrigin-RevId: 256285890
2019-07-02 19:28:59 -07:00