summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--pkg/sentry/fs/proc/net.go132
-rw-r--r--pkg/sentry/kernel/ptrace.go4
-rw-r--r--pkg/sentry/platform/ptrace/subprocess.go56
-rw-r--r--test/syscalls/linux/setgid.cc17
4 files changed, 120 insertions, 89 deletions
diff --git a/pkg/sentry/fs/proc/net.go b/pkg/sentry/fs/proc/net.go
index 03127f816..203cfa061 100644
--- a/pkg/sentry/fs/proc/net.go
+++ b/pkg/sentry/fs/proc/net.go
@@ -128,13 +128,17 @@ func (*ifinet6) NeedsUpdate(generation int64) bool {
// ReadSeqFileData implements seqfile.SeqSource.ReadSeqFileData.
func (n *ifinet6) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]seqfile.SeqData, int64) {
+ contents := n.contents()
+ minI := 0
if h != nil {
- return nil, 0
+ minI = h.(int) + 1
+ if minI > len(contents) {
+ minI = len(contents)
+ }
}
-
var data []seqfile.SeqData
- for _, l := range n.contents() {
- data = append(data, seqfile.SeqData{Buf: []byte(l), Handle: (*ifinet6)(nil)})
+ for i, l := range contents[minI:] {
+ data = append(data, seqfile.SeqData{Buf: []byte(l), Handle: i + minI})
}
return data, 0
@@ -155,10 +159,6 @@ func (n *netDev) NeedsUpdate(generation int64) bool {
// ReadSeqFileData implements seqfile.SeqSource.ReadSeqFileData. See Linux's
// net/core/net-procfs.c:dev_seq_show.
func (n *netDev) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]seqfile.SeqData, int64) {
- if h != nil {
- return nil, 0
- }
-
interfaces := n.s.Interfaces()
contents := make([]string, 2, 2+len(interfaces))
// Add the table header. From net/core/net-procfs.c:dev_seq_show.
@@ -197,9 +197,16 @@ func (n *netDev) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]se
contents = append(contents, l)
}
+ minI := 0
+ if h != nil {
+ minI = h.(int) + 1
+ if minI > len(contents) {
+ minI = len(contents)
+ }
+ }
var data []seqfile.SeqData
- for _, l := range contents {
- data = append(data, seqfile.SeqData{Buf: []byte(l), Handle: (*netDev)(nil)})
+ for i, l := range contents[minI:] {
+ data = append(data, seqfile.SeqData{Buf: []byte(l), Handle: i + minI})
}
return data, 0
@@ -264,10 +271,6 @@ func sprintSlice(s []uint64) string {
// ReadSeqFileData implements seqfile.SeqSource.ReadSeqFileData. See Linux's
// net/core/net-procfs.c:dev_seq_show.
func (n *netSnmp) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]seqfile.SeqData, int64) {
- if h != nil {
- return nil, 0
- }
-
contents := make([]string, 0, len(snmp)*2)
types := []interface{}{
&inet.StatSNMPIP{},
@@ -309,9 +312,16 @@ func (n *netSnmp) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]s
)
}
+ minI := 0
+ if h != nil {
+ minI = h.(int) + 1
+ if minI > len(contents) {
+ minI = len(contents)
+ }
+ }
data := make([]seqfile.SeqData, 0, len(snmp)*2)
- for _, l := range contents {
- data = append(data, seqfile.SeqData{Buf: []byte(l), Handle: (*netSnmp)(nil)})
+ for i, l := range contents[minI:] {
+ data = append(data, seqfile.SeqData{Buf: []byte(l), Handle: i + minI})
}
return data, 0
@@ -332,10 +342,6 @@ func (n *netRoute) NeedsUpdate(generation int64) bool {
// ReadSeqFileData implements seqfile.SeqSource.ReadSeqFileData.
// See Linux's net/ipv4/fib_trie.c:fib_route_seq_show.
func (n *netRoute) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]seqfile.SeqData, int64) {
- if h != nil {
- return nil, 0
- }
-
interfaces := n.s.Interfaces()
contents := []string{"Iface\tDestination\tGateway\tFlags\tRefCnt\tUse\tMetric\tMask\tMTU\tWindow\tIRTT"}
for _, rt := range n.s.RouteTable() {
@@ -383,10 +389,17 @@ func (n *netRoute) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]
contents = append(contents, l)
}
+ minI := 0
+ if h != nil {
+ minI = h.(int) + 1
+ if minI > len(contents) {
+ minI = len(contents)
+ }
+ }
var data []seqfile.SeqData
- for _, l := range contents {
+ for i, l := range contents[minI:] {
l = fmt.Sprintf("%-127s\n", l)
- data = append(data, seqfile.SeqData{Buf: []byte(l), Handle: (*netRoute)(nil)})
+ data = append(data, seqfile.SeqData{Buf: []byte(l), Handle: i + minI})
}
return data, 0
@@ -406,10 +419,6 @@ func (*netUnix) NeedsUpdate(generation int64) bool {
// ReadSeqFileData implements seqfile.SeqSource.ReadSeqFileData.
func (n *netUnix) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]seqfile.SeqData, int64) {
- if h != nil {
- return []seqfile.SeqData{}, 0
- }
-
var buf bytes.Buffer
for _, se := range n.k.ListSockets() {
s := se.Sock.Get()
@@ -482,15 +491,22 @@ func (n *netUnix) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]s
s.DecRef(ctx)
}
- data := []seqfile.SeqData{
- {
+ minI := 0
+ if h != nil {
+ minI = h.(int) + 1
+ }
+ var data []seqfile.SeqData
+ if minI <= 0 {
+ data = append(data, seqfile.SeqData{
Buf: []byte("Num RefCount Protocol Flags Type St Inode Path\n"),
- Handle: n,
- },
- {
+ Handle: 0,
+ })
+ }
+ if minI <= 1 {
+ data = append(data, seqfile.SeqData{
Buf: buf.Bytes(),
- Handle: n,
- },
+ Handle: 1,
+ })
}
return data, 0
}
@@ -557,10 +573,6 @@ func commonReadSeqFileDataTCP(ctx context.Context, n seqfile.SeqHandle, k *kerne
// degrade gracefully and retrieve what we can.
t := kernel.TaskFromContext(ctx)
- if h != nil {
- return nil, 0
- }
-
var buf bytes.Buffer
for _, se := range k.ListSockets() {
s := se.Sock.Get()
@@ -667,15 +679,22 @@ func commonReadSeqFileDataTCP(ctx context.Context, n seqfile.SeqHandle, k *kerne
s.DecRef(ctx)
}
- data := []seqfile.SeqData{
- {
+ minI := 0
+ if h != nil {
+ minI = h.(int) + 1
+ }
+ var data []seqfile.SeqData
+ if minI <= 0 {
+ data = append(data, seqfile.SeqData{
Buf: header,
- Handle: n,
- },
- {
+ Handle: 0,
+ })
+ }
+ if minI <= 1 {
+ data = append(data, seqfile.SeqData{
Buf: buf.Bytes(),
- Handle: n,
- },
+ Handle: 1,
+ })
}
return data, 0
}
@@ -735,10 +754,6 @@ func (n *netUDP) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]se
// degrade gracefully and retrieve what we can.
t := kernel.TaskFromContext(ctx)
- if h != nil {
- return nil, 0
- }
-
var buf bytes.Buffer
for _, se := range n.k.ListSockets() {
s := se.Sock.Get()
@@ -825,15 +840,22 @@ func (n *netUDP) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]se
s.DecRef(ctx)
}
- data := []seqfile.SeqData{
- {
+ minI := 0
+ if h != nil {
+ minI = h.(int) + 1
+ }
+ var data []seqfile.SeqData
+ if minI <= 0 {
+ data = append(data, seqfile.SeqData{
Buf: []byte(" sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops \n"),
- Handle: n,
- },
- {
+ Handle: 0,
+ })
+ }
+ if minI <= 1 {
+ data = append(data, seqfile.SeqData{
Buf: buf.Bytes(),
- Handle: n,
- },
+ Handle: 1,
+ })
}
return data, 0
}
diff --git a/pkg/sentry/kernel/ptrace.go b/pkg/sentry/kernel/ptrace.go
index c3980350a..f5a60e749 100644
--- a/pkg/sentry/kernel/ptrace.go
+++ b/pkg/sentry/kernel/ptrace.go
@@ -770,8 +770,8 @@ func (t *Task) ptraceClone(kind ptraceCloneKind, child *Task, opts *CloneOptions
if !t.hasTracer() {
return false
}
- t.tg.pidns.owner.mu.RLock()
- defer t.tg.pidns.owner.mu.RUnlock()
+ t.tg.pidns.owner.mu.Lock()
+ defer t.tg.pidns.owner.mu.Unlock()
event := false
if !opts.Untraced {
switch kind {
diff --git a/pkg/sentry/platform/ptrace/subprocess.go b/pkg/sentry/platform/ptrace/subprocess.go
index acccbfe2e..d2284487a 100644
--- a/pkg/sentry/platform/ptrace/subprocess.go
+++ b/pkg/sentry/platform/ptrace/subprocess.go
@@ -69,7 +69,7 @@ type thread struct {
// threadPool is a collection of threads.
type threadPool struct {
// mu protects below.
- mu sync.Mutex
+ mu sync.RWMutex
// threads is the collection of threads.
//
@@ -85,30 +85,42 @@ type threadPool struct {
//
// Precondition: the runtime OS thread must be locked.
func (tp *threadPool) lookupOrCreate(currentTID int32, newThread func() *thread) *thread {
- tp.mu.Lock()
+ // The overwhelming common case is that the thread is already created.
+ // Optimistically attempt the lookup by only locking for reading.
+ tp.mu.RLock()
t, ok := tp.threads[currentTID]
- if !ok {
- // Before creating a new thread, see if we can find a thread
- // whose system tid has disappeared.
- //
- // TODO(b/77216482): Other parts of this package depend on
- // threads never exiting.
- for origTID, t := range tp.threads {
- // Signal zero is an easy existence check.
- if err := unix.Tgkill(unix.Getpid(), int(origTID), 0); err != nil {
- // This thread has been abandoned; reuse it.
- delete(tp.threads, origTID)
- tp.threads[currentTID] = t
- tp.mu.Unlock()
- return t
- }
- }
+ tp.mu.RUnlock()
+ if ok {
+ return t
+ }
- // Create a new thread.
- t = newThread()
- tp.threads[currentTID] = t
+ tp.mu.Lock()
+ defer tp.mu.Unlock()
+
+ // Another goroutine might have created the thread for currentTID in between
+ // mu.RUnlock() and mu.Lock().
+ if t, ok = tp.threads[currentTID]; ok {
+ return t
+ }
+
+ // Before creating a new thread, see if we can find a thread
+ // whose system tid has disappeared.
+ //
+ // TODO(b/77216482): Other parts of this package depend on
+ // threads never exiting.
+ for origTID, t := range tp.threads {
+ // Signal zero is an easy existence check.
+ if err := unix.Tgkill(unix.Getpid(), int(origTID), 0); err != nil {
+ // This thread has been abandoned; reuse it.
+ delete(tp.threads, origTID)
+ tp.threads[currentTID] = t
+ return t
+ }
}
- tp.mu.Unlock()
+
+ // Create a new thread.
+ t = newThread()
+ tp.threads[currentTID] = t
return t
}
diff --git a/test/syscalls/linux/setgid.cc b/test/syscalls/linux/setgid.cc
index 98f8f3dfe..ce61bc36d 100644
--- a/test/syscalls/linux/setgid.cc
+++ b/test/syscalls/linux/setgid.cc
@@ -107,16 +107,7 @@ PosixErrorOr<std::pair<gid_t, gid_t>> Groups() {
if (!capable.ValueOrDie()) {
return PosixError(EPERM, "missing CAP_SETGID");
}
- gid_t gid = getegid();
- auto cleanup1 = Setegid(gid);
- if (!cleanup1.ok()) {
- return cleanup1.error();
- }
- auto cleanup2 = Setegid(kNobody);
- if (!cleanup2.ok()) {
- return cleanup2.error();
- }
- return std::pair<gid_t, gid_t>(gid, kNobody);
+ return std::pair<gid_t, gid_t>(getegid(), kNobody);
}
class SetgidDirTest : public ::testing::Test {
@@ -132,6 +123,12 @@ class SetgidDirTest : public ::testing::Test {
SKIP_IF(!groups.ok());
groups_ = groups.ValueOrDie();
+ // Ensure we can actually use both groups.
+ auto cleanup1 = Setegid(groups_.first);
+ SKIP_IF(!cleanup1.ok());
+ auto cleanup2 = Setegid(groups_.second);
+ SKIP_IF(!cleanup2.ok());
+
auto cleanup = Setegid(groups_.first);
temp_dir_ = ASSERT_NO_ERRNO_AND_VALUE(
TempPath::CreateDirWith(GetAbsoluteTestTmpdir(), 0777 /* mode */));