Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow D-Bus methods to auth. for more than one polkit action #26365

Merged
merged 8 commits into from Jul 14, 2023

Conversation

dtardon
Copy link
Collaborator

@dtardon dtardon commented Feb 8, 2023

The current code handling async. polkit authentication allows a D-Bus method to auth. for at most one action. If the same method tries to auth. for another action, it'll end with -ESTALE. That's a problem for verify_shutdown_creds(), which may need to authenticate for both org.freedesktop.login1.hibernate-multiple-sessions and org.freedesktop.login1.hibernate-ignore-inhibit. This PR extends the handling of async. polkit requests to allow auth. for multiple actions. Unfortunately, it increases complexity of already quite complex code (esp. wrt. memory management)...

Fixes #20155

@github-actions github-actions bot added util-lib please-review PR is ready for (re-)review by a maintainer labels Feb 8, 2023
@github-actions
Copy link

github-actions bot commented Feb 8, 2023

An -rc1 tag has been created and a release is being prepared, so please note that PRs introducing new features and APIs will be held back until the new version has been released.

@yuwata yuwata added this to the v254 milestone Feb 10, 2023
@github-actions

This comment was marked as outdated.

src/shared/bus-polkit.c Outdated Show resolved Hide resolved
@@ -379,6 +473,20 @@ int bus_verify_polkit_async(
if (r < 0)
return r;

if (!qs) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this condition necessary?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is. On the first call of this function (for given call), qs will be NULL.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, here qs is always NULL, no?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. When a dbus method needs to auth. for a polkit action, it calls bus_verify_polkit_async(). The function creates an AsyncPolkitQueries instance (and stores it into registry), an AsyncPolkitQuery instance, and issues an async call to polkit. The dbus method then returns immediately after returning from bus_verify_polkit_async(). When the async call finishes, async_polkit_callback() gets called, which stores the reply in its associated AsyncPolkitQuery object and reschedules the same bus message for processing. This time, when bus_verify_polkit_async() is called, it finds that a query for this call + action combination is already present in registry, hence it just processes the reply and returns. If the method then needs to auth. for another action, it calls bus_verify_polkit_async() again. This time, no existing query is found in the registry (it's a different action than previously), but the AsyncPolkitQueries is (as we're still processing the same bus message), hence qs is set. The function then proceeds with creating another query (so qs contains two items now, each for a different action) and issues another async call to polkit. The dbus method again returns and is later rescheduled by async_polkit_callback(). And so on...

I hope this is at least a bit understandable...

(Btw, if this sounds complicated, it's because it is :-) But most of the complexity is due to the async. nature of this and has already been there before.)


r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0);
if (r < 0) {
async_polkit_query_free(q);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this is dropped?? q seems to be leaked.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not leaked. At this point, q is already managed by qs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, then, I'd like to move LIST_PREPEND in the above after the bus call.

if (!qs)
return NULL;

LIST_FOREACH(item, i, qs->items)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about to store query into a hashmap by the action?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not worth it. In most cases there'll be only one item in the list.

src/shared/bus-polkit.c Outdated Show resolved Hide resolved
src/shared/bus-polkit.c Outdated Show resolved Hide resolved
src/shared/bus-polkit.c Outdated Show resolved Hide resolved
@yuwata yuwata added reviewed/needs-rework 🔨 PR has been reviewed and needs another round of reworks and removed please-review PR is ready for (re-)review by a maintainer labels Feb 22, 2023
@github-actions github-actions bot added please-review PR is ready for (re-)review by a maintainer and removed reviewed/needs-rework 🔨 PR has been reviewed and needs another round of reworks labels Feb 22, 2023
@dtardon dtardon added reviewed/needs-rework 🔨 PR has been reviewed and needs another round of reworks and removed please-review PR is ready for (re-)review by a maintainer labels Feb 22, 2023
@github-actions github-actions bot added please-review PR is ready for (re-)review by a maintainer and removed reviewed/needs-rework 🔨 PR has been reviewed and needs another round of reworks labels Feb 22, 2023
@dtardon
Copy link
Collaborator Author

dtardon commented May 5, 2023

I've added a detailed (and hopefully understandable) explanation how the polkit auth. works. I hope that makes the change easier to understand.

@yuwata yuwata added the rc-blocker 🚧 PRs and Issues tagged this way are blocking the upcoming rc release! label Jun 1, 2023
@poettering
Copy link
Member

hmm, can you split out the first three commits in a PR of its own? we should be able to merge those as generally useful cleanups independently of the rest, once they pass CI.

@poettering
Copy link
Member

hmm, what I don't get about this, wouldn't it suffice to add a new strv field to AsyncPolkitQuery that lists all actions that have already been validated in the current method handling? Then, when we can just check against those whenever we are called, and only do requests for the stuff we haven't validated yet.

@poettering poettering added reviewed/needs-rework 🔨 PR has been reviewed and needs another round of reworks and removed please-review PR is ready for (re-)review by a maintainer labels Jun 14, 2023
@dtardon
Copy link
Collaborator Author

dtardon commented Jun 16, 2023

hmm, can you split out the first three commits in a PR of its own? we should be able to merge those as generally useful cleanups independently of the rest, once they pass CI.

Will do.

@dtardon
Copy link
Collaborator Author

dtardon commented Jun 16, 2023

hmm, what I don't get about this, wouldn't it suffice to add a new strv field to AsyncPolkitQuery that lists all actions that have already been validated in the current method handling? Then, when we can just check against those whenever we are called, and only do requests for the stuff we haven't validated yet.

Does "I haven't thought of that" count as an answer? .-)

@bluca
Copy link
Member

bluca commented Jul 11, 2023

@dtardon this is one of the last remaining few RC1 blockers, will you have time to work on this today or tomorrow? If not, it's ok, but we might bump to the next release

There are no user facing stuff, so actually it's fine to get in a bit later for 254 if you have time to get the review comments sorted this week or next week @dtardon

@github-actions github-actions bot added please-review PR is ready for (re-)review by a maintainer and removed reviewed/needs-rework 🔨 PR has been reviewed and needs another round of reworks labels Jul 13, 2023
@dtardon
Copy link
Collaborator Author

dtardon commented Jul 13, 2023

Btw, #28381 is my attempt to create a test for polkit authentication. Unfortunately, it's not ready yet: the script runs just fine locally, but it always fails (at different places) when I run it as a test. And I have no idea why...

In systemd#20155, verify_shutdown_creds() needs to authenticate for both
org.freedesktop.login1.hibernate-multiple-sessions and
org.freedesktop.login1.hibernate-ignore-inhibit . Previously, the second
authentication attempt would fail with -ESTALE.

Fixes systemd#20155.
@bluca bluca added good-to-merge/waiting-for-ci 👍 PR is good to merge, but CI hasn't passed at time of review. Please merge if you see CI has passed and removed please-review PR is ready for (re-)review by a maintainer labels Jul 13, 2023
@bluca bluca modified the milestones: v255, v254 Jul 14, 2023
@bluca bluca merged commit 0865c46 into systemd:main Jul 14, 2023
40 of 48 checks passed
@github-actions github-actions bot removed the good-to-merge/waiting-for-ci 👍 PR is good to merge, but CI hasn't passed at time of review. Please merge if you see CI has passed label Jul 14, 2023
@dtardon dtardon deleted the multiple-polkit-calls branch July 17, 2023 08:01
@@ -214,7 +220,11 @@ static AsyncPolkitQuery *async_polkit_query_free(AsyncPolkitQuery *q) {

sd_event_source_disable_unref(q->defer_event_source);

async_polkit_query_action_free(q->authorized_action);
while ((a = q->authorized_actions)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LIST_POP()

arnout pushed a commit to buildroot/buildroot that referenced this pull request Aug 9, 2023
…failure

As reported by [1] [2], the return code of systemctl command between
systemd 253 and 254 has changed when the polkit authentication is
refused:

/bin/systemctl restart systemd-timesyncd.service

The return code changed from 1 to 4. The Polkit test case
"TestPolkitSystemd" expected 1 as return code [3].

The service log is not the same either:

systemd v253:
Failed to restart systemd-timesyncd.service: Interactive authentication required.

systemd v254:
Failed to restart systemd-timesyncd.service: Access denied

git bisect report this commit:
systemd/systemd@959301c

From the PR (to get more context):
systemd/systemd#26365

Note: systemd doesn't recommend using systemctl exit code to check unit states:
"The mapping of LSB service states to systemd unit states is imperfect, so it is better to
not rely on those return values but to look for specific unit states and substates instead."

Since we only want to check if the command failed, update our test to
check if systemctl returned a non zero code whatever the reason of the
failure.

Thanks to Yann E. MORIN for the brainstorming!

Fixes:
https://gitlab.com/buildroot.org/buildroot/-/jobs/4768561464 (TestPolkitSystemd)

[1] http://lists.busybox.net/pipermail/buildroot/2023-August/671900.html
[2] https://lists.freedesktop.org/archives/systemd-devel/2023-August/049362.html
[3] https://git.buildroot.net/buildroot/tree/support/testing/tests/package/test_polkit.py?h=2023.08-rc1#n45
[4] https://github.com/systemd/systemd/blob/v254/man/systemctl.xml#L2612

Signed-off-by: Romain Naour <romain.naour@smile.fr>
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
dtardon added a commit to dtardon/systemd that referenced this pull request Aug 17, 2023
An error reply from polkit is a valid case and should not be propagated
as failure of async_polkit_callback(). It should only be saved here.
It'll be returned by bus_verify_polkit_async() later, when it's called
for the same method again.

Follow-up for systemd#26365.
poettering pushed a commit that referenced this pull request Aug 17, 2023
An error reply from polkit is a valid case and should not be propagated
as failure of async_polkit_callback(). It should only be saved here.
It'll be returned by bus_verify_polkit_async() later, when it's called
for the same method again.

Follow-up for #26365.
citral23 pushed a commit to citral23/buildroot that referenced this pull request Sep 18, 2023
…failure

As reported by [1] [2], the return code of systemctl command between
systemd 253 and 254 has changed when the polkit authentication is
refused:

/bin/systemctl restart systemd-timesyncd.service

The return code changed from 1 to 4. The Polkit test case
"TestPolkitSystemd" expected 1 as return code [3].

The service log is not the same either:

systemd v253:
Failed to restart systemd-timesyncd.service: Interactive authentication required.

systemd v254:
Failed to restart systemd-timesyncd.service: Access denied

git bisect report this commit:
systemd/systemd@959301c

From the PR (to get more context):
systemd/systemd#26365

Note: systemd doesn't recommend using systemctl exit code to check unit states:
"The mapping of LSB service states to systemd unit states is imperfect, so it is better to
not rely on those return values but to look for specific unit states and substates instead."

Since we only want to check if the command failed, update our test to
check if systemctl returned a non zero code whatever the reason of the
failure.

Thanks to Yann E. MORIN for the brainstorming!

Fixes:
https://gitlab.com/buildroot.org/buildroot/-/jobs/4768561464 (TestPolkitSystemd)

[1] http://lists.busybox.net/pipermail/buildroot/2023-August/671900.html
[2] https://lists.freedesktop.org/archives/systemd-devel/2023-August/049362.html
[3] https://git.buildroot.net/buildroot/tree/support/testing/tests/package/test_polkit.py?h=2023.08-rc1#n45
[4] https://github.com/systemd/systemd/blob/v254/man/systemctl.xml#L2612

Signed-off-by: Romain Naour <romain.naour@smile.fr>
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
peckato1 pushed a commit to peckato1/systemd that referenced this pull request Jan 16, 2024
An error reply from polkit is a valid case and should not be propagated
as failure of async_polkit_callback(). It should only be saved here.
It'll be returned by bus_verify_polkit_async() later, when it's called
for the same method again.

Follow-up for systemd#26365.

(cherry picked from commit 45b1c01)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
4 participants