Skip to content

Commit

Permalink
many: rename prompt remaining permissions to outstanding permissions
Browse files Browse the repository at this point in the history
Signed-off-by: Oliver Calder <[email protected]>
  • Loading branch information
olivercalder committed Dec 18, 2024
1 parent 1f677f1 commit 6c9cc3f
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 64 deletions.
10 changes: 5 additions & 5 deletions interfaces/prompting/requestprompts/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
73 changes: 37 additions & 36 deletions interfaces/prompting/requestprompts/requestprompts.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand All @@ -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)
Expand All @@ -135,17 +135,17 @@ 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
// requested.
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
Expand Down Expand Up @@ -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,
Expand All @@ -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) {
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
26 changes: 13 additions & 13 deletions interfaces/prompting/requestprompts/requestprompts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 := &noticeInfo{promptID: prompt1.ID, data: map[string]string{"resolved": "satisfied"}}
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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 {
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 {
Expand All @@ -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)
Expand Down
12 changes: 6 additions & 6 deletions overlord/ifacestate/apparmorprompting/prompting.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 {
Expand All @@ -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
Expand All @@ -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)

Expand Down Expand Up @@ -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
}
}
Expand Down
Loading

0 comments on commit 6c9cc3f

Please sign in to comment.