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

Qrexec policy daemon #6

Merged
merged 7 commits into from
Feb 20, 2020
Merged

Conversation

marmarta
Copy link
Member

@marmarta marmarta commented Aug 9, 2019

Rewritten qrexec-daemon to use policy daemon instead of running
policy-exec separately for each call. If daemon fails, falls back
to old solution. Also contains some tests.

fixes QubesOS/qubes-issues#5125

@marmarta marmarta force-pushed the qrexec-policy-daemon branch 12 times, most recently from 31de73d to d88a0da Compare August 9, 2019 22:25
@codecov-io
Copy link

codecov-io commented Aug 9, 2019

Codecov Report

Merging #6 into master will increase coverage by 0.02%.
The diff coverage is 89.07%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master       #6      +/-   ##
==========================================
+ Coverage   87.98%   88.01%   +0.02%     
==========================================
  Files          15       19       +4     
  Lines        2506     2771     +265     
==========================================
+ Hits         2205     2439     +234     
- Misses        301      332      +31
Impacted Files Coverage Δ
qrexec/tests/qrexec_policy_daemon.py 100% <100%> (ø)
qrexec/__init__.py 100% <100%> (ø) ⬆️
qrexec/tests/cli.py 100% <100%> (ø) ⬆️
qrexec/tests/policy_cache.py 100% <100%> (ø)
qrexec/tests/policy_parser.py 99.83% <100%> (ø) ⬆️
qrexec/policy/parser.py 81.31% <100%> (+0.05%) ⬆️
qrexec/tools/qrexec_policy_exec.py 81.9% <70.96%> (-4.77%) ⬇️
qrexec/tools/qrexec_policy_daemon.py 71.83% <71.83%> (ø)
qrexec/policy/utils.py 90.69% <90.69%> (ø)
... and 3 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ba755a8...bf57fe5. Read the comment docs.

@marmarta marmarta force-pushed the qrexec-policy-daemon branch 3 times, most recently from 4586fc6 to 12f048f Compare August 9, 2019 22:50
@marmarek
Copy link
Member

I've done some tests. Start situation: qrexec call into dom0 (/bin/true as a service) takes ~380ms. Observations:

  1. Enabling this policy daemon saves ~100ms
  2. qubes-rpc-multiplexer takes about ~130ms
  3. Disabling policy loading on each call (caching it) saves another ~120ms

The second point should be hopefully solved by #3 (for latency critical services).
The third point could be solved by some clever caching the policy, including detection of changes. Or requiring explicit policy reload after modification, but that wouldn't be nice...

@marmarek
Copy link
Member

marmarek commented Dec 3, 2019

Some issues detected during tests:

  • qubes-qrexec-policy-daemon service is not set to autostart (missing enable entry in a preset file)
  • socket is created with wrong permissions (0644 instead of 0660, especially group qubes don't have access, making it impossible to connect)
  • logs about allowed connections are duplicated in journalctl - once as qrexec and then as qrexec-policy-daemon
  • the daemon waits for qrexec-client process to terminate before serving next requests; in case of connection to dom0, this means waiting until the whole connection is terminated; this can be also an issue (untested) for calls into DisposableVM, where the daemon needs to cleanup the VM after connection is terminated

marmarta added a commit to marmarta/qubes-core-admin-linux that referenced this pull request Dec 3, 2019
@marmarta marmarta force-pushed the qrexec-policy-daemon branch 8 times, most recently from a2213ec to 19e79f7 Compare December 7, 2019 01:26
@marmarta marmarta force-pushed the qrexec-policy-daemon branch 3 times, most recently from 5534e24 to e35906a Compare December 7, 2019 12:17
- assume_yes_for_ask=yes
- just_evaluate=yes

Newline-separated
Copy link
Member

Choose a reason for hiding this comment

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

Already mentioned at the beginning.


newline + further

all not compliant responses are bad no good terrible
Copy link
Member

Choose a reason for hiding this comment

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

This should be more formal.

#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2017 Marta Marczykowska-Górecka
Copy link
Member

Choose a reason for hiding this comment

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

2019

functools.partial(qrexec_policy_daemon.handle_client_connection,
log, Mock()),
path=str(tmp_path / "socket.d"))
# because travis is stuck in python3.5, we can't use yield
Copy link
Member

Choose a reason for hiding this comment

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

In the meantime I've updated travis to python 3.7. If you want, you can change it now. But it can stay as is too.

@pytest.mark.asyncio
async def test_wrong_arg(self, mock_request, async_server, tmp_path):

data = b'domains_id=a\n' \
Copy link
Member

Choose a reason for hiding this comment

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

Please add a comment pointing at this typo, or make the wrong arg more explicit.

#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2017 Marta Marczykowska-Górecka
Copy link
Member

Choose a reason for hiding this comment

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

2019

# and then start it back
if systemctl is-enabled qubes-qrexec-policy-daemon.service >/dev/null 2>&1; then
systemctl start qubes-qrexec-policy-daemon.service
fi
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 %posttrans section really necessary? It is in the -vm package, because qubes-qrexec-agent.service was present before in a different package (was moved from qubes-core-agent-linux to qubes-core-qrexec). But the policy daemon wasn't here before.

@@ -1357,7 +1359,7 @@ class FilePolicy(AbstractFileSystemLoader, AbstractPolicy):
... 'qrexec.Service', '+argument', 'source-name', 'target-name',
... system_info=qrexec.utils.get_system_info())
>>> resolution = policy.evaluate(request)
>>> resolution.execute('process-ident')
>>> resolution.execute('process-ident') # this method is asynchroneous
Copy link
Member

Choose a reason for hiding this comment

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

I'd add this for clarity:

Suggested change
>>> resolution.execute('process-ident') # this method is asynchroneous
>>> await resolution.execute('process-ident') # this method is asynchroneous

OPTIONAL_REQUEST_ARGUMENTS


class DaemonResolution(AllowResolution):
Copy link
Member

Choose a reason for hiding this comment

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

DaemonAllowResolution?

Also includes rudimentary protocol documentation.
Contains only pure policy daemon that's not used
by anything yet.
references QubesOS/qubes-issues#5125
Rewritten qrexec-daemon to use policy daemon instead of running
policy-exec separately for each call. If daemon fails, falls back
to old solution.

fixes QubesOS/qubes-issues#5125
Log message and daemon response now are sent before the call
is fully executed.
Fixed daemon socket permissions being wrong.
No more duplicate logs.
Calls are now handled asynchroneously.
Policy parser will now be cached and updated only when changes in policy directories
occured.
@DemiMarie
Copy link
Contributor

@marmarek @marmarta is there still a reason to fall back to the old solution?


[Service]
Type=simple
ExecStart=/usr/bin/qrexec-policy-daemon
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be nice if this used socket activation.

@marmarek
Copy link
Member

marmarek commented Dec 7, 2019

@marmarek @marmarta is there still a reason to fall back to the old solution?

Yes, if policy daemon isn't running/can't start for any reason. Having some kind of fallback is especially useful with GUI VM (qrexec as the only interface to dom0). This is also why socket activation may not be the best idea - it would prevent such fallback from working. On the other hand, automatic restart on crash may be worth adding.

@marmarek
Copy link
Member

I'll merge this PR only after #3, as conflict resolution will be much easier this way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants