diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2018-06-18 19:45:48 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2018-06-18 19:45:48 +0200 |
| commit | dcb1eebb7ffdd179de39e7cb89ca085368ee69d5 (patch) | |
| tree | 00cd2f8591f0dbb82cade9531b5af050a303127d /prog/resources.go | |
| parent | 920b18be87d248413f549d978d7dd68495a6ea7c (diff) | |
prog: more precise constructor calculation
Currently a call that both accepts and creates a resource
self-justifies itself and thus is always enabled.
A good example is accept call. Accepts are always self-enable
and thus enable all other syscalls that work with the socket.
Calculate TransitivelyEnabledCalls in the opposite direction
to resolve this. Start with empty set of enable syscalls,
then enable syscalls that don't accept any resources,
then enable syscalls that accept resources created by the
previous batch of syscalls, and so on.
This prevents self-enablement of accept.
Diffstat (limited to 'prog/resources.go')
| -rw-r--r-- | prog/resources.go | 128 |
1 files changed, 79 insertions, 49 deletions
diff --git a/prog/resources.go b/prog/resources.go index 68fbe1599..bddb158d9 100644 --- a/prog/resources.go +++ b/prog/resources.go @@ -7,6 +7,13 @@ import ( "fmt" ) +// We need to support structs as resources, +// but for now we just special-case timespec/timeval. +var timespecRes = &ResourceDesc{ + Name: "timespec", + Kind: []string{"timespec"}, +} + func (target *Target) calcResourceCtors(kind []string, precise bool) []*Syscall { // Find calls that produce the necessary resources. var metas []*Syscall @@ -28,6 +35,11 @@ func (target *Target) calcResourceCtors(kind []string, precise bool) []*Syscall metas = append(metas, meta) } } + if kind[0] == timespecRes.Name { + if c := target.SyscallMap["clock_gettime"]; c != nil { + metas = append(metas, c) + } + } return metas } @@ -72,82 +84,100 @@ func isCompatibleResourceImpl(dst, src []string, precise bool) bool { return true } -func (c *Syscall) inputResources() []*ResourceType { - var resources []*ResourceType +func (target *Target) inputResources(c *Syscall) []*ResourceDesc { + var resources []*ResourceDesc + ForeachType(c, func(typ Type) { + if typ.Dir() == DirOut { + return + } + switch typ1 := typ.(type) { + case *ResourceType: + if !typ1.IsOptional { + resources = append(resources, typ1.Desc) + } + case *StructType: + if target.OS == "linux" && (typ1.Name() == "timespec" || typ1.Name() == "timeval") { + resources = append(resources, timespecRes) + } + } + }) + return resources +} + +func (target *Target) outputResources(c *Syscall) []*ResourceDesc { + var resources []*ResourceDesc ForeachType(c, func(typ Type) { switch typ1 := typ.(type) { case *ResourceType: - if typ1.Dir() != DirOut && !typ1.IsOptional { - resources = append(resources, typ1) + if typ1.Dir() != DirIn { + resources = append(resources, typ1.Desc) } } }) + if c.CallName == "clock_gettime" { + resources = append(resources, timespecRes) + } return resources } func (target *Target) TransitivelyEnabledCalls(enabled map[*Syscall]bool) (map[*Syscall]bool, map[*Syscall]string) { supported := make(map[*Syscall]bool) disabled := make(map[*Syscall]string) + canCreate := make(map[string]bool) + inputResources := make(map[*Syscall][]*ResourceDesc) for c := range enabled { - supported[c] = true - } - inputResources := make(map[*Syscall][]*ResourceType) - ctors := make(map[string][]*Syscall) - for c := range supported { - inputs := c.inputResources() - inputResources[c] = inputs - for _, res := range inputs { - if _, ok := ctors[res.Desc.Name]; ok { - continue - } - ctors[res.Desc.Name] = target.calcResourceCtors(res.Desc.Kind, true) - } + inputResources[c] = target.inputResources(c) } for { n := len(supported) - haveGettime := supported[target.SyscallMap["clock_gettime"]] - for c := range supported { - cantCreate := "" - var resourceCtors []*Syscall + for c := range enabled { + if supported[c] { + continue + } + ready := true for _, res := range inputResources[c] { - noctors := true - for _, ctor := range ctors[res.Desc.Name] { - if supported[ctor] { - noctors = false - break - } - } - if noctors { - cantCreate = res.Desc.Name - resourceCtors = ctors[res.Desc.Name] + if !canCreate[res.Name] { + ready = false break } } - // We need to support structs as resources, - // but for now we just special-case timespec/timeval. - if cantCreate == "" && !haveGettime && target.SyscallMap["clock_gettime"] != nil { - ForeachType(c, func(typ Type) { - if a, ok := typ.(*StructType); ok && a.Dir() != DirOut && - (a.Name() == "timespec" || a.Name() == "timeval") { - cantCreate = a.Name() - resourceCtors = []*Syscall{target.SyscallMap["clock_gettime"]} + if ready { + supported[c] = true + for _, res := range target.outputResources(c) { + for _, kind := range res.Kind { + canCreate[kind] = true } - }) - } - if cantCreate != "" { - delete(supported, c) - var ctorNames []string - for _, ctor := range resourceCtors { - ctorNames = append(ctorNames, ctor.Name) } - disabled[c] = fmt.Sprintf("no syscalls can create resource %v,"+ - " enable some syscalls that can create it %v", - cantCreate, ctorNames) } } if n == len(supported) { break } } + ctors := make(map[string][]string) + for c := range enabled { + if supported[c] { + continue + } + for _, res := range inputResources[c] { + if canCreate[res.Name] { + continue + } + if ctors[res.Name] == nil { + var names []string + for _, call := range target.calcResourceCtors(res.Kind, true) { + names = append(names, call.Name) + } + ctors[res.Name] = names + } + disabled[c] = fmt.Sprintf("no syscalls can create resource %v,"+ + " enable some syscalls that can create it %v", + res.Name, ctors[res.Name]) + break + } + } + if len(enabled) != len(supported)+len(disabled) { + panic("lost syscalls") + } return supported, disabled } |
