Bug 526053

Summary: Authorization request blocks all other polkit authorization requests.
Product: [Fedora] Fedora Reporter: Thomas Woerner <twoerner>
Component: polkit-gnomeAssignee: David Zeuthen <davidz>
Status: CLOSED UPSTREAM QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: high Docs Contact:
Priority: high    
Version: rawhideCC: davidz, dcbw, mclasen, nphilipp
Target Milestone: ---Keywords: Reopened
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
: 528456 (view as bug list) Environment:
Last Closed: 2009-11-10 14:39:24 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 528456    

Description Thomas Woerner 2009-09-28 14:45:49 UTC
Description of problem:
While a polkit authorization request dialog is visible, all other polikt requests fail with PolKit.NotAuthorizedException, even those of other applications.

There is no way on the application side (python interface) to determine the cause of the exception. Did the user press cancel or is there another request running or was the password incorrect. Therefore some applications are exiting here, which is bad in the case of request conflicts, but it is needed to stop the application if the user cancelled the authorization.

Version-Release number of selected component (if applicable):
polkit-0.95-0.git20090913.2.fc12

How reproducible:
Always

Steps to Reproduce:
1. terminal 1> pkcheck --allow-user-interaction --process $$ --action-id org.freedesktop.policykit.exec
2. Leave authorization request as is.
3. terminal 2> pkcheck --allow-user-interaction --process $$ --action-id org.fedoraproject.config.firewall.auth

Actual results:
Not authorized.

Expected results:
Second authorization request.

Additional info:

Comment 1 Nils Philippsen 2009-09-28 15:03:47 UTC
NB: NotAuthorizedException is from the wrapper around polkit, meaning that a specific action is not authorized for a subject.

Comment 2 David Zeuthen 2009-09-28 17:31:18 UTC
This is how it is supposed to work - we don't want multiple authentications being shown at the same time. I'm not sure there's a better way to achieve this goal other than refusing to show another authentication dialog.

Also, it is not true that all other requests fail that way. For example, if no authentication is needed for an authorization check, it will succeed. Example

$ pkcheck --action-id org.freedesktop.devicekit.disks.filesystem-mount-system-internal --process $$ -u &
[1] 24944

# authentication dialog for the check above is shown

$ pkcheck --action-id org.freedesktop.devicekit.disks.filesystem-mount --process $$ -u
$ echo $?
0

# cancel dialog

Not authorized.

[1]+  Exit 1                  pkcheck --action-id org.freedesktop.devicekit.disks.filesystem-mount-system-internal --process $$ -u
[davidz@x61 ~]$

Comment 3 David Zeuthen 2009-09-28 17:46:34 UTC
The main thing here is that if you run into a situation where you need to show multiple authentication dialogs at the same time... then your app is broken and you need to redesign it.

The bug summary is short on details - Thomas, perhaps you can explain what you are trying to achieve and why you run into this problem? Thanks.

Comment 4 Thomas Woerner 2009-09-29 09:44:16 UTC
David,

I am talking about two separate applications. It is not possible to get these applications to serialize their authentication requests on application level, because they do not know about each other.

At the moment it is very simple to get all authentication requests for all applications with one simple request to fail. This is some kind of DOS in a fairly simple way.

This is really bad behaviour for a security mechanism in my opinion.

Think about this scenario:

User opens app1, issuing an auth request. User is not closing the dialog. User starts app2 also issuing an auth request. app2 immediately gets "Not Authorized" and exits.

There is only one real solution (out of three) in my opinion:

1) Request serialization
app2 gets blocked in the auth request till the matching dialog can be shown.
  + All requests will be handled (sometimes)
  - blocking, DOS possible

2) Retry exception
app2 gets signalled to try again by retry exception.
  + Apps could retry, because they are aware of the problem.
  - blocking, DOS possible

3) Handle more than one auth request at the same time
Auth request for app2 is shown.
  + All requests  will be handled in a timely manner
  + Non blocking, no DOS possible
  - Some UI work for polkit.

Auth requests do not need to be user driven. If you have for example a service requesting authentication, then it needs to be possible to get the authentication quickly.

Comment 5 Thomas Woerner 2009-09-29 09:45:43 UTC
Other problems with current polkit:

Currently there is no way to get the cause of an unsuccessfull authentication. There are three causes:

1) Timeout (25 seconds)
2) User clicked cancel
3) User entered the wrong password 3 times

Cause 1) is really bad, because 25 seconds are really short. 
Example: User has not seen the request because there has been someone at the phone.

There needs to be a way to get this information on application level.

Comment 6 David Zeuthen 2009-09-29 15:40:21 UTC
(In reply to comment #4)
> Auth requests do not need to be user driven. 

Indeed they do. The whole idea behind the "ask for authentication when doing an authorization check" dance (e.g. passing ALLOW_USER_INTERACTION) is that we want the _human_ in front of the session to prove he really is the user (by authenticating as the user) or that he really is the administrator (by authenticating as the administrator).

So if you pass ALLOW_USER_INTERACTION for a non-user-driver authorization check, then the user gets to see random authentication dialogs popup in their session. That's not going to work, it's a totally poor user experience and also undermines whatever trust the user might have had in the machine. Thomas, why would you ever think that's a good idea?

By the same token, apps don't randomly start a PAM authentication session; that's not how PAM is supposed to be working.

If apps needs to do what you want, e.g. do authorization checks for non-user-driver events, you need to avoid passing the ALLOW_USER_INTERACTION flag.

(I assume here that with "user driven" you mean that authorization checks are only done on operations triggered from actions performed by the user. Such as clicking a button in the UI or attaching hardware or whatnot.)

> If you have for example a service
> requesting authentication, then it needs to be possible to get the
> authentication quickly.  

No, apps just _cannot_ assume there's even an authentication agent available. Nor can apps assume how the authentication app works. For example, for trusted path, an authentication agent may be a separate device (with a small display and button) or an app running on an iphone etc etc.

FYI, the authentication agent in GNOME used to grab the screen and keyboard so there was _no way_ that the user could trigger other actions. For technical reasons (involving a11y) we no longer do this. We really need to make it system modal but that's a GNOME problem.

Comment 7 David Zeuthen 2009-09-29 15:43:28 UTC
(In reply to comment #5)
> Other problems with current polkit:
> 
> Currently there is no way to get the cause of an unsuccessfull authentication.
> There are three causes:
> 
> 1) Timeout (25 seconds)
> 2) User clicked cancel
> 3) User entered the wrong password 3 times
> 
> Cause 1) is really bad, because 25 seconds are really short. 
> Example: User has not seen the request because there has been someone at the
> phone.
> 
> There needs to be a way to get this information on application level.  

No, I will not provide this information because if I did... then people would adapt their apps with complicated workarounds so it worked with one particular implementation of an Authentication Agent.

The main problem here is that you apparently want to write apps that randomly pops up authentication dialogs. That's a no-no.

Comment 8 David Zeuthen 2009-09-29 16:02:02 UTC
Upstream commit with clarification about when AllowUserInteraction shouldn't be used: 

http://cgit.freedesktop.org/PolicyKit/commit/?id=ce29effd0d2405e2adea7dc496be8ed841083ed1

Comment 9 David Zeuthen 2009-09-29 16:11:25 UTC
(In reply to comment #5)
> 1) Timeout (25 seconds)

Btw, this is a problem with the D-Bus client code you are using. With libpolkit-gobject-1 this works just fine (just try 'pkexec bash'). You need to set the timeout to something like INT32_MAX (which in D-Bus happens to mean 'forever', not 49ish days) when calling the CheckAuthorization() D-Bus method on the Authority.

Comment 10 David Zeuthen 2009-09-29 16:15:17 UTC
(In reply to comment #7)
> The main problem here is that you apparently want to write apps that randomly
> pops up authentication dialogs. That's a no-no.  

FWIW, we had a similar problem with automounting volumes. The way it works is that when your login session starts, we want automount all attached volumes. This caused authentication dialogs to appear. We fixed that by making the Mount() method in DeviceKit-disks take a 'auth_no_user_interaction' option and if this option was passed, we didn't pass ALLOW_USER_INTERACTION when checking with the authority. See

 https://bugs.freedesktop.org/show_bug.cgi?id=22652

for more details.

Comment 11 Nils Philippsen 2009-09-30 09:57:33 UTC
Hmm, maybe my assumptions are bad (been there, done that), but right now it seems to me that a second request to polkitd to get the auth via an agent would have to end up with "sorry, can't do that right now, can't tell you why either" in the front end, or does polkitd give that information back to the requesting application, e.g. in the details dict? In that case the app could tell the user that there's a second authentication ongoing which needs to be finished first.

Comment 12 David Zeuthen 2009-09-30 23:09:21 UTC
(In reply to comment #11)
> Hmm, maybe my assumptions are bad (been there, done that), but right now it
> seems to me that a second request to polkitd to get the auth via an agent would
> have to end up with "sorry, can't do that right now, can't tell you why either"
> in the front end, or does polkitd give that information back to the requesting
> application, e.g. in the details dict? In that case the app could tell the user
> that there's a second authentication ongoing which needs to be finished first.  

I suppose we could add such a thing. But would it be meaningful? I mean, are there any legitimate examples where you'd have two authorization checks with ALLOW_USER_INTERACTION pending? (I'm not trying to troll here)

If there really are such examples (I doubt it) maybe a better course of action is to just queue up the authorization checks inside the polkit daemon. At least that will move complexity out of clients wanting to do this. And it probably wouldn't be too hard to do that. 

Anyway, I'd hate to do something like this because it is almost an invitation to write code that spams the user with authentication dialogs. E.g. enforcing behavior and patterns on users is normally a Good Thing.

PS: Btw, even if we don't find a reasonable reason for doing this today, nothing prevents us from adding queuing in the future.

PPS: The theoretical Denial Of Service attacks mentioned in comment 4 don't apply. First, the message bus will throttle all connected clients (see dbus-daemon man page) to you can't make polkitd run out of memory. 

Second, you need to be either uid 0 or the uid owning the session to pop up a dialog in a session. If you are uid 0, then all bets are off. If you are the uid for the session, it's easier to just use X (you can trivially find $DISPLAY via /proc if you don't know it) to draw windows...

Comment 13 Thomas Woerner 2009-10-12 10:14:48 UTC
I am reopening this, because currently you could have more than one user-initiated auth requests at a time. Before this is fixed (for all desktops and also using window managers), this is a serious problem.

I'd suggest to add an exception to make it clear to the application that there is another auth request active already. This is the only way an app could be sure that the user want to start it and that he/she did not clicked the abort button.

Comment 14 David Zeuthen 2009-10-16 22:08:53 UTC
(In reply to comment #13)
> I am reopening this, because currently you could have more than one
> user-initiated auth requests at a time. Before this is fixed (for all desktops
> and also using window managers), this is a serious problem.

Listen, Thomas, I asked for _specific_ examples in comment 12. You didn't provide any. Yet you reopened the bug with hand-wavy reasons. This is pissing me off.

> I'd suggest to add an exception to make it clear to the application that there
> is another auth request active already. This is the only way an app could be
> sure that the user want to start it and that he/she did not clicked the abort
> button.

No, it would be much better to just queue up authorization requests so this is transparent. I said that in comment 12 as well.

I'm keeping this bug open because it's easier for me to give you guys rope than keep having to explain over and over why you shouldn't hang yourself. This is by no means a blocker bug (unless it's a blocker to allow people to write broken apps) so I'm removing it from the list.

Comment 15 Thomas Woerner 2009-10-19 10:18:13 UTC
David,

this here is from Comment #4:

> User opens app1, issuing an auth request. User is not closing the dialog. User
> starts app2 also issuing an auth request. app2 immediately gets "Not
> Authorized" and exits.

Just replace app* with something using polkit v1 authorization requests in F-12 or rawhide:

1) Start app1 = system-config-services
2) Select a service and klick on stop, auth request dialog appears, leave it as
3) Start app2 = system-config-firewall from menu, control center or a shell, click on close of welcome dialog
4) See error dialog

This error dialog is bad, because it will be shown for the following reasons:
a) There is another auth request already running
b) The user clicked on cancel in the system-config-firewall auth dialog
c) The user entered a wrong password 3 times in the system-config-firewall auth dialog

The problem here is a). If there is no error dialog here at all, then the app will exit after it got "Not Authorized" from the auth request. There is no way to see if cases a) or b) and c) happened. In case of b) and c), the app can exit, but it should not do this in case of a). This will be a very bad user experience: Clicking to start something and nothing happens. The error dialog in the only way to tell the user that something went wrong.

Also see comment #11 from Nils.

Comment 16 David Zeuthen 2009-11-10 14:39:24 UTC
Actually now that I look at the code, multiple outstanding requests has been supported by day one and it's up to the Authentication Agent to decide if it wants to service multiple requests at the same time. So reassigning the component.

Anyway, this upstream commit

http://git.gnome.org/cgit/PolicyKit-gnome/commit/?id=f32cb7faa7197b9db55b569677732742c3c7fdc1

in the Authentication Agent now provides this feature - the current policy is to serialize authentication requests. Close as UPSTREAM. This will be available in a (zero-day) update to F12.

Comment 17 Dan Williams 2009-12-07 07:20:13 UTC
*** Bug 544534 has been marked as a duplicate of this bug. ***