Skip to content

Commit

Permalink
feat: warn/confirm with user if enabling fips downgrades the kernel
Browse files Browse the repository at this point in the history
This change adds a new message prompting the user to confirm if enabling
fips downgrades the kernel.
  • Loading branch information
catmsred committed Jan 31, 2024
1 parent 9c738af commit 46ec689
Show file tree
Hide file tree
Showing 8 changed files with 575 additions and 393 deletions.
393 changes: 202 additions & 191 deletions debian/po/pt_BR.po

Large diffs are not rendered by default.

390 changes: 200 additions & 190 deletions debian/po/ubuntu-pro.pot

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion features/attached_commands.feature
Original file line number Diff line number Diff line change
Expand Up @@ -824,7 +824,7 @@ Feature: Command behaviour when attached to an Ubuntu Pro subscription
And I apt update
And I run `pro enable <fips-service> --assume-yes` with sudo
And I reboot the machine
Then I verify that `<fips-service>` is eanbled
Then I verify that `<fips-service>` is enabled
When I run `uname -r` as non-root
Then stdout matches regexp:
"""
Expand Down
4 changes: 1 addition & 3 deletions features/enable_fips_container.feature
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Feature: FIPS enablement in lxd containers
Given a `<release>` `<machine_type>` machine with ubuntu-advantage-tools installed
When I attach `contract_token` with sudo
And I apt install `openssh-client openssh-server strongswan openssl <libssl> libgcrypt20`
And I run `pro enable fips<updates>` `with sudo` and stdin `y`
And I run `pro enable fips<updates>` `with sudo` and stdin `y\ny`
Then stdout matches regexp:
"""
Warning: Enabling <fips-name> in a container.
Expand All @@ -16,9 +16,7 @@ Feature: FIPS enablement in lxd containers
"""
And stdout contains substring:
"""
Updating <fips-name> package lists
Installing <fips-name> packages
Updating standard Ubuntu package lists
<fips-name> enabled
A reboot is required to complete install.
Please run `apt upgrade` to ensure all FIPS packages are updated to the correct
Expand Down
8 changes: 6 additions & 2 deletions features/enable_fips_pro.feature
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@ Feature: FIPS enablement in PRO cloud based machines
Then I verify that `fips` is disabled
And I verify that `fips-updates` is disabled
When I run `pro enable <fips-service> --assume-yes` with sudo
Then stdout contains substring:
Then stdout matches regexp:
"""
Updating <fips-name> package lists
Installing <fips-name> packages
Updating standard Ubuntu package lists
This will downgrade the kernel from .+ to .+\.
Warning: Downgrading the kernel may cause hardware failures. Please ensure the
hardware is compatible with the new kernel version before proceeding.
Updating standard Ubuntu package lists(\n.*)?
<fips-name> enabled
A reboot is required to complete install
"""
Expand Down
80 changes: 77 additions & 3 deletions uaclient/entitlements/fips.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import logging
import os
import re
from itertools import groupby
from typing import List, Optional, Tuple # noqa: F401
from typing import Callable, List, Optional, Tuple, Union # noqa: F401

from uaclient import apt, event_logger, exceptions, messages, system, util
from uaclient.clouds.identity import NoCloudTypeReason, get_cloud_type
Expand Down Expand Up @@ -154,6 +155,56 @@ def conditional_packages(self):

return FIPS_CONDITIONAL_PACKAGES.get(series, [])

def prompt_if_kernel_downgrade(
self,
assume_yes: bool = False,
) -> bool:
"""Check if installing a FIPS kernel will downgrade the kernel
and prompt for confirmation if it will.
"""
# Prior to installing packages, check if the kernel is being downgraded
# and if so verify that the user wants to continue
our_full_kernel_str = (
system.get_kernel_info().proc_version_signature_version
)
if our_full_kernel_str is None:
LOG.warning("Cannot gather kernel information")
return False
our_m = re.search(
r"(?P<kernel_version>\d+\.\d+\.\d+)", our_full_kernel_str
)
fips_kernel_version_str = apt.get_pkg_candidate_version("linux-fips")
if our_m is not None and fips_kernel_version_str is not None:
our_kernel_version_str = our_m.group("kernel_version")
LOG.debug(
"Kernel information: cur='%s' and fips='%s'",
our_full_kernel_str,
fips_kernel_version_str,
)
if (
apt.version_compare(
fips_kernel_version_str, our_kernel_version_str
)
< 0
):
event.info(
messages.KERNEL_DOWNGRADE_WARNING.format(
current_version=our_kernel_version_str,
new_version=fips_kernel_version_str,
)
)
return util.prompt_for_confirmation(
msg=messages.PROMPT_YES_NO,
assume_yes=self.assume_yes,
)
else:
LOG.warning(
"Cannot gather kernel information for '%s' and '%s'",
our_full_kernel_str,
fips_kernel_version_str,
)
return True

def install_packages(
self,
package_list: Optional[List[str]] = None,
Expand All @@ -167,6 +218,7 @@ def install_packages(
:param cleanup_on_failure: Cleanup apt files if apt install fails.
:param verbose: If true, print messages to stdout
"""

if verbose:
event.info(
messages.INSTALLING_SERVICE_PACKAGES.format(title=self.title)
Expand Down Expand Up @@ -195,8 +247,14 @@ def install_packages(

for pkg in desired_packages:
try:
super().install_packages(
package_list=[pkg], cleanup_on_failure=False, verbose=False
apt.run_apt_install_command(
packages=[pkg],
override_env_vars={"DEBIAN_FRONTEND": "noninteractive"},
apt_options=[
"--allow-downgrades",
'-o Dpkg::Options::="--force-confdef"',
'-o Dpkg::Options::="--force-confold"',
],
)
except exceptions.UbuntuProError:
event.info(
Expand Down Expand Up @@ -478,6 +536,14 @@ def messaging(self) -> MessagingOperationsDict:
{"msg": pre_enable_prompt, "assume_yes": self.assume_yes},
)
],
"pre_install": [
(
self.prompt_if_kernel_downgrade,
{
"assume_yes": self.assume_yes,
},
)
],
"post_enable": post_enable,
"pre_disable": pre_disable,
}
Expand Down Expand Up @@ -554,6 +620,14 @@ def messaging(self) -> MessagingOperationsDict:
{"msg": pre_enable_prompt, "assume_yes": self.assume_yes},
)
],
"pre_install": [
(
self.prompt_if_kernel_downgrade,
{
"assume_yes": self.assume_yes,
},
)
],
"post_enable": post_enable,
"pre_disable": pre_disable,
}
Expand Down
84 changes: 81 additions & 3 deletions uaclient/entitlements/tests/test_fips.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,55 @@ def test_conditional_packages(
conditional_packages = entitlement.conditional_packages
assert expected == conditional_packages

@pytest.mark.parametrize(
"fips_version, assume_yes, expected_continue",
(
(
"0",
True,
True,
),
(
"0",
False,
False,
),
(
"999",
True,
True,
),
(
"999",
False,
True,
),
),
)
@mock.patch(M_PATH + "apt.get_pkg_candidate_version")
@mock.patch(M_PATH + "util.prompt_for_confirmation")
def test_kernel_downgrade(
self,
m_prompt_for_confirmation,
m_pkg_candidate_version,
fips_version,
assume_yes,
expected_continue,
entitlement,
):
"""Test kernel downgrades block install if user denies prompt"""
m_prompt_for_confirmation = util.prompt_for_confirmation
# if user is prompted for confirmation assume they say no
if not assume_yes:
m_prompt_for_confirmation.return_value = False
else:
m_prompt_for_confirmation.return_value = True
m_pkg_candidate_version.return_value = fips_version
install_continues = entitlement.prompt_if_kernel_downgrade(
assume_yes=assume_yes
)
assert install_continues == expected_continue

def test_default_repo_key_file(self, entitlement):
"""GPG keyring file is the same for both FIPS and FIPS with Updates"""
assert entitlement.repo_key_file == "ubuntu-pro-fips.gpg"
Expand All @@ -135,6 +184,14 @@ def test_messaging_passes_assume_yes(
},
)
],
"pre_install": [
(
entitlement.prompt_if_kernel_downgrade,
{
"assume_yes": assume_yes,
},
)
],
"post_enable": None,
"pre_disable": [
(
Expand All @@ -158,6 +215,14 @@ def test_messaging_passes_assume_yes(
},
)
],
"pre_install": [
(
entitlement.prompt_if_kernel_downgrade,
{
"assume_yes": assume_yes,
},
)
],
"post_enable": None,
"pre_disable": [
(
Expand Down Expand Up @@ -198,6 +263,14 @@ def test_messaging_on_containers(
},
)
],
"pre_install": [
(
entitlement.prompt_if_kernel_downgrade,
{
"assume_yes": False,
},
)
],
"post_enable": [messages.FIPS_RUN_APT_UPGRADE],
"pre_disable": [
(
Expand All @@ -223,6 +296,14 @@ def test_messaging_on_containers(
},
)
],
"pre_install": [
(
entitlement.prompt_if_kernel_downgrade,
{
"assume_yes": False,
},
)
],
"post_enable": [messages.FIPS_RUN_APT_UPGRADE],
"pre_disable": [
(
Expand Down Expand Up @@ -1104,7 +1185,6 @@ def test_install_packages_dont_fail_if_conditional_pkgs_not_installed(
fips_entitlement_factory,
event,
):

conditional_pkgs = ["b", "c"]
m_installed_pkgs.return_value = conditional_pkgs
packages = ["a"]
Expand Down Expand Up @@ -1142,11 +1222,9 @@ def test_install_packages_dont_fail_if_conditional_pkgs_not_installed(
[
"Installing {} packages".format(entitlement.title),
"Updating standard Ubuntu package lists",
"Could not enable {}.".format(entitlement.title),
messages.FIPS_PACKAGE_NOT_AVAILABLE.format(
service=entitlement.title, pkg="b"
),
"Could not enable {}.".format(entitlement.title),
messages.FIPS_PACKAGE_NOT_AVAILABLE.format(
service=entitlement.title, pkg="c"
),
Expand Down
7 changes: 7 additions & 0 deletions uaclient/messages/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1310,6 +1310,13 @@ class TxtColor:
)
+ PROMPT_YES_NO
)
KERNEL_DOWNGRADE_WARNING = t.gettext(
"""\
This will downgrade the kernel from {current_version} to {new_version}.
Warning: Downgrading the kernel may cause hardware failures. Please ensure the
hardware is compatible with the new kernel version before proceeding.
"""
)
FIPS_SYSTEM_REBOOT_REQUIRED = t.gettext(
"FIPS support requires system reboot to complete configuration."
)
Expand Down

0 comments on commit 46ec689

Please sign in to comment.