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

c/snap-bootstrap/initramfs_systemd_mount: add support for dm-verity options #14178

Merged
merged 14 commits into from
Nov 20, 2024

Conversation

sespiros
Copy link
Contributor

@sespiros sespiros commented Jul 12, 2024

@zyga
Copy link
Contributor

zyga commented Jul 15, 2024

Hey @sespiros can you please link this to a Jira card if one exists.

@sespiros
Copy link
Contributor Author

Hey @sespiros can you please link this to a Jira card if one exists.

Added the link to the description.

@codecov-commenter
Copy link

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 78.72%. Comparing base (ea13a33) to head (4093b13).
Report is 56 commits behind head on master.

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #14178      +/-   ##
==========================================
- Coverage   78.73%   78.72%   -0.01%     
==========================================
  Files        1055     1061       +6     
  Lines      138275   139831    +1556     
==========================================
+ Hits       108866   110080    +1214     
- Misses      22588    22870     +282     
- Partials     6821     6881      +60     
Flag Coverage Δ
unittests 78.72% <100.00%> (-0.01%) ⬇️

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.

@sespiros sespiros requested review from valentindavid and zyga July 17, 2024 12:34
Copy link
Member

@alfonsosanchezbeato alfonsosanchezbeato left a comment

Choose a reason for hiding this comment

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

Thank you, some minor comments

cmd/snap-bootstrap/initramfs_systemd_mount_test.go Outdated Show resolved Hide resolved
cmd/snap-bootstrap/initramfs_systemd_mount.go Outdated Show resolved Hide resolved
cmd/snap-bootstrap/initramfs_systemd_mount.go Outdated Show resolved Hide resolved
Copy link
Member

@alfonsosanchezbeato alfonsosanchezbeato left a comment

Choose a reason for hiding this comment

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

LGTM, thank you

Copy link
Contributor

@zyga zyga left a comment

Choose a reason for hiding this comment

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

Almost +1 but a question on escaping path device. Please respond and ping me for re-review.

cmd/snap-bootstrap/initramfs_systemd_mount_test.go Outdated Show resolved Hide resolved
}
if opts.VerityHashDevice != "" && opts.VerityRootHash != "" {
options = append(options, fmt.Sprintf("verity.roothash=%s", opts.VerityRootHash))
options = append(options, fmt.Sprintf("verity.hashdevice=%s", opts.VerityHashDevice))
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to possibly escape the hash device path? Is there any convention about this? What if the device has a space or a comma in the name?

Copy link
Contributor Author

@sespiros sespiros Sep 9, 2024

Choose a reason for hiding this comment

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

Thanks for catching this. I had already done escaping for the comma in the overlayfs PR (9850c03) so I added the same here.

I added an extra test case for this but I have it commented out for now as the test code will need to use SplitMountOptions() (introduced in f1171b9 and later moved in 3477400) to properly split the mount options. The code for SplitMountOptions() will be introduced as part of the overlayfs PR, so once that one is merged I will uncomment the test and remove the TODO comment.

Spaces don't seem to need escaping. These are options that get passed to systemd-mount when it's ran using Go's Exec so I think the shell escapes those for us. This is some example code I used to test this:

# First create the necessary folders under tmp
mkdir -p /tmp/overlay/lower\ 
mkdir -p /tmp/overlay/upper
mkdir -p /tmp/overlay/work
func (s *doSystemdMountSuite) TestSpace(c *C) {
	dirWithSpace := "/tmp/overlay/lower "
	args := []string{dirWithSpace, "/tmp/overlay/merged"}
	args = append(args, "--type=overlay")

	var options []string
	lowerdir := dirWithSpace
	upperdir := "/tmp/overlay/upper"
	workdir := "/tmp/overlay/work"
	options = append(options, fmt.Sprintf("lowerdir=%s", strings.ReplaceAll(lowerdir, ",", `\,`)))
	options = append(options, fmt.Sprintf("upperdir=%s", strings.ReplaceAll(upperdir, ",", `\,`)))
	options = append(options, fmt.Sprintf("workdir=%s", strings.ReplaceAll(workdir, ",", `\,`)))

	args = append(args, "--options="+strings.Join(options, ","))
	cmd := exec.Command("systemd-mount", args...)

	// Run the command and capture the output
	output, err := cmd.Output()

	// Check for errors
	if err != nil {
		log.Fatalf("Error running command: %v", err)
	}

	// Print the output
	fmt.Printf("Command output: %s\n", output)
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Spaces do need escaping. Look at the issues with p9 file system. If you don't escape spaces then /proc/self/mountinfo cannot be parsed correctly, as it has optional fields and options (the naming is beyond our control) and both are separated by spaces from each other (any number of optional fields and the singular "options" field).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Interesting! Do we support this in snapd currently? I guess I could perform the same escaping for spaces as well in addition to the commas (and I guess I would also need to do that in the overlay PR). I am not aware of a more exact convention about this.

Copy link
Contributor

Choose a reason for hiding this comment

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

I hope we don't have to use spaces but the point is that the options field is quite fragile so we should employ some escape logic for it. My advice is to look at the source code carefully: https://elixir.bootlin.com/linux/v6.10.9/source/fs/overlayfs/params.c#L189

The unfortunate reality is that it is a mess and literally every routine does something custom. In some places spaces are escaped, in others they are not.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a commit for this to both this and the overlay PR.

@sespiros sespiros requested a review from zyga September 9, 2024 12:14
}
if opts.VerityHashDevice != "" && opts.VerityRootHash != "" {
options = append(options, fmt.Sprintf("verity.roothash=%s", opts.VerityRootHash))
options = append(options, fmt.Sprintf("verity.hashdevice=%s", strings.ReplaceAll(opts.VerityHashDevice, ",", `\,`)))
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it is very important to have a clear picture of who is parsing this and how it is done. I've done by best to figure out how this is used and this is what I think happens:

  • options are given to systemd-mount from systemd
  • then options are given to libmount from util-linux in libmount/src/hook_veritydev.c
  • then some if this uses cryptsetup to setup the device

As far as I can see, there's no escaping anywhere. So after the mount options are parsed by libmount, all paths are verbatim. I'm trying to see if libmount has some escape logic.

@ernestl ernestl self-assigned this Sep 25, 2024
@ernestl ernestl added the Azure CVM/rootfs integrity https://warthogs.atlassian.net/browse/FR-7575 label Sep 25, 2024
@ernestl ernestl removed their assignment Sep 25, 2024
options = append(options, fmt.Sprintf("verity.roothash=%s", opts.VerityRootHash))

escaper := strings.NewReplacer(",", `\,`, " ", `\ `)
options = append(options, fmt.Sprintf("verity.hashdevice=%s", escaper.Replace(opts.VerityHashDevice)))
Copy link
Contributor

Choose a reason for hiding this comment

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

Would that work to use "verity.hashdevice=\"%s\""

Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of escaping.

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 reverted the escaping logic.
  • I escaped the hash device using double quotes.
  • I forbid backslashes, commas, spaces, colons, double quotes and spaces from appearing in paths used for dm-verity hash devices.
  • added a test.

Copy link

codecov bot commented Oct 9, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 79.03%. Comparing base (96ea7b0) to head (afae71d).
Report is 87 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #14178      +/-   ##
==========================================
+ Coverage   78.95%   79.03%   +0.08%     
==========================================
  Files        1084     1087       +3     
  Lines      146638   147700    +1062     
==========================================
+ Hits       115773   116738     +965     
- Misses      23667    23732      +65     
- Partials     7198     7230      +32     
Flag Coverage Δ
unittests 79.03% <100.00%> (+0.08%) ⬆️

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.


🚨 Try these New Features:

double quoting the options to systemd-mount resulted in errors for the
overlayfs case such as:

localhost kernel: overlayfs: failed to resolve '"/run/mnt/foo"': -2

which is possibly due to an older util-linux being used.

In the same spirit, since we now forbid many characters, we can safely
remove the extra double quotes.
@sespiros sespiros requested a review from zyga October 18, 2024 10:27
Copy link
Contributor

@zyga zyga left a comment

Choose a reason for hiding this comment

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

LGTM with one more tweak suggested inline.

}

if strings.ContainsAny(opts.VerityHashDevice, forbiddenChars) {
return fmt.Errorf("cannot mount %q at %q: dm-verity hash device path contains forbidden characters. %q contains one of \"%s\".", what, where, opts.VerityHashDevice, forbiddenChars)
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
return fmt.Errorf("cannot mount %q at %q: dm-verity hash device path contains forbidden characters. %q contains one of \"%s\".", what, where, opts.VerityHashDevice, forbiddenChars)
return fmt.Errorf("cannot mount %q at %q: dm-verity hash device path contains forbidden characters. %q contains one of %q".", what, where, opts.VerityHashDevice, forbiddenChars)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks! Pushed the change.

Copy link

github-actions bot commented Nov 11, 2024

Everyone contributing to this PR have now signed the CLA. Thanks!

* master: (486 commits)
  o/snapstate, daemon: respect lanes that are passed to snapstate.InstallComponents, snapstate.InstallComponentPath (canonical#14695)
  cmd/snap-bootstrap: support for noexec and nodev options in preparation of tightening mount options for ubuntu core partitions
  o/hookstate: allow snapctl model command for kernel snaps
  many: complete various component cross-checks (canonical#14634)
  github: only check formatting when using latest/stable Go
  tests/main/auto-refresh-backoff: fix sorting of changes from the state (canonical#14691)
  store: place downloaded file in cache after rebuilding from delta (canonical#14680)
  interfaces/desktop: Improve launch entry and systray integration with session (canonical#14132)
  interfaces: desktop session improvements to shutdown,{system,upower}-observe and desktop  (canonical#13947)
  github: run make distcheck
  packaging: symlink fedora-latest to fedora packaging
  github: run unit tests on fedora:latest
  s/snapenv, snapdtool: fix tests that depend on user's SNAP_REEXEC (canonical#14681)
  store: refactor and improve store cache (canonical#14524)
  many: registry API creates transaction commit change (canonical#14675)
  tests/main/nvidia-files: set ubuntu-20.04-64/550-server to broken packaging in table of expectations (canonical#14679)
  c/snap-mgmt: unmount components before unmounting snaps (canonical#14664)
  .github/workflows/coverity-scan.yaml: add github action for Coverity (canonical#14654)
  data/selinux: remove timedatex (canonical#14670)
  c/snap-bootstrap: import users from hybrid system into recovery system (canonical#14521)
  ...
* master: (44 commits)
  wrappers: do not reload activation units (canonical#14724)
  gadget/install: support for no{exec,dev,suid} mount flags
  interfaces/builtin/mount_control: add support for nfs mounts (canonical#14694)
  tests: use gojq - part 1 (canonical#14686)
  interfaces/desktop-legacy: allow DBus access to com.canonical.dbusmenu
  interfaces/builtin/fwupd.go: allow access to nvmem for thunderbolt plugin
  tests: removing uc16 executions (canonical#14575)
  tests: Added arm github runner to build snapd (canonical#14504)
  tests: no need to run spread when there are not tests matching the filter (canonical#14728)
  tests/lib/tools/store-state: exit on errors, update relevant tests (canonical#14725)
  tests: udpate the github workflow to run tests suggested by spread-filter tool (canonical#14519)
  testtime: add mockable timers for use in tests (canonical#14672)
  interface/screen_inhibit_control: Improve screen inhibit control for use on core (canonical#14134)
  tests: use images with 20G disk in openstack (canonical#14720)
  i/builtin: allow @ in custom-device filepaths (canonical#14651)
  tests: refactor test-snapd-desktop-layout-with-content
  tests: fix broken app definition
  tests: capitalize sentences in comments
  tests: wrap very long shell line
  tests: fix raciness in async startup and sync install
  ...
@alfonsosanchezbeato alfonsosanchezbeato merged commit f3e1721 into canonical:master Nov 20, 2024
52 of 56 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Azure CVM/rootfs integrity https://warthogs.atlassian.net/browse/FR-7575 Run nested The PR also runs tests inluded in nested suite
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants