From 6c9cc3fad1979ebc4bc7dce95a19262937ccb79c Mon Sep 17 00:00:00 2001 From: Oliver Calder Date: Mon, 16 Dec 2024 17:30:14 -0600 Subject: [PATCH] many: rename prompt remaining permissions to outstanding permissions Signed-off-by: Oliver Calder --- .../prompting/requestprompts/export_test.go | 10 +-- .../requestprompts/requestprompts.go | 73 ++++++++++--------- .../requestprompts/requestprompts_test.go | 26 +++---- .../ifacestate/apparmorprompting/prompting.go | 12 +-- .../apparmorprompting/prompting_test.go | 8 +- 5 files changed, 65 insertions(+), 64 deletions(-) diff --git a/interfaces/prompting/requestprompts/export_test.go b/interfaces/prompting/requestprompts/export_test.go index 2cc1dc1232d..f89f3c79df4 100644 --- a/interfaces/prompting/requestprompts/export_test.go +++ b/interfaces/prompting/requestprompts/export_test.go @@ -33,12 +33,12 @@ const ( MaxOutstandingPromptsPerUser = maxOutstandingPromptsPerUser ) -func NewPrompt(id prompting.IDType, timestamp time.Time, snap string, iface string, path string, remainingPermissions []string, availablePermissions []string, originalPermissions []string) *Prompt { +func NewPrompt(id prompting.IDType, timestamp time.Time, snap string, iface string, path string, outstandingPermissions []string, availablePermissions []string, originalPermissions []string) *Prompt { constraints := &promptConstraints{ - path: path, - remainingPermissions: remainingPermissions, - availablePermissions: availablePermissions, - originalPermissions: originalPermissions, + path: path, + outstandingPermissions: outstandingPermissions, + availablePermissions: availablePermissions, + originalPermissions: originalPermissions, } return &Prompt{ ID: id, diff --git a/interfaces/prompting/requestprompts/requestprompts.go b/interfaces/prompting/requestprompts/requestprompts.go index 281c3df16ae..2350052c660 100644 --- a/interfaces/prompting/requestprompts/requestprompts.go +++ b/interfaces/prompting/requestprompts/requestprompts.go @@ -86,7 +86,7 @@ type jsonPromptConstraints struct { func (p *Prompt) MarshalJSON() ([]byte, error) { constraints := &jsonPromptConstraints{ Path: p.Constraints.path, - RequestedPermissions: p.Constraints.remainingPermissions, + RequestedPermissions: p.Constraints.outstandingPermissions, AvailablePermissions: p.Constraints.availablePermissions, } toMarshal := &jsonPrompt{ @@ -109,10 +109,10 @@ func (p *Prompt) sendReply(outcome prompting.OutcomeType) error { // If outcome is allow, then reply by allowing all originally-requested // permissions. If outcome is deny, only allow permissions which were // originally requested but have since been allowed by rules, and deny any - // remaining permissions. + // outstanding permissions. var deniedPermissions []string if !allow { - deniedPermissions = p.Constraints.remainingPermissions + deniedPermissions = p.Constraints.outstandingPermissions } allowedPermission := p.Constraints.buildResponse(p.Interface, deniedPermissions) return p.sendReplyWithPermission(allowedPermission) @@ -135,7 +135,7 @@ var sendReply = (*listener.Request).Reply // promptConstraints store the path which was requested, along with three // lists of permissions: the original permissions associated with the request, -// the remaining unsatisfied permissions (as rules may satisfy some of the +// the outstanding unsatisfied permissions (as rules may satisfy some of the // permissions from a prompt before the prompt is fully resolved), and the // available permissions for the interface associated with the prompt, so that // the client may reply with a broader set of permissions than was originally @@ -143,9 +143,9 @@ var sendReply = (*listener.Request).Reply type promptConstraints struct { // path is the path to which the application is requesting access. path string - // remainingPermissions are the remaining unsatisfied permissions for which - // the application is requesting access. - remainingPermissions []string + // outstandingPermissions are the outstanding unsatisfied permissions for + // which the application is requesting access. + outstandingPermissions []string // availablePermissions are the permissions which are supported by the // interface associated with the prompt to which the constraints apply. availablePermissions []string @@ -176,7 +176,7 @@ func (pc *promptConstraints) equals(other *promptConstraints) bool { return true } -// applyRuleConstraints modifies the prompt constraints, removing any remaining +// applyRuleConstraints modifies the prompt constraints, removing any outstanding // permissions which are matched by the given rule constraints. // // Returns whether the prompt constraints were affected by the rule constraints, @@ -186,7 +186,7 @@ func (pc *promptConstraints) equals(other *promptConstraints) bool { // other return values can be ignored. // // If the path pattern does not match the prompt path, or the permissions in -// the rule constraints do not include any of the remaining prompt permissions, +// the rule constraints do not include any of the outstanding prompt permissions, // then affectedByRule is false, and no changes are made to the prompt // constraints. func (pc *promptConstraints) applyRuleConstraints(constraints *prompting.RuleConstraints) (affectedByRule, respond bool, deniedPermissions []string, err error) { @@ -202,13 +202,13 @@ func (pc *promptConstraints) applyRuleConstraints(constraints *prompting.RuleCon // Path pattern matched, now check if any permissions match - newRemainingPermissions := make([]string, 0, len(pc.remainingPermissions)) - for _, perm := range pc.remainingPermissions { + newOutstandingPermissions := make([]string, 0, len(pc.outstandingPermissions)) + for _, perm := range pc.outstandingPermissions { entry, exists := constraints.Permissions[perm] if !exists { // Permission not covered by rule constraints, so permission - // should continue to be in remainingPermissions. - newRemainingPermissions = append(newRemainingPermissions, perm) + // should continue to be in outstandingPermissions. + newOutstandingPermissions = append(newOutstandingPermissions, perm) continue } affectedByRule = true @@ -227,9 +227,9 @@ func (pc *promptConstraints) applyRuleConstraints(constraints *prompting.RuleCon return false, false, nil, nil } - pc.remainingPermissions = newRemainingPermissions + pc.outstandingPermissions = newOutstandingPermissions - if len(pc.remainingPermissions) == 0 || len(deniedPermissions) > 0 { + if len(pc.outstandingPermissions) == 0 || len(deniedPermissions) > 0 { // All permissions allowed or at least one permission denied, so tell // the caller to send a response back to the kernel. respond = true @@ -269,10 +269,10 @@ func (pc *promptConstraints) Path() string { return pc.path } -// Permissions returns the remaining unsatisfied permissions associated with -// the prompt. -func (pc *promptConstraints) RemainingPermissions() []string { - return pc.remainingPermissions +// OutstandingPermissions returns the outstanding unsatisfied permissions +// associated with the prompt. +func (pc *promptConstraints) OutstandingPermissions() []string { + return pc.outstandingPermissions } // userPromptDB maps prompt IDs to prompts for a single user. @@ -435,7 +435,7 @@ var timeAfterFunc = func(d time.Duration, f func()) timeutil.Timer { // // The caller must ensure that the given permissions are in the order in which // they appear in the available permissions list for the given interface. -func (pdb *PromptDB) AddOrMerge(metadata *prompting.Metadata, path string, requestedPermissions []string, remainingPermissions []string, listenerReq *listener.Request) (*Prompt, bool, error) { +func (pdb *PromptDB) AddOrMerge(metadata *prompting.Metadata, path string, requestedPermissions []string, outstandingPermissions []string, listenerReq *listener.Request) (*Prompt, bool, error) { availablePermissions, err := prompting.AvailablePermissions(metadata.Interface) if err != nil { // Error should be impossible, since caller has already validated that @@ -464,10 +464,10 @@ func (pdb *PromptDB) AddOrMerge(metadata *prompting.Metadata, path string, reque } constraints := &promptConstraints{ - path: path, - remainingPermissions: remainingPermissions, - availablePermissions: availablePermissions, - originalPermissions: requestedPermissions, + path: path, + outstandingPermissions: outstandingPermissions, + availablePermissions: availablePermissions, + originalPermissions: requestedPermissions, } // Search for an identical existing prompt, merge if found @@ -487,7 +487,7 @@ func (pdb *PromptDB) AddOrMerge(metadata *prompting.Metadata, path string, reque if len(userEntry.prompts) >= maxOutstandingPromptsPerUser { logger.Noticef("WARNING: too many outstanding prompts for user %d; auto-denying new one", metadata.User) // Deny all permissions which are not already allowed by existing rules - allowedPermission := constraints.buildResponse(metadata.Interface, constraints.remainingPermissions) + allowedPermission := constraints.buildResponse(metadata.Interface, constraints.outstandingPermissions) sendReply(listenerReq, allowedPermission) return nil, false, prompting_errors.ErrTooManyPrompts } @@ -594,14 +594,14 @@ func (pdb *PromptDB) Reply(user uint32, id prompting.IDType, outcome prompting.O // contents and, if so, sends back a decision to their listener requests. // // A prompt is satisfied by the given rule contents if the user, snap, -// interface, and path of the prompt match those of the rule, and all remaining -// permissions are covered by permissions in the rule constraints or at least -// one of the remaining permissions is covered by a permission which has an -// outcome of "deny". +// interface, and path of the prompt match those of the rule, and all +// outstanding permissions are covered by permissions in the rule constraints +// or at least one of the outstanding permissions is covered by a rule +// permission which has an outcome of "deny". // // Records a notice for any prompt which was satisfied, or which had some of // its permissions satisfied by the rule contents. In the future, only the -// remaining unsatisfied permissions of a partially-satisfied prompt must be +// outstanding unsatisfied permissions of a partially-satisfied prompt must be // satisfied for the prompt as a whole to be satisfied. // // Returns the IDs of any prompts which were fully satisfied by the given rule @@ -649,17 +649,18 @@ func (pdb *PromptDB) HandleNewRule(metadata *prompting.Metadata, constraints *pr // back to the kernel, and record a notice that the prompt was satisfied. if len(deniedPermissions) > 0 { // At least one permission was denied by new rule, and we want to - // send a response immediately, so include any remaining + // send a response immediately, so include any outstanding // permissions as denied as well. // // This could be done as part of applyRuleConstraints instead, but // it seems semantically clearer to only return the permissions // which were explicitly denied by the rule, rather than all - // remaining permissions because at least one was denied. It's the - // prorogative of the caller (this function) to treat the remaining - // permissions as denied since we want to send a response without - // waiting for future rules to satisfy the remaining permissions. - deniedPermissions = append(deniedPermissions, prompt.Constraints.remainingPermissions...) + // outstanding permissions because at least one was denied. It's + // the prorogative of the caller (this function) to treat the + // outstanding permissions as denied since we want to send a + // response without waiting for future rules to satisfy the + // outstanding permissions. + deniedPermissions = append(deniedPermissions, prompt.Constraints.outstandingPermissions...) } // Build and send a response with any permissions which were allowed, // either by this new rule or by previous rules. diff --git a/interfaces/prompting/requestprompts/requestprompts_test.go b/interfaces/prompting/requestprompts/requestprompts_test.go index b14d28dba99..7f2afc44ad7 100644 --- a/interfaces/prompting/requestprompts/requestprompts_test.go +++ b/interfaces/prompting/requestprompts/requestprompts_test.go @@ -309,7 +309,7 @@ func (s *requestpromptsSuite) TestAddOrMerge(c *C) { c.Check(prompt1.Snap, Equals, metadata.Snap) c.Check(prompt1.Interface, Equals, metadata.Interface) c.Check(prompt1.Constraints.Path(), Equals, path) - c.Check(prompt1.Constraints.RemainingPermissions(), DeepEquals, permissions) + c.Check(prompt1.Constraints.OutstandingPermissions(), DeepEquals, permissions) stored, err = pdb.Prompts(metadata.User, clientActivity) c.Assert(err, IsNil) @@ -553,9 +553,9 @@ func (s *requestpromptsSuite) TestReply(c *C) { // Check that permissions in response map to prompt's permissions abstractPermissions, err := prompting.AbstractPermissionsFromAppArmorPermissions(prompt1.Interface, allowedPermission) c.Check(err, IsNil) - c.Check(abstractPermissions, DeepEquals, prompt1.Constraints.RemainingPermissions()) + c.Check(abstractPermissions, DeepEquals, prompt1.Constraints.OutstandingPermissions()) // Check that prompt's permissions map to response's permissions - expectedPerm, err := prompting.AbstractPermissionsToAppArmorPermissions(prompt1.Interface, prompt1.Constraints.RemainingPermissions()) + expectedPerm, err := prompting.AbstractPermissionsToAppArmorPermissions(prompt1.Interface, prompt1.Constraints.OutstandingPermissions()) c.Check(err, IsNil) c.Check(allowedPermission, DeepEquals, expectedPerm) } else { @@ -695,7 +695,7 @@ func (s *requestpromptsSuite) TestHandleNewRule(c *C) { c.Check(promptIDListContains(satisfied, prompt1.ID), Equals, true) c.Check(promptIDListContains(satisfied, prompt3.ID), Equals, true) - // Read permissions of prompt2 satisfied, but it has one remaining + // Read permissions of prompt2 satisfied, but it has one outstanding // permission, so notice re-issued. prompt1 satisfied because at least // one permission was denied, and prompt3 permissions fully satisfied. e1 := ¬iceInfo{promptID: prompt1.ID, data: map[string]string{"resolved": "satisfied"}} @@ -1028,9 +1028,9 @@ func (s *requestpromptsSuite) TestPromptMarshalJSON(c *C) { } path := "/home/test/foo" requestedPermissions := []string{"read", "write", "execute"} - remainingPermissions := []string{"write", "execute"} + outstandingPermissions := []string{"write", "execute"} - prompt, merged, err := pdb.AddOrMerge(metadata, path, requestedPermissions, remainingPermissions, nil) + prompt, merged, err := pdb.AddOrMerge(metadata, path, requestedPermissions, outstandingPermissions, nil) c.Assert(err, IsNil) c.Assert(merged, Equals, false) @@ -1074,7 +1074,7 @@ func (s *requestpromptsSuite) TestPromptExpiration(c *C) { } path := "/home/test/foo" requestedPermissions := []string{"read", "write", "execute"} - remainingPermissions := []string{"write", "execute"} + outstandingPermissions := []string{"write", "execute"} noticeChan := make(chan noticeInfo, 1) pdb, err := requestprompts.New(func(userID uint32, promptID prompting.IDType, data map[string]string) error { @@ -1090,7 +1090,7 @@ func (s *requestpromptsSuite) TestPromptExpiration(c *C) { // Add prompt listenerReq := &listener.Request{} - prompt, merged, err := pdb.AddOrMerge(metadata, path, requestedPermissions, remainingPermissions, listenerReq) + prompt, merged, err := pdb.AddOrMerge(metadata, path, requestedPermissions, outstandingPermissions, listenerReq) c.Assert(err, IsNil) c.Assert(merged, Equals, false) checkCurrentNotices(c, noticeChan, prompt.ID, nil) @@ -1105,7 +1105,7 @@ func (s *requestpromptsSuite) TestPromptExpiration(c *C) { // Add another prompt, check that it does not bump the activity timeout listenerReq = &listener.Request{} otherPath := "/home/test/bar" - prompt2, merged, err := pdb.AddOrMerge(metadata, otherPath, requestedPermissions, remainingPermissions, listenerReq) + prompt2, merged, err := pdb.AddOrMerge(metadata, otherPath, requestedPermissions, outstandingPermissions, listenerReq) c.Assert(err, IsNil) c.Assert(merged, Equals, false) checkCurrentNotices(c, noticeChan, prompt2.ID, nil) @@ -1120,7 +1120,7 @@ func (s *requestpromptsSuite) TestPromptExpiration(c *C) { // Add prompt again listenerReq = &listener.Request{} - prompt, merged, err = pdb.AddOrMerge(metadata, path, requestedPermissions, remainingPermissions, listenerReq) + prompt, merged, err = pdb.AddOrMerge(metadata, path, requestedPermissions, outstandingPermissions, listenerReq) c.Assert(err, IsNil) c.Assert(merged, Equals, false) checkCurrentNotices(c, noticeChan, prompt.ID, nil) @@ -1160,7 +1160,7 @@ func (s *requestpromptsSuite) TestPromptExpiration(c *C) { // Add prompt again listenerReq = &listener.Request{} - prompt, merged, err = pdb.AddOrMerge(metadata, path, requestedPermissions, remainingPermissions, listenerReq) + prompt, merged, err = pdb.AddOrMerge(metadata, path, requestedPermissions, outstandingPermissions, listenerReq) c.Assert(err, IsNil) c.Assert(merged, Equals, false) checkCurrentNotices(c, noticeChan, prompt.ID, nil) @@ -1220,7 +1220,7 @@ func (s *requestpromptsSuite) TestPromptExpirationRace(c *C) { } path := "/home/test/foo" requestedPermissions := []string{"read", "write", "execute"} - remainingPermissions := []string{"write", "execute"} + outstandingPermissions := []string{"write", "execute"} noticeChan := make(chan noticeInfo, 1) pdb, err := requestprompts.New(func(userID uint32, promptID prompting.IDType, data map[string]string) error { @@ -1236,7 +1236,7 @@ func (s *requestpromptsSuite) TestPromptExpirationRace(c *C) { // Add prompt listenerReq := &listener.Request{} - prompt, merged, err := pdb.AddOrMerge(metadata, path, requestedPermissions, remainingPermissions, listenerReq) + prompt, merged, err := pdb.AddOrMerge(metadata, path, requestedPermissions, outstandingPermissions, listenerReq) c.Assert(err, IsNil) c.Assert(merged, Equals, false) checkCurrentNotices(c, noticeChan, prompt.ID, nil) diff --git a/overlord/ifacestate/apparmorprompting/prompting.go b/overlord/ifacestate/apparmorprompting/prompting.go index 97461bbabd2..0e9813b7dcf 100644 --- a/overlord/ifacestate/apparmorprompting/prompting.go +++ b/overlord/ifacestate/apparmorprompting/prompting.go @@ -212,7 +212,7 @@ func (m *InterfacesRequestsManager) handleListenerReq(req *listener.Request) err return requestReply(req, nil) } - remainingPerms := make([]string, 0, len(permissions)) + outstandingPerms := make([]string, 0, len(permissions)) satisfiedPerms := make([]string, 0, len(permissions)) // we're done with early checks, serious business starts now, and we can @@ -234,7 +234,7 @@ func (m *InterfacesRequestsManager) handleListenerReq(req *listener.Request) err logger.Noticef("error while checking request against existing rules: %v", err) } // No matching rule found - remainingPerms = append(remainingPerms, perm) + outstandingPerms = append(outstandingPerms, perm) } } if matchedDenyRule { @@ -250,7 +250,7 @@ func (m *InterfacesRequestsManager) handleListenerReq(req *listener.Request) err return requestReply(req, allowedPermission) } - if len(remainingPerms) == 0 { + if len(outstandingPerms) == 0 { logger.Debugf("request allowed by existing rule: %+v", req) // We don't want to just send back req.Permission() here, since that @@ -273,7 +273,7 @@ func (m *InterfacesRequestsManager) handleListenerReq(req *listener.Request) err Interface: iface, } - newPrompt, merged, err := m.prompts.AddOrMerge(metadata, path, permissions, remainingPerms, req) + newPrompt, merged, err := m.prompts.AddOrMerge(metadata, path, permissions, outstandingPerms, req) if err != nil { logger.Noticef("error while checking request against prompt DB: %v", err) @@ -390,10 +390,10 @@ func (m *InterfacesRequestsManager) HandleReply(userID uint32, promptID promptin // XXX: do we want to allow only replying to a select subset of permissions, and // auto-deny the rest? - contained := constraints.ContainPermissions(prompt.Constraints.RemainingPermissions()) + contained := constraints.ContainPermissions(prompt.Constraints.OutstandingPermissions()) if !contained { return nil, &prompting_errors.RequestedPermissionsNotMatchedError{ - Requested: prompt.Constraints.RemainingPermissions(), + Requested: prompt.Constraints.OutstandingPermissions(), Replied: replyConstraints.Permissions, // equivalent to keys of constraints.Permissions } } diff --git a/overlord/ifacestate/apparmorprompting/prompting_test.go b/overlord/ifacestate/apparmorprompting/prompting_test.go index 4f4449fe000..1448d23bb03 100644 --- a/overlord/ifacestate/apparmorprompting/prompting_test.go +++ b/overlord/ifacestate/apparmorprompting/prompting_test.go @@ -590,8 +590,8 @@ func (s *apparmorpromptingSuite) TestExistingRulePartiallyAllowsNewPrompt(c *C) } _, prompt := s.simulateRequest(c, reqChan, mgr, partialReq, false) - // Check that prompt was created for remaining "write" permission - c.Check(prompt.Constraints.RemainingPermissions(), DeepEquals, []string{"write"}) + // Check that prompt was created for outstanding "write" permission + c.Check(prompt.Constraints.OutstandingPermissions(), DeepEquals, []string{"write"}) c.Assert(mgr.Stop(), IsNil) } @@ -765,7 +765,7 @@ func (s *apparmorpromptingSuite) TestNewRuleAllowExistingPrompt(c *C) { c.Check(err, NotNil) // Check that rwPrompt only has write permission left - c.Check(rwPrompt.Constraints.RemainingPermissions(), DeepEquals, []string{"write"}) + c.Check(rwPrompt.Constraints.OutstandingPermissions(), DeepEquals, []string{"write"}) // Check that two prompts still exist prompts, err := mgr.Prompts(s.defaultUser, clientActivity) @@ -1097,7 +1097,7 @@ func (s *apparmorpromptingSuite) TestRequestMerged(c *C) { } s.simulateRequest(c, reqChan, mgr, identicalReqAgain, true) - // Now new requests for just write access will have identical remaining + // Now new requests for just write access will have identical outstanding // permissions, but not identical original permissions, so should not merge readReq := &listener.Request{ Permission: notify.AA_MAY_WRITE,