[SERVER-54216] killAllSessions produces authorization error while killing own sessions Created: 02/Feb/21  Updated: 08/Jan/24  Resolved: 19/Apr/21

Status: Closed
Project: Core Server
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Oleg Pudeyev (Inactive) Assignee: Backlog - Security Team
Resolution: Won't Fix Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
is related to DRIVERS-1577 Workarounds for killAllSessions in un... Implementing
Assigned Teams:
Server Security
Operating System: ALL
Sprint: Security 2021-03-08, Security 2021-03-22, Security 2021-04-05
Participants:

 Description   

https://docs.mongodb.com/manual/reference/command/killAllSessions/ says:

> If the deployment enforces authentication/authorization, you must have the killAnySession to run the killAllSessions command.

> Users can kill their own sessions even without killAnySession privilege action.

I wrote a test program that created an unprivileged user and tried to kill this user's session:

require 'mongo'
 
ac = Mongo::Client.new('mongodb://dev:dev@localhost:14430/admin')
 
ac.database.users.remove('u') rescue nil
ac.database.users.create('u', password: 'u', roles: [])
 
c = Mongo::Client.new('mongodb://u:u@localhost:14430/test?authSource=admin')
 
c.command(killAllSessions: [{user: 'u', db: 'admin'}])

This produced an error:

/home/w/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/mongo-2.14.0/lib/mongo/operation/result.rb:343:in `raise_operation_failure': not authorized on test to execute command { killAllSessions: [ { user: "u", db: "admin" } ], $db: "test", $readPreference: { mode: "primary" }, $clusterTime: { clusterTime: Timestamp(1612295875, 2), signature: { hash: BinData(0, FC221A2F292297A116C77126E8DFBB14A4A232EC), keyId: 6924477619006078979 } }, lsid: { id: UUID("bbd5742e-9f38-4137-b644-c94371244b69") } } (13) (on localhost:14430) (Mongo::Error::OperationFailure)

It seems the server is not behaving as documented by not allowing the user to kill their own sessions.

The session killing is part of unified test runner requirements (https://github.com/mongodb/specifications/blob/master/source/unified-test-format/unified-test-format.rst). On Atlas the killAllSession privilege is not granted to any user and is not grantable (https://jira.mongodb.org/browse/DOCSP-14305), and with the user being unable to kill their own sessions per this ticket the unified test runner cannot be executed on Atlas at all it seems (as part of https://jira.mongodb.org/browse/DRIVERS-828).



 Comments   
Comment by Sergey Galtsev (Inactive) [ 01/Apr/21 ]

Putting this ticket into scheduling queue, so that we can agree on design and properly scope and assign

Comment by Oleg Pudeyev (Inactive) [ 31/Mar/21 ]

I expect it will be easier for drivers to simply not kill sessions (or, more precisely, make session killing conditional).

Comment by Sergey Galtsev (Inactive) [ 31/Mar/21 ]

oleg.pudeyev I was offering a workaround to use combination of $listSessions and killSessions commands, would that not fulfill your needs?

Comment by Oleg Pudeyev (Inactive) [ 31/Mar/21 ]

It is my understanding that drivers currently use killAllSessions to abort any in-progress transactions when testing transactions. Without this, test suites can hang for long times when open transactions make operations stuck (I believe dropping databases might be an example of an operation that would get stuck if there are open transactions on that database?)

killAnySession privilege is not implemented by Atlas. Therefore we are unable to killAllSessions in Atlas.

As a workaround, drivers are configuring themselves to not killAllSessions when running Atlas maintenance tests. I believe this workaround is sufficient for the time being. If the server feels that any change to killAllSessions is non-trivial, I will communicate this in DRIVERS-1577 with the expectation that drivers will be formally required to not killAllSessions when running Atlas maintenance tests.

Comment by Sergey Galtsev (Inactive) [ 31/Mar/21 ]

oleg.pudeyev I got the subject reviewed with spencer.jackson, and there are a couple of points:

listsessions+killsessions and session id collision

this is an event which is so rare that we consider it impossible. There was a discussion previously, I believe schwerin and mira.carey@mongodb.com were involved, and the outcome was: session ids can be considered to be unique at all times

killAllSessions to allow working without killAnySession privilege

this is not how it works now, but the change is possible, and it could work in several ways:

  • killAllSessions when run without a killAnySession privilege kills all sessions it has access to and ignores any "access denied" errors. It also implies, that there is never an "access denied" to this call
  • killAllSessions can have a second boolean optional parameter indicating that only own sessions must be killed. This will allow running it without killAnySession privilege
  • killAllSessions when run without a killAnySession can return errors and indicate which sessions were not killed due to access denied, but only when the session has listSessions action privilege, so that to only reveal existence of other sessions if it already has an access to see them
  • killAllSessions can operate without killAnySession privilege, but only when a filter specified with a single object matching own userid and db. This is doable, but a bit clunky, and has potential for bugs

We probably need to make this a feature ticket to get this going, so that we can formally change behavior, since there is so many options and a design review is in order to get an agreement how we implement this.

oleg.pudeyev please indicate if killing own sessions via a single call is an absolute must for drivers, or you can get away with listsessions+killsessions . If it's a former, we should start a feature design

Comment by Oleg Pudeyev (Inactive) [ 31/Mar/21 ]

sergey.galtsev The documentation at https://docs.mongodb.com/manual/reference/command/killAllSessions/ does not say anything about the command returning a list of sessions it failed to kill.

Generally to iterate an unbounded list, drivers must receive a cursor from the server. The documentation doesn't state that killAllSessions returns a cursor either (and cursors must be cleaned up, so simply returning one without the driver expecting it won't be great too).

If killAllSessions does indeed return a list of sessions it failed to kill, this should be documented in the documentation. I suspect it doesn't return such a list.

The documentation also states precedent for killAllSessions ignoring some of the requested sessions:

(1, 2) The killAllSessions operation ignores sessions that have transactions in prepared state. See Behavior for details.

Ignoring other sessions (such as those from other users) seems consistent with existing behavior.

Using listsessions+killsessions would, I think, cause at least the following problem:

1. User A via application P creates a session S.
2. User A (now logged in via a shell) wants to kill all sessions. The list of sessions is retrieved which includes S.
3. The application P is done with session S and deletes it.
4. Application Q, running via user B, creates a session which happens to be named S.
5. User A issues killsessions for many sessions including S.

Now, either the killsessions in step 5 has to fail, or failure to kill someone else's session is silent and not reported by the server. If the former happens, what is the user A to do when session killing fails? If the latter happens, it would be much easier for user A to use killallsessions and for that command to ignore sessions that the user A isn't allowed to kill.

Comment by Sergey Galtsev (Inactive) [ 31/Mar/21 ]

The manual page of killAllSessions states:

If the deployment enforces authentication/authorization, you must have the killAnySession to run the killAllSessions command.

With this in mind, the behavior described in the ticket is as-designed. Users can indeed kill their own sessions, they just can not use killAllSessions command to do it.

Reasoning behind this behavior: We can't let killAllSessions just kill sessions it has access to and leave the other sessions alone, because there is no consistent way to provide feedback without revealing potentially secure information. When some sessions are killed and some are not, do we provide list of session we failed to kill? If yes, then we just revealed to the user some information said user didn't have access to. If no, do we fail or succeed? If we fail, then we just revealed that there are sessions current user has no access to - this is still leakage of security information.

oleg.pudeyev can you please check if your requirements could be satisfied using a combination of $listSessions and killSessions commands?

Comment by Jeremy Mikola [ 05/Mar/21 ]

shreyas.kalyan: Does this bug also apply to killAllSessionsByPattern. Note that it says "Users can kill their own sessions even without killAnySession privilege action."

I'm specifically considering the case where we might want to use killAllSessionsByPattern to kill individual sessions (owned by the currently authenticated user) by their LSID and not the users/roles patterns.

Generated at Thu Feb 08 05:32:57 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.