RFC: Altering the processing of IPv4 (aka Host) ACLs to enforce negative rights

Jeffrey E Altman <[email protected]> Mon, 20 Mar 2023 16:21:12 -0400
Newsgroups gmane.comp.file-systems.openafs.general
Organization AuriStor, Inc.
Message-ID <[email protected]>
On 7 March Andrew Deason submitted a patch to OpenAFS documenting the 
existing behavior of the OpenAFS fileserver when computing Anonymous and 
Caller Access Rights if the IPv4 address from which the RXAFS RPC was 
received matches a PTS host entry and that PTS entry matches an Access 
Control Entry (ACE).

https://gerrit.openafs.org/#/c/15340/

Quoting Andrew's submission to the fs_setacl man page:

    "Combining _Negative rights_ granted from machine entries (IP
    addresses) and _Normal rights_ granted from non-machine entries (or
    vice versa) will generally not work as expected. Permissions granted
    by machine entries and by non-machine entries are calculated
    separately, and both sets of permissions are given to an accessing
    user. For example, if permissions are granted to an authenticated
    user or group (or _system:anyuser_), you cannot remove those
    permissions from specific hosts by adding machine entries to a group
    in an ACL in the _Negative rights_> section."

The IBM AFS Administrator's Guide "Protecting Data in AFS" section states:

    "When determining what type of access to grant to a user, theFile
    Server first compiles a set of permissions by examiningall of the
    entries in the Normal rights section of the ACL. Itthen subtracts
    any permissions associated with the user (orwith groups to which the
    user belongs) on the Negative rightssection of the ACL. Therefore,
    negative permissions alwayscancel out normal permissions."

IBM/Transarc AFS 3.2 introduced the granting of permissions based upon 
the host's IPv4 address in addition to those granted to the caller. The 
implementation evaluates the caller's rights independently of the host's 
rights and then ORs the results. This approach violates the statement 
that negative permissions always cancel out normal (aka positive) 
permissions. If a caller is granted "read" but there is a matching 
negative "read" ACE (aka permission) for the host, the negative "read" 
ACE is ignored. Likewise if "lookup" is granted to the host but the 
caller matches a negative "lookup" ACE, then the caller's negative 
"lookup" ACE is ignored.

The problem can be demonstrated with a couple of examples.   First, lets 
define some PTS entities and membership relations:

  * user: jane = 1000
      o member: system:authusers
      o member: system:anyuser
      o member: no-admin
  * user: 128.66.0.130 = 2000
      o member: local-hosts
  * group: no-admin = -100
      o member: jane
  * group: local-hosts = -500
      o member: 128.66.0.130

Example 1:  RXAFS RPC received from a host that is not a member of 
local-hosts

ACL

  * system:anyuser: l; -none
  * system:authuser: lrk; -none
  * jane: none; -r
  * local-hosts: r; -none

Rights:

  * system:anyuser: lookup
  * system:authuser: lookup, read, lock
  * jane: lookup, lock

When "jane" accesses a file with this ACL the granted rights will be 
"lk" because the negative read permission cancels the positive read 
permission granted by the membership in the system:authuser group.


Example 2: RXAFS RPC received from a host that is a member of local-hosts

ACL

  * system:anyuser: l; -none
  * system:authuser: lrk; -none
  * jane: none; -r
  * local-hosts: r; -none

Rights:

  * system:anyuser: lookup, read
  * system:authuser: lookup, read, lock
  * jane: lookup, read, lock

In this case, even though "jane" is denied the "read" permission granted 
to members of "system:authuser" because of the negative "read" in the 
"jane" ACE she is granted the permission because of the positive read 
permission granted to "local-hosts" members. The granting of "read" 
permission to "jane" is an unexpected result!


Example 3: RXAFS RPC received from a host that is not a member of 
local-hosts

ACL

  * system:anyuser: l; -none
  * system:authuser: lrk; -none
  * jane: lrkwid; -none
  * local-hosts: none; -wida

Rights:

  * system:anyuser: lookup
  * system:authuser: lookup, read, lock
  * jane: lookup, read, lock, write, insert, delete

In this case, "jane" is granted all of the permissions other than "admin".


Example 4: RXAFS RPC received from a host that is a member of local-hosts

ACL

  * system:anyuser: l; -none
  * system:authuser: lrk; -none
  * jane: lrkwid; -none
  * local-hosts: none; -wida

Rights:

  * system:anyuser: lookup
  * system:authuser: lookup, read, lock
  * jane: lookup, read, lock, write, insert, delete

In this case, "jane" is granted all of the permissions other than 
"admin".   However, because the RPC was issued from a host that is a 
member of "local-hosts" the expected result would be "jane" receiving 
only the "lookup, read, lock" rights.    The granting of "write, insert 
and delete" permission is an unexpected outcome!


In examples 2 and 4 rights are granted to the caller that would appear 
to be contrary to the explicit use of negative rights in the access 
control entries.  The example 4 use case might represent client systems 
which are intended to be read-only consumers of the /afs content but 
which might be vulnerable to exploitation.   Example 2 is intended to 
always deny read privileges to "jane" but if she can gain access to the 
host with IPv4 address 128.66.0.130 she can bypass those restrictions.

This behavior feels like a bug to me. A bug that has been present since 
the release of AFS 3.2 more than thirty years ago but a bug 
nevertheless.  I propose that OpenAFS fix the broken behavior so that 
ACL interpretation is consistent with the documentation inherited from IBM.

Two commits submitted to Gerrit will enforce negative access rights.

https://gerrit.openafs.org/#/c/15344/
https://gerrit.openafs.org/#/c/15345/


History:

AFS 3.1 and earlier did not have a concept of IP or Host ACLs.   That 
functionality was introduced in AFS 3.2.  However, the implementation 
that is present in the release version of AFS 3.2 and in use to this day 
might not have been the original implementation.    Today's fileserver 
issues separate calls to the protection service to obtain the caller's 
Current Protection Set (CPS) and the host's CPS.   The fileserver then 
computes the caller rights by comparing the caller's CPS to the object's 
ACL; and it computes the host's rights by comparing the host's CPS to 
the object's ACL.   The fileserver then grants the caller all rights 
granted to both the caller and the host.

The host's CPS is obtained by the fileserver by issuing the 
PR_GetHostCPS RPC.  PR_GetHostCPS differs from PR_GetCPS in that it 
matches the host's IPv4 address using wildcard pattern matching when 
searching for a matching PTS ID.  It also does not treat the PTS entity 
as a member of the system:anyuser group.

Before PR_GetHostCPS was added to the protection service another RPC was 
introduced, PR_GetCPS2 which obtained the CPS for the combination of a 
caller and a host. An implementation of IP ACLs that used PR_GetCPS2 
would have behaved as expected because the all of the positive rights 
would have been computed and from those all of the negative rights would 
have been removed.  I do not have access to the source code for a 
version of the fileserver that used the PR_GetCPS2 RPC but I can imagine 
that a likely implementation would have issued a PR_GetCPS2 call for 
(anonymous, host) and (caller, host).   The additional load these RPCs 
placed on the protection service might have been deemed too expensive.  
As a result, the alternative approach using the PR_GetHostCPS was 
introduced.

Whatever the motivation for PR_GetHostCPS in preference to PR_GetCPS2, 
the existing implementation does not interpret ACLs in a manner that 
permits negative rights to be superior to positive rights.   Perhaps it 
didn't occur to the implementer that there was a problem; and it didn't 
occur to anyone that a simple change to acl_checkRights() and the 
fileserver GetRights() function would permit computing the expected results.


Proposal:

I propose that OpenAFS treat the current behavior as a bug.  The use of 
negative rights is discouraged because they are hard to analyze.  It is 
hoped that their use is rare.  If negative rights are not in use, then 
changing the behavior when IP ACLs exist will not alter the computed 
outcome.  However, if negative rights are in use, they are likely being 
used because it wasn't easy to limit the access any other way.  In which 
case, granting more access then was specified is problematic.   A CVE 
can be published to document the existing behavior and the behavior as 
it will appear beginning with a specific version of the fileserver.

If required, a configuration option can be provided to enable the AFS 
3.2 behavior until all of the fileservers within a cell have been 
updated.   I discourage using a configuration option to enable the 
stricter interpretation of ACLs as that will result in some sites being 
vulnerable when they did not intend to be.


Jeffrey Altman

P.S. I am writing this letter publicly as opposed to sending it to the 
openafs-security queue because the behavior in question is public and 
Andrew's proposed patch to the OpenAFS man pages is public.
smime.p7s (application/pkcs7-signature, 3.9 KB) - not displayed