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

Add boot mode support #653

Merged
merged 1 commit into from
Mar 9, 2025
Merged

Conversation

ArrayBolt3
Copy link
Contributor

@ArrayBolt3 ArrayBolt3 commented Feb 13, 2025

This PR is intended to add support for boot modes as specified here: QubesOS/qubes-issues#9750 (comment) This naturally only handles the backend part of things, the frontend will need its own PR against qubes-manager.

This is incomplete - I have not yet actually added the part that listens for qvm-request-features calls from TemplateVMs and sets boot mode features appropriately.

This implements (or rather, will implement) the backend component needed to implement QubesOS/qubes-issues#9750.

@ArrayBolt3
Copy link
Contributor Author

ArrayBolt3 commented Feb 14, 2025

Most of the backend is now working, however see QubesOS/qubes-issues#9775, which blocks this from being fully functional. (EDIT: The linked bug report has been fixed by Marek, thus this is no longer blocked.)

@ArrayBolt3 ArrayBolt3 force-pushed the arraybolt3/boot-modes branch from 8a8dc7d to f8270e6 Compare February 24, 2025 01:20
@ArrayBolt3 ArrayBolt3 changed the title (wip) Add boot mode support Add boot mode support Feb 24, 2025
@ArrayBolt3 ArrayBolt3 marked this pull request as ready for review February 24, 2025 01:21
@ArrayBolt3 ArrayBolt3 force-pushed the arraybolt3/boot-modes branch from f8270e6 to 222d0ef Compare February 24, 2025 01:23
@ArrayBolt3
Copy link
Contributor Author

This is now ready for review. This should be merged at the same time as the corresponding frontend PR, QubesOS/qubes-manager#407.

@marmarek
Copy link
Member

The first thing I see - this needs unit tests. See qubes/tests/ dir. You are most likely interested in ext.py and vm/qubes.py there.

@ArrayBolt3
Copy link
Contributor Author

Yep, I figured those were probably necessary. I'm working on those now.

@ArrayBolt3 ArrayBolt3 force-pushed the arraybolt3/boot-modes branch from 222d0ef to 2278612 Compare February 24, 2025 04:57
@ArrayBolt3
Copy link
Contributor Author

Unit tests now added (and broken ones fixed). They may need to be enhanced though, not all of the new code is tested because I haven't figured out how to make the defaults mechanism work seamlessly in the mocks. Not sure if that's even possible, or desirable.

@marmarek
Copy link
Member

and see also CI - both pylint and black complain

@ArrayBolt3
Copy link
Contributor Author

Thanks for the very thorough review! Will work through these issues and then request another review once ready.

@ArrayBolt3
Copy link
Contributor Author

@marmarek What would you think about me reorganizing the boot mode feature names from boot-mode.bootmodename.kernelopts to boot-mode.kernelopts.bootmodename and the like? Right now I'm using regex matching to find boot mode related features, when I could be using str.startswith() if it was flipped around. That would probably come with performance advantages and less risk of security-related issues.

@marmarek
Copy link
Member

@marmarek What would you think about me reorganizing the boot mode feature names from boot-mode.bootmodename.kernelopts to boot-mode.kernelopts.bootmodename and the like? Right now I'm using regex matching to find boot mode related features, when I could be using str.startswith() if it was flipped around. That would probably come with performance advantages and less risk of security-related issues.

Fine with me.

@ArrayBolt3 ArrayBolt3 force-pushed the arraybolt3/boot-modes branch 2 times, most recently from bc4c000 to 3d15788 Compare February 26, 2025 02:12
@ArrayBolt3
Copy link
Contributor Author

Still need to deal with pylint and black issues, the ext unit tests, and look at the default boot mode name stuff a bit more. Pushed what I had so far since it resolved most issues.

@ArrayBolt3 ArrayBolt3 force-pushed the arraybolt3/boot-modes branch from 3d15788 to 6041b90 Compare February 26, 2025 04:51
@ArrayBolt3 ArrayBolt3 requested a review from marmarek February 26, 2025 05:03
@ArrayBolt3
Copy link
Contributor Author

This should now be ready for another review. I still haven't figured out the default boot mode name stuff, but everything else should now be dealt with.

@marmarek
Copy link
Member

black issues

hint: black -l80 qubes will do the job for you

@ArrayBolt3
Copy link
Contributor Author

@marmarek The problem I'm running into with trying to add a default boot mode name is that in qubes-builderv2, initialize_widget_for_property, the value used to fill in the default entry is the value of the property, not the associated name of the property. I think that could probably be fixed, and if so, adding a default boot mode name should be doable.

@ArrayBolt3 ArrayBolt3 force-pushed the arraybolt3/boot-modes branch from d1c6e0f to 975b945 Compare March 2, 2025 18:44
@ArrayBolt3
Copy link
Contributor Author

Did another push because black had to reformat some things.

@marmarek
Copy link
Member

marmarek commented Mar 3, 2025

pylint complains...

@ArrayBolt3
Copy link
Contributor Author

Fighting with event handler regression test issues, not ready for review yet...

@ArrayBolt3 ArrayBolt3 force-pushed the arraybolt3/boot-modes branch from c063813 to a6b1df5 Compare March 5, 2025 04:00
@ArrayBolt3
Copy link
Contributor Author

@marmarek I tried to fix the pylint issues, which seems to have made it happy, but the regression tests now fail:

======================================================================
ERROR: qubes.tests.vm.qubesvm/TC_90_QubesVM/test_811_default_bootmode
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib64/python3.13/contextlib.py", line 85, in inner
    return func(*args, **kwds)
  File "/home/user/qubes-core-admin/qubes/tests/vm/qubesvm.py", line 3121, in test_811_default_bootmode
    vm.features["boot-mode.active"] = "testmode1"
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
  File "/home/user/qubes-core-admin/qubes/features.py", line 93, in __setitem__
    self.subject.fire_event(
    ~~~~~~~~~~~~~~~~~~~~~~~^
        "domain-feature-set:" + key, feature=key, value=value
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/home/user/qubes-core-admin/qubes/events.py", line 200, in fire_event
    sync_effects, async_effects = self._fire_event(
                                  ~~~~~~~~~~~~~~~~^
        event, kwargs, pre_event=pre_event
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/home/user/qubes-core-admin/qubes/events.py", line 169, in _fire_event
    effect = func(self, event, **kwargs)
TypeError: QubesVM.on_feature_bootmode_active_set() missing 1 required positional argument: 'event'

I can't figure out why this happens though - qubes/vm/qubesvm.py -> on_feature_bootmode_active_set uses this "signature" (not sure what these are called in Python):

    @qubes.events.handler("domain-feature-set:boot-mode.active")
    def on_feature_bootmode_active_set(
        self, vm, event, feature, value, oldvalue=None
    ):

This is nearly identical to a signature in qubes/ext/services.py -> on_domain_feature_set:

    @qubes.ext.handler("domain-feature-set:*")
    def on_domain_feature_set(self, vm, event, feature, value, oldvalue=None):

How come the second one works but the first one doesn't? (The first one used to work without problems before adding self as the first argument, as required by pylint.)

@marmarek
Copy link
Member

marmarek commented Mar 5, 2025

self, vm,

self is vm, don't need to repeat it. It's the difference between event handler defined in the VM class itself (@qubes.events.handler) and in an extension (@qubes.ext.handler)

@ArrayBolt3
Copy link
Contributor Author

Oh sheesh. I stared at this code for like fifteen minutes and didn't notice the qubes.ext.handler vs qubes.events.handler bit. Guess that'll teach me to use a visual diff tool rather than comparing side-by-side in Vim 😅

@ArrayBolt3 ArrayBolt3 force-pushed the arraybolt3/boot-modes branch from a6b1df5 to eef6ece Compare March 5, 2025 22:18
@ArrayBolt3
Copy link
Contributor Author

Fixed the issue with the failing regression tests.

@ArrayBolt3 ArrayBolt3 requested a review from marmarek March 5, 2025 22:21
Copy link

codecov bot commented Mar 5, 2025

Codecov Report

Attention: Patch coverage is 99.01961% with 1 line in your changes missing coverage. Please review.

Project coverage is 70.07%. Comparing base (5df3ba5) to head (e9c62be).
Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
qubes/vm/qubesvm.py 97.43% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #653      +/-   ##
==========================================
+ Coverage   69.90%   70.07%   +0.16%     
==========================================
  Files          59       59              
  Lines       12612    12683      +71     
==========================================
+ Hits         8817     8888      +71     
  Misses       3795     3795              
Flag Coverage Δ
unittests 70.07% <99.01%> (+0.16%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ArrayBolt3
Copy link
Contributor Author

@marmarek How would I run the code coverage test locally? It looks like there's some missed stuff I would have liked to have caught on my end earlier. Currently working on resolving that now.

@marmarek
Copy link
Member

marmarek commented Mar 7, 2025

The run-tests scripts does run with code coverage enabled. You can get the report with coverage tool (or python3 -m coverage)

@ArrayBolt3 ArrayBolt3 force-pushed the arraybolt3/boot-modes branch from eef6ece to 1ce1cdb Compare March 7, 2025 20:13
@ArrayBolt3
Copy link
Contributor Author

qubesvm.py line 1010 should be unreachable code, thus why it shows as not covered. (_default_bootmode() shouldn't ever return something that isn't found by self.features.check_with_template(), except of course for the default value.) All the other code coverage issues should now be solved.

@marmarek
Copy link
Member

marmarek commented Mar 7, 2025

Black complains about one tiny thing...

Boot modes provide a way for VMs to advertise that they can have their
behavior changed by booting them with a predefined combination of
additional kernel parameters set. This allows qubes to offer features
like a secure system maintenance mode in a way that works seemlessly
with Qubes OS.

This commit adds boot mode support to qubes-core-admin, providing API
support for boot modes and allowing VMs to be booted with special
kernel parameters specified by boot modes.
@ArrayBolt3 ArrayBolt3 force-pushed the arraybolt3/boot-modes branch from 1ce1cdb to e9c62be Compare March 9, 2025 14:10
@ArrayBolt3
Copy link
Contributor Author

Should be fixed, I'll try to get in the habit of running it before all pushes.

(aside, qubes-manager is NOT formatted by black, and I've caused myself major headaches more than once thinking I'm supposed to reformat it after changing it and then realizing I just changed like 90% of the code in a way that's tricky to revert if you had uncommitted, unstaged changes, or were silly enough to run git add -A after that. Is there a reason it isn't "blackened"?)

@marmarek
Copy link
Member

marmarek commented Mar 9, 2025

Is there a reason it isn't "blackened"

It isn't yet

@marmarek marmarek merged commit 54527f8 into QubesOS:main Mar 9, 2025
4 of 5 checks passed
marmarek added a commit that referenced this pull request Mar 10, 2025
* origin/pr/666:
  Keep AppVM boot modes and template AppVM default boot mode in sync

Pull request description:

Qube Manager was showing the wrong boot mode kernel options for AppVMs if you changed a template's AppVM default boot mode. Issue had a similar root cause to #653 (comment). This PR fixes it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants