Skip to content

Commit de750eb

Browse files
nixprimegvisor-bot
authored andcommitted
Add Execve and ExitNotifyParent checkpoints.
Call sites for the two checkpoints aren't added yet. PiperOrigin-RevId: 398375903
1 parent d877254 commit de750eb

File tree

5 files changed

+155
-11
lines changed

5 files changed

+155
-11
lines changed

pkg/sentry/seccheck/BUILD

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ go_fieldenum(
88
name = "seccheck_fieldenum",
99
srcs = [
1010
"clone.go",
11+
"execve.go",
12+
"exit.go",
1113
"task.go",
1214
],
1315
out = "seccheck_fieldenum.go",
@@ -29,6 +31,8 @@ go_library(
2931
name = "seccheck",
3032
srcs = [
3133
"clone.go",
34+
"execve.go",
35+
"exit.go",
3236
"seccheck.go",
3337
"seccheck_fieldenum.go",
3438
"seqatomic_checkerslice_unsafe.go",

pkg/sentry/seccheck/execve.go

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright 2021 The gVisor Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package seccheck
16+
17+
import (
18+
"gvisor.dev/gvisor/pkg/context"
19+
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
20+
)
21+
22+
// ExecveInfo contains information used by the Execve checkpoint.
23+
//
24+
// +fieldenum Execve
25+
type ExecveInfo struct {
26+
// Invoker identifies the invoking thread.
27+
Invoker TaskInfo
28+
29+
// Credentials are the invoking thread's credentials.
30+
Credentials *auth.Credentials
31+
32+
// BinaryPath is a path to the executable binary file being switched to in
33+
// the mount namespace in which it was opened.
34+
BinaryPath string
35+
36+
// Argv is the new process image's argument vector.
37+
Argv []string
38+
39+
// Env is the new process image's environment variables.
40+
Env []string
41+
42+
// BinaryMode is the executable binary file's mode.
43+
BinaryMode uint16
44+
45+
// BinarySHA256 is the SHA-256 hash of the executable binary file.
46+
//
47+
// Note that this requires reading the entire file into memory, which is
48+
// likely to be extremely slow.
49+
BinarySHA256 [32]byte
50+
}
51+
52+
// ExecveReq returns fields required by the Execve checkpoint.
53+
func (s *state) ExecveReq() ExecveFieldSet {
54+
return s.execveReq.Load()
55+
}
56+
57+
// Execve is called at the Execve checkpoint.
58+
func (s *state) Execve(ctx context.Context, mask ExecveFieldSet, info *ExecveInfo) error {
59+
for _, c := range s.getCheckers() {
60+
if err := c.Execve(ctx, mask, *info); err != nil {
61+
return err
62+
}
63+
}
64+
return nil
65+
}

pkg/sentry/seccheck/exit.go

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2021 The gVisor Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package seccheck
16+
17+
import (
18+
"gvisor.dev/gvisor/pkg/abi/linux"
19+
"gvisor.dev/gvisor/pkg/context"
20+
)
21+
22+
// ExitNotifyParentInfo contains information used by the ExitNotifyParent
23+
// checkpoint.
24+
//
25+
// +fieldenum ExitNotifyParent
26+
type ExitNotifyParentInfo struct {
27+
// Exiter identifies the exiting thread. Note that by the checkpoint's
28+
// definition, Exiter.ThreadID == Exiter.ThreadGroupID and
29+
// Exiter.ThreadStartTime == Exiter.ThreadGroupStartTime, so requesting
30+
// ThreadGroup* fields is redundant.
31+
Exiter TaskInfo
32+
33+
// ExitStatus is the exiting thread group's exit status, as reported
34+
// by wait*().
35+
ExitStatus linux.WaitStatus
36+
}
37+
38+
// ExitNotifyParentReq returns fields required by the ExitNotifyParent
39+
// checkpoint.
40+
func (s *state) ExitNotifyParentReq() ExitNotifyParentFieldSet {
41+
return s.exitNotifyParentReq.Load()
42+
}
43+
44+
// ExitNotifyParent is called at the ExitNotifyParent checkpoint.
45+
//
46+
// The ExitNotifyParent checkpoint occurs when a zombied thread group leader,
47+
// not waiting for exit acknowledgement from a non-parent ptracer, becomes the
48+
// last non-dead thread in its thread group and notifies its parent of its
49+
// exiting.
50+
func (s *state) ExitNotifyParent(ctx context.Context, mask ExitNotifyParentFieldSet, info *ExitNotifyParentInfo) error {
51+
for _, c := range s.getCheckers() {
52+
if err := c.ExitNotifyParent(ctx, mask, *info); err != nil {
53+
return err
54+
}
55+
}
56+
return nil
57+
}

pkg/sentry/seccheck/seccheck.go

+24-2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ type Point uint
2929
// PointX represents the checkpoint X.
3030
const (
3131
PointClone Point = iota
32+
PointExecve
33+
PointExitNotifyParent
3234
// Add new Points above this line.
3335
pointLength
3436

@@ -47,6 +49,8 @@ const (
4749
// registered concurrently with invocations of checkpoints).
4850
type Checker interface {
4951
Clone(ctx context.Context, mask CloneFieldSet, info CloneInfo) error
52+
Execve(ctx context.Context, mask ExecveFieldSet, info ExecveInfo) error
53+
ExitNotifyParent(ctx context.Context, mask ExitNotifyParentFieldSet, info ExitNotifyParentInfo) error
5054
}
5155

5256
// CheckerDefaults may be embedded by implementations of Checker to obtain
@@ -58,6 +62,16 @@ func (CheckerDefaults) Clone(ctx context.Context, mask CloneFieldSet, info Clone
5862
return nil
5963
}
6064

65+
// Execve implements Checker.Execve.
66+
func (CheckerDefaults) Execve(ctx context.Context, mask ExecveFieldSet, info ExecveInfo) error {
67+
return nil
68+
}
69+
70+
// ExitNotifyParent implements Checker.ExitNotifyParent.
71+
func (CheckerDefaults) ExitNotifyParent(ctx context.Context, mask ExitNotifyParentFieldSet, info ExitNotifyParentInfo) error {
72+
return nil
73+
}
74+
6175
// CheckerReq indicates what checkpoints a corresponding Checker runs at, and
6276
// what information it requires at those checkpoints.
6377
type CheckerReq struct {
@@ -69,7 +83,9 @@ type CheckerReq struct {
6983

7084
// All of the following fields indicate what fields in the corresponding
7185
// XInfo struct will be requested at the corresponding checkpoint.
72-
Clone CloneFields
86+
Clone CloneFields
87+
Execve ExecveFields
88+
ExitNotifyParent ExitNotifyParentFields
7389
}
7490

7591
// Global is the method receiver of all seccheck functions.
@@ -101,7 +117,9 @@ type state struct {
101117
// corresponding XInfo struct have been requested by any registered
102118
// checker, are accessed using atomic memory operations, and are mutated
103119
// with registrationMu locked.
104-
cloneReq CloneFieldSet
120+
cloneReq CloneFieldSet
121+
execveReq ExecveFieldSet
122+
exitNotifyParentReq ExitNotifyParentFieldSet
105123
}
106124

107125
// AppendChecker registers the given Checker to execute at checkpoints. The
@@ -110,7 +128,11 @@ type state struct {
110128
func (s *state) AppendChecker(c Checker, req *CheckerReq) {
111129
s.registrationMu.Lock()
112130
defer s.registrationMu.Unlock()
131+
113132
s.cloneReq.AddFieldsLoadable(req.Clone)
133+
s.execveReq.AddFieldsLoadable(req.Execve)
134+
s.exitNotifyParentReq.AddFieldsLoadable(req.ExitNotifyParent)
135+
114136
s.appendCheckerLocked(c)
115137
for _, p := range req.Points {
116138
word, bit := p/32, p%32

tools/go_fieldenum/main.go

+5-9
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ func main() {
5555

5656
// Determine which types are marked "+fieldenum" and will consequently have
5757
// code generated.
58+
var typeNames []string
5859
fieldEnumTypes := make(map[string]fieldEnumTypeInfo)
5960
for _, f := range inputFiles {
6061
for _, decl := range f.Decls {
@@ -75,6 +76,7 @@ func main() {
7576
if !ok {
7677
log.Fatalf("Type %s is marked +fieldenum, but is not a struct", name)
7778
}
79+
typeNames = append(typeNames, name)
7880
fieldEnumTypes[name] = fieldEnumTypeInfo{
7981
prefix: prefix,
8082
structType: st,
@@ -86,9 +88,10 @@ func main() {
8688
}
8789

8890
// Collect information for each type for which code is being generated.
89-
structInfos := make([]structInfo, 0, len(fieldEnumTypes))
91+
structInfos := make([]structInfo, 0, len(typeNames))
9092
needSyncAtomic := false
91-
for typeName, typeInfo := range fieldEnumTypes {
93+
for _, typeName := range typeNames {
94+
typeInfo := fieldEnumTypes[typeName]
9295
var si structInfo
9396
si.name = typeName
9497
si.prefix = typeInfo.prefix
@@ -204,13 +207,6 @@ func structFieldName(f *ast.Field) string {
204207
}
205208
}
206209

207-
// Workaround for Go defect (map membership test isn't usable in an
208-
// expression).
209-
func fetContains(xs map[string]*ast.StructType, x string) bool {
210-
_, ok := xs[x]
211-
return ok
212-
}
213-
214210
func (si *structInfo) writeTo(b *strings.Builder) {
215211
fmt.Fprintf(b, "// A %sField represents a field in %s.\n", si.prefix, si.name)
216212
fmt.Fprintf(b, "type %sField uint\n\n", si.prefix)

0 commit comments

Comments
 (0)