mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Add Execve and ExitNotifyParent checkpoints.
Call sites for the two checkpoints aren't added yet. PiperOrigin-RevId: 398375903
This commit is contained in:
@@ -8,6 +8,8 @@ go_fieldenum(
|
||||
name = "seccheck_fieldenum",
|
||||
srcs = [
|
||||
"clone.go",
|
||||
"execve.go",
|
||||
"exit.go",
|
||||
"task.go",
|
||||
],
|
||||
out = "seccheck_fieldenum.go",
|
||||
@@ -29,6 +31,8 @@ go_library(
|
||||
name = "seccheck",
|
||||
srcs = [
|
||||
"clone.go",
|
||||
"execve.go",
|
||||
"exit.go",
|
||||
"seccheck.go",
|
||||
"seccheck_fieldenum.go",
|
||||
"seqatomic_checkerslice_unsafe.go",
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
// Copyright 2021 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package seccheck
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
)
|
||||
|
||||
// ExecveInfo contains information used by the Execve checkpoint.
|
||||
//
|
||||
// +fieldenum Execve
|
||||
type ExecveInfo struct {
|
||||
// Invoker identifies the invoking thread.
|
||||
Invoker TaskInfo
|
||||
|
||||
// Credentials are the invoking thread's credentials.
|
||||
Credentials *auth.Credentials
|
||||
|
||||
// BinaryPath is a path to the executable binary file being switched to in
|
||||
// the mount namespace in which it was opened.
|
||||
BinaryPath string
|
||||
|
||||
// Argv is the new process image's argument vector.
|
||||
Argv []string
|
||||
|
||||
// Env is the new process image's environment variables.
|
||||
Env []string
|
||||
|
||||
// BinaryMode is the executable binary file's mode.
|
||||
BinaryMode uint16
|
||||
|
||||
// BinarySHA256 is the SHA-256 hash of the executable binary file.
|
||||
//
|
||||
// Note that this requires reading the entire file into memory, which is
|
||||
// likely to be extremely slow.
|
||||
BinarySHA256 [32]byte
|
||||
}
|
||||
|
||||
// ExecveReq returns fields required by the Execve checkpoint.
|
||||
func (s *state) ExecveReq() ExecveFieldSet {
|
||||
return s.execveReq.Load()
|
||||
}
|
||||
|
||||
// Execve is called at the Execve checkpoint.
|
||||
func (s *state) Execve(ctx context.Context, mask ExecveFieldSet, info *ExecveInfo) error {
|
||||
for _, c := range s.getCheckers() {
|
||||
if err := c.Execve(ctx, mask, *info); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright 2021 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package seccheck
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
)
|
||||
|
||||
// ExitNotifyParentInfo contains information used by the ExitNotifyParent
|
||||
// checkpoint.
|
||||
//
|
||||
// +fieldenum ExitNotifyParent
|
||||
type ExitNotifyParentInfo struct {
|
||||
// Exiter identifies the exiting thread. Note that by the checkpoint's
|
||||
// definition, Exiter.ThreadID == Exiter.ThreadGroupID and
|
||||
// Exiter.ThreadStartTime == Exiter.ThreadGroupStartTime, so requesting
|
||||
// ThreadGroup* fields is redundant.
|
||||
Exiter TaskInfo
|
||||
|
||||
// ExitStatus is the exiting thread group's exit status, as reported
|
||||
// by wait*().
|
||||
ExitStatus linux.WaitStatus
|
||||
}
|
||||
|
||||
// ExitNotifyParentReq returns fields required by the ExitNotifyParent
|
||||
// checkpoint.
|
||||
func (s *state) ExitNotifyParentReq() ExitNotifyParentFieldSet {
|
||||
return s.exitNotifyParentReq.Load()
|
||||
}
|
||||
|
||||
// ExitNotifyParent is called at the ExitNotifyParent checkpoint.
|
||||
//
|
||||
// The ExitNotifyParent checkpoint occurs when a zombied thread group leader,
|
||||
// not waiting for exit acknowledgement from a non-parent ptracer, becomes the
|
||||
// last non-dead thread in its thread group and notifies its parent of its
|
||||
// exiting.
|
||||
func (s *state) ExitNotifyParent(ctx context.Context, mask ExitNotifyParentFieldSet, info *ExitNotifyParentInfo) error {
|
||||
for _, c := range s.getCheckers() {
|
||||
if err := c.ExitNotifyParent(ctx, mask, *info); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -29,6 +29,8 @@ type Point uint
|
||||
// PointX represents the checkpoint X.
|
||||
const (
|
||||
PointClone Point = iota
|
||||
PointExecve
|
||||
PointExitNotifyParent
|
||||
// Add new Points above this line.
|
||||
pointLength
|
||||
|
||||
@@ -47,6 +49,8 @@ const (
|
||||
// registered concurrently with invocations of checkpoints).
|
||||
type Checker interface {
|
||||
Clone(ctx context.Context, mask CloneFieldSet, info CloneInfo) error
|
||||
Execve(ctx context.Context, mask ExecveFieldSet, info ExecveInfo) error
|
||||
ExitNotifyParent(ctx context.Context, mask ExitNotifyParentFieldSet, info ExitNotifyParentInfo) error
|
||||
}
|
||||
|
||||
// CheckerDefaults may be embedded by implementations of Checker to obtain
|
||||
@@ -58,6 +62,16 @@ func (CheckerDefaults) Clone(ctx context.Context, mask CloneFieldSet, info Clone
|
||||
return nil
|
||||
}
|
||||
|
||||
// Execve implements Checker.Execve.
|
||||
func (CheckerDefaults) Execve(ctx context.Context, mask ExecveFieldSet, info ExecveInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExitNotifyParent implements Checker.ExitNotifyParent.
|
||||
func (CheckerDefaults) ExitNotifyParent(ctx context.Context, mask ExitNotifyParentFieldSet, info ExitNotifyParentInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckerReq indicates what checkpoints a corresponding Checker runs at, and
|
||||
// what information it requires at those checkpoints.
|
||||
type CheckerReq struct {
|
||||
@@ -69,7 +83,9 @@ type CheckerReq struct {
|
||||
|
||||
// All of the following fields indicate what fields in the corresponding
|
||||
// XInfo struct will be requested at the corresponding checkpoint.
|
||||
Clone CloneFields
|
||||
Clone CloneFields
|
||||
Execve ExecveFields
|
||||
ExitNotifyParent ExitNotifyParentFields
|
||||
}
|
||||
|
||||
// Global is the method receiver of all seccheck functions.
|
||||
@@ -101,7 +117,9 @@ type state struct {
|
||||
// corresponding XInfo struct have been requested by any registered
|
||||
// checker, are accessed using atomic memory operations, and are mutated
|
||||
// with registrationMu locked.
|
||||
cloneReq CloneFieldSet
|
||||
cloneReq CloneFieldSet
|
||||
execveReq ExecveFieldSet
|
||||
exitNotifyParentReq ExitNotifyParentFieldSet
|
||||
}
|
||||
|
||||
// AppendChecker registers the given Checker to execute at checkpoints. The
|
||||
@@ -110,7 +128,11 @@ type state struct {
|
||||
func (s *state) AppendChecker(c Checker, req *CheckerReq) {
|
||||
s.registrationMu.Lock()
|
||||
defer s.registrationMu.Unlock()
|
||||
|
||||
s.cloneReq.AddFieldsLoadable(req.Clone)
|
||||
s.execveReq.AddFieldsLoadable(req.Execve)
|
||||
s.exitNotifyParentReq.AddFieldsLoadable(req.ExitNotifyParent)
|
||||
|
||||
s.appendCheckerLocked(c)
|
||||
for _, p := range req.Points {
|
||||
word, bit := p/32, p%32
|
||||
|
||||
@@ -55,6 +55,7 @@ func main() {
|
||||
|
||||
// Determine which types are marked "+fieldenum" and will consequently have
|
||||
// code generated.
|
||||
var typeNames []string
|
||||
fieldEnumTypes := make(map[string]fieldEnumTypeInfo)
|
||||
for _, f := range inputFiles {
|
||||
for _, decl := range f.Decls {
|
||||
@@ -75,6 +76,7 @@ func main() {
|
||||
if !ok {
|
||||
log.Fatalf("Type %s is marked +fieldenum, but is not a struct", name)
|
||||
}
|
||||
typeNames = append(typeNames, name)
|
||||
fieldEnumTypes[name] = fieldEnumTypeInfo{
|
||||
prefix: prefix,
|
||||
structType: st,
|
||||
@@ -86,9 +88,10 @@ func main() {
|
||||
}
|
||||
|
||||
// Collect information for each type for which code is being generated.
|
||||
structInfos := make([]structInfo, 0, len(fieldEnumTypes))
|
||||
structInfos := make([]structInfo, 0, len(typeNames))
|
||||
needSyncAtomic := false
|
||||
for typeName, typeInfo := range fieldEnumTypes {
|
||||
for _, typeName := range typeNames {
|
||||
typeInfo := fieldEnumTypes[typeName]
|
||||
var si structInfo
|
||||
si.name = typeName
|
||||
si.prefix = typeInfo.prefix
|
||||
@@ -204,13 +207,6 @@ func structFieldName(f *ast.Field) string {
|
||||
}
|
||||
}
|
||||
|
||||
// Workaround for Go defect (map membership test isn't usable in an
|
||||
// expression).
|
||||
func fetContains(xs map[string]*ast.StructType, x string) bool {
|
||||
_, ok := xs[x]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (si *structInfo) writeTo(b *strings.Builder) {
|
||||
fmt.Fprintf(b, "// A %sField represents a field in %s.\n", si.prefix, si.name)
|
||||
fmt.Fprintf(b, "type %sField uint\n\n", si.prefix)
|
||||
|
||||
Reference in New Issue
Block a user