diff options
-rw-r--r-- | pkg/sentry/fs/proc/net.go | 132 | ||||
-rw-r--r-- | pkg/sentry/kernel/ptrace.go | 4 | ||||
-rw-r--r-- | pkg/sentry/platform/ptrace/subprocess.go | 56 | ||||
-rw-r--r-- | test/syscalls/linux/setgid.cc | 17 |
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 */)); |