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

interfaces: disable udev backend when inside a container #14930

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

zyga
Copy link
Contributor

@zyga zyga commented Jan 15, 2025

Devices are not namespace-aware in Linux, thus udev inside containers does not really do anything sensible and is set to not execute if /sys is not mounted as a writable file system.

This solves the issue where snapd is failing to install snaps in LXD, demanding workarounds like installing the snap twice, hoping that once-generated files are intact and not trigger a udev rule reload.

Fixes: https://bugs.launchpad.net/snapd/+bug/1712808
Fixes: https://bugs.launchpad.net/snapd/+bug/1865503
Jira: https://warthogs.atlassian.net/browse/SNAPDENG-24757

@@ -33,6 +35,14 @@ import (
apparmor_sandbox "github.com/snapcore/snapd/sandbox/apparmor"
)

func isContainer() bool {
cmd := exec.Command("systemd-detect-virt", "--container", "--quiet")
Copy link
Collaborator

Choose a reason for hiding this comment

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

we are doing this from other places, maybe time to have something in osutil?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I saw we check for non-contianer virt as well. I'll have a look at a common helper used in both places.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've added a helper but one remaining call site is hard to adjust (squashfs) as it introduces dependency loops. I think this is fine for now. Without forcing a package split to resolve that.

@ernestl ernestl added this to the 2.68 milestone Jan 15, 2025
@pedronis pedronis requested a review from bboozzoo January 15, 2025 15:30
@pedronis pedronis added the Needs security review Can only be merged once security gave a :+1: label Jan 15, 2025
@zyga
Copy link
Contributor Author

zyga commented Jan 15, 2025

A quick run locally shows only unrelated failures:

2025-01-15 16:40:55 Failed tasks: 1
    - google-nested:ubuntu-24.04-64:tests/main/services-user
2025-01-15 16:40:55 Failed task prepare: 4
    - google-nested-dev:ubuntu-24.04-64:tests/main/interfaces-opengl-nvidia:experimental
    - google-nested-dev:ubuntu-24.04-64:tests/main/interfaces-opengl-nvidia:stable
    - google-nested:ubuntu-24.04-64:tests/main/interfaces-opengl-nvidia:experimental
    - google-nested:ubuntu-24.04-64:tests/main/interfaces-opengl-nvidia:stable
2025-01-15 16:40:55 Failed project prepare: 1
    - google:ubuntu-24.04-64:project

Copy link

github-actions bot commented Jan 15, 2025

Fri Jan 17 17:28:22 UTC 2025
The following results are from: https://github.com/canonical/snapd/actions/runs/12827805274

Failures:

Preparing:

  • openstack:opensuse-15.6-64
  • openstack:opensuse-15.6-64
  • openstack:opensuse-15.6-64
  • openstack:opensuse-15.6-64
  • openstack:opensuse-15.6-64:tests/completion/
  • openstack:opensuse-15.6-64:tests/smoke/
  • openstack:opensuse-15.6-64:tests/main/install-sideload-epochs:reexec0

Executing:

  • openstack:debian-sid-64:tests/main/degraded
  • openstack:debian-12-64:tests/main/mounts-persist-refresh-content-snap
  • openstack:debian-12-64:tests/main/cgroup-devices-v2
  • openstack:fedora-41-64:tests/main/theme-install

Restoring:

  • openstack:opensuse-15.6-64
  • openstack:opensuse-15.6-64
  • openstack:opensuse-15.6-64
  • openstack:opensuse-15.6-64:tests/main/install-sideload:reexec1
  • openstack:opensuse-15.6-64:tests/main/
  • openstack:opensuse-15.6-64
  • openstack:opensuse-15.6-64:tests/main/install-sideload-epochs:reexec0
  • openstack:opensuse-15.6-64:tests/main/
  • openstack:opensuse-15.6-64

@bboozzoo bboozzoo changed the title interfaces: disable udev backend when insider container interfaces: disable udev backend when inside a container Jan 16, 2025
zyga added 2 commits January 16, 2025 15:30
We need know if we are running in a container in quite a few places in
the code. It's time to add a helper and call it instead of doing it by
hand.

Signed-off-by: Zygmunt Krynicki <[email protected]>
@zyga zyga force-pushed the fix/udev-in-containers-SNAPDENG-24757 branch from 6748117 to 3b289f6 Compare January 17, 2025 10:45
@zyga zyga marked this pull request as ready for review January 17, 2025 10:47
Devices are not namespace-aware in Linux, thus udev inside containers
does not really do anything sensible and is set to not execute if /sys
is not mounted as a writable file system.

This solves the issue where snapd is failing to install snaps in LXD,
demanding workarounds like installing the snap twice, hoping that
once-generated files are intact and not trigger a udev rule reload.

Fixes: https://bugs.launchpad.net/snapd/+bug/1712808
Fixes: https://bugs.launchpad.net/snapd/+bug/1865503
Jira: https://warthogs.atlassian.net/browse/SNAPDENG-24757

Signed-off-by: Zygmunt Krynicki <[email protected]>
@zyga zyga force-pushed the fix/udev-in-containers-SNAPDENG-24757 branch from 3b289f6 to 82721e8 Compare January 17, 2025 11:03
Copy link

codecov bot commented Jan 17, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 78.06%. Comparing base (24a0034) to head (82721e8).
Report is 124 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #14930      +/-   ##
==========================================
- Coverage   78.20%   78.06%   -0.15%     
==========================================
  Files        1151     1135      -16     
  Lines      151396   152387     +991     
==========================================
+ Hits       118402   118955     +553     
- Misses      25662    26097     +435     
- Partials     7332     7335       +3     
Flag Coverage Δ
unittests 78.06% <100.00%> (-0.15%) ⬇️

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.

Copy link
Contributor

@bboozzoo bboozzoo left a comment

Choose a reason for hiding this comment

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

there are 2 more

Comment on lines +26 to +35
// IsContainer returns true if the system is running in a container.
//
// The implementation calls: systemd-detect-virt --quiet --container. It can
// be mocked with testutil.MockCommand. The zero exit code indicates that
// system _is_ running a container. Ensuring that --container is passed is
// important.
func IsContainer() bool {
err := exec.Command("systemd-detect-virt", "--quiet", "--container").Run()
return err == nil
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// IsContainer returns true if the system is running in a container.
//
// The implementation calls: systemd-detect-virt --quiet --container. It can
// be mocked with testutil.MockCommand. The zero exit code indicates that
// system _is_ running a container. Ensuring that --container is passed is
// important.
func IsContainer() bool {
err := exec.Command("systemd-detect-virt", "--quiet", "--container").Run()
return err == nil
}
// IsContainer returns true if the system is running in a container as detected
// by systemd helper tool systemd-detect-virt.
func IsContainer() bool {
// it's imperative to pass --container, zero exit code indicates thatsystem _is_
// running a container
err := exec.Command("systemd-detect-virt", "--quiet", "--container").Run()
return err == nil
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I kept the comment on how to mock it in the documentation because that shows up in IDEs.

*
*/

package systemd
Copy link
Contributor

Choose a reason for hiding this comment

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

not entirely convinced this should be in systemd package. What about osutil?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why would it be in osutil? It's literally calling systemd. Osutil is a bag with endless OS code and I'd rather not append to it.

@@ -149,7 +149,7 @@ func loadAppArmorProfiles() error {

func isContainer() bool {
// systemd's implementation may fail on WSL2 with custom kernels
return release.OnWSL || (exec.Command("systemd-detect-virt", "--quiet", "--container").Run() == nil)
return release.OnWSL || systemd.IsContainer()
Copy link
Contributor

Choose a reason for hiding this comment

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

there are 2 more call locations: osutil/squashfs/fstype.go and daemon/api_general.go.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes I know.

  • squashfs cannot import systemd, I've mentioned that in the comment above.
  • daemon doesn't check for containers so I left it out, the signature would be systemd.VirtualizationType but this is orthogonal to this fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs security review Can only be merged once security gave a :+1:
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants