https://bugs.openldap.org/show_bug.cgi?id=10659
Issue ID: 10659 Summary: slapo-deref: the cached ACL result is shared between the search entry and the dereferenced entries, disclosing attribute values the client may not read Product: OpenLDAP Version: unspecified Hardware: All OS: All Status: UNCONFIRMED Keywords: needs_review Severity: normal Priority: --- Component: overlays Assignee: bugs@openldap.org Reporter: hamano@osstech.co.jp Target Milestone: ---
- Affected versions: 2.5.20, 2.6.16, master
## Summary
`deref_response()` in slapo-deref passes a single `AccessControlState` to `access_allowed()` for both the search result entry (`rs->sr_entry`) and the dereferenced entries (`e`). The cache in `access_allowed()` does not distinguish entries, so when an attribute that was allowed on one entry is evaluated on another entry, the cached result is used without evaluating the ACLs. As a result, a client sending the Dereference control (not an RFC, draft-masarati-ldap-deref) can receive attribute values in the response control that the ACLs do not allow it to read.
## Details
`servers/slapd/overlays/deref.c`:
```c AccessControlState acl_state = ACL_STATE_INIT; ... if ( !access_allowed( op, rs->sr_entry, a->a_desc, NULL, ACL_READ, &acl_state ) ) /* search result entry */ ... rc = overlay_entry_get_ov( op, &a->a_nvals[ i ], NULL, NULL, 0, &e, dc->dc_on ); ... if ( !access_allowed( op, e, ds->ds_attributes[ j ], NULL,
ACL_READ, &acl_state ) ) /* dereferenced entry */ ...
if ( !access_allowed( op, e,
aa->a_desc,
&aa->a_nvals[ k ],
ACL_READ, &acl_state ) ) ```
`access_allowed_mask()` in `servers/slapd/acl.c` returns the cached `state->as_result` as is when `state->as_desc` and `state->as_access` match and there are no value dependent ACLs (`!state->as_vd_acl_present`). It does not check the entry or the value.
```c if ( state != NULL ) { if ( state->as_desc == desc && state->as_access == access && state->as_result != -1 && !state->as_vd_acl_present ) { Debug( LDAP_DEBUG_ACL, "=> access_allowed: result was in cache (%s)\n", attr ); return state->as_result; ```
`send_search_entry()` initializes an `AccessControlState` for each entry, so it does not have this problem. deref reuses one state across several entries, so the result for another entry is used in the following two cases:
1. The same attribute as derefAttr is requested from the dereferenced entries (e.g. dereference `member` and request `member`). The result for `member` of the search result entry is used for `member` of the dereferenced entries. 2. The same attribute is requested from several dereferenced entries. The result for the first dereferenced entry is used for the second and subsequent ones.
If an "allowed" result is cached, values the client may not read are returned; conversely, if a "denied" result is cached, values the client may read are not returned.
## Impact
With the deref overlay configured, and ACLs that allow or deny reading the same attribute depending on the entry's location (DN), a client that can search (possibly including anonymous, depending on the ACLs) can obtain attribute values it is not allowed to read.
https://bugs.openldap.org/show_bug.cgi?id=10659
--- Comment #1 from HAMANO Tsukasa hamano@osstech.co.jp --- https://git.openldap.org/openldap/openldap/-/merge_requests/951