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

storage: Confirmation before erasing non-empty filesystems #20272

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

mvollmer
Copy link
Member

@mvollmer mvollmer commented Apr 8, 2024

But only in Anaconda mode.

Demo: https://youtu.be/EYU2jzDI0gk


Storage: Cockpit asks for extra confirmation before deleting files in Anaconda mode

When using Cockpit to configure storage manually during installation with Anaconda, one normally only operates on empty filesystems. You might create a couple of partitions with filesystems and then change your mind and delete those partitions again, maybe to create them in a slightly different way. These are all pretty harmless operations since no actual data gets deleted.

However, there might also be filesystems present that have not been created during installation. They might contain other operating systems and old, valueable files. In order to protect against deleting these by accident, Cockpit now checks whether a filesystem contains actual files before deleting it, and asks for extra confirmation if it does.

image

@mvollmer mvollmer force-pushed the storage-extra-warning-for-non-empty-filesystems branch 7 times, most recently from 5803fbe to 1acb017 Compare April 10, 2024 12:13
@garrett
Copy link
Member

garrett commented Apr 10, 2024

Here's some revised mockups that streamline things:

Initilize disk

  1. Don't show two or three options in a dropdown (that should really be for 5 or more items only, or a dynamic amount that can be 5 or more); I changed it to radios instead
  2. I renamed it to "modern" and "legacy" with GPT and MBR specified in parenthesis
  3. The 2 TB limit is specified on the legacy MBR option, as it's a limitation of the old method, not a feature of the new
  4. The warning is not a warning (as it is not the result of an action), but a helper text
  5. The table is without much else, so it's just the possibly affected partitions with data
  6. The table contains the filesystem label as well as the size (used & total)
  7. I dropped the /dev/ to be more consistent with the rest of Cockpit and Anaconda (as /dev/ is redundant for devices, as every device is in /dev/)
  8. Use PatternFly suggestions (for the heading, for example)
  9. Remove overwrite with zeros option, as per our few discussions about it, as it's problematic for all kinds of reasons (false sense of security, isn't consistently supported, physically damages drives, can destroy drives in some cases, and the actual solution for ensuring sensitive data is not on the drive is to have it encrypted from the start).

This is all assuming we detect data like we talked about yesterday. That is, show the warning only if:

  1. It's not a partition created in this Anaconda and/or Cockpit session
  2. It has data
    • Ideally without mounting the partition
    • We could check the used size; if it's over a certain small threshold, we know there are files
    • If it's encrypted

Examples:

  • If someone created an encrypted partition within the session, it wouldn't get flagged as containing data, as it was created in the session.
  • If someone created a partition with another tool ahead of time, but it does not contain data (as in, the used size is barely anything), then it wouldn't be flagged as having data.

This would let Cockpit not get in the way when someone is adding and removing partitions, but it also would protect someone from accidentally losing data.

We should use this general pattern for initializing the disk, formatting a partition, and anything else that would probably cause someone to lose data on a partition like this. Although we should rework the warning area a little with regard to the text (and probably table too).

Open questions:

  • Should we not even include an option of GPT vs. MBR for disks that are 2TB or more?
  • Should we really include options for GPT vs. MBR at all? (Is it actually important in 2024?)

@mvollmer
Copy link
Member Author

Here's some revised mockups that streamline things:

Thanks!

I think we should split the parts out that are general improvements to the "Initialize disk" dialog. They might even happen as part of #19882.

@mvollmer
Copy link
Member Author

I think "a partition on this disk" is too specific, there are other cases like LVM2 logical volumes. What about "Important data might be deleted" as the header?

@mvollmer mvollmer force-pushed the storage-extra-warning-for-non-empty-filesystems branch from 1acb017 to e75d76d Compare April 11, 2024 11:39
@mvollmer
Copy link
Member Author

mvollmer commented Apr 11, 2024

@garrett, looks like this now:

image

The text of the "important data" section pretty small. This is the result of using HelperText and a compact Table...

The gap between the table and the checkbox line is because the table is in the dialog body, while the checkbox line is in the footer.

@mvollmer mvollmer force-pushed the storage-extra-warning-for-non-empty-filesystems branch 2 times, most recently from 61d25c4 to 6aa6559 Compare April 12, 2024 09:10
@mvollmer
Copy link
Member Author

mvollmer commented Apr 12, 2024

  1. Don't show two or three options in a dropdown (that should really be for 5 or more items only, or a dynamic amount that can be 5 or more); I changed it to radios instead

  2. I renamed it to "modern" and "legacy" with GPT and MBR specified in parenthesis

  3. The 2 TB limit is specified on the legacy MBR option, as it's a limitation of the old method, not a feature of the new

  4. Remove overwrite with zeros option, as per our few discussions about it, as it's problematic for all kinds of reasons (false sense of security, isn't consistently supported, physically damages drives, can destroy drives in some cases, and the actual solution for ensuring sensitive data is not on the drive is to have it encrypted from the start).

This has been implemented in #19882.

  1. The warning is not a warning (as it is not the result of an action), but a helper text

  2. The table is without much else, so it's just the possibly affected partitions with data

  3. The table contains the filesystem label as well as the size (used & total)

This has been implemented here.

  1. I dropped the /dev/ to be more consistent with the rest of Cockpit and Anaconda (as /dev/ is redundant for devices, as every device is in /dev/)

This has been partly implemented here (for the "important data" table), and will be completed in #19882.

  1. Use PatternFly suggestions (for the heading, for example)

@garrett, I don't understand this, can you elaborate?

@mvollmer
Copy link
Member Author

mvollmer commented Apr 16, 2024

  • Should we not even include an option of GPT vs. MBR for disks that are 2TB or more?

I did this in #19882.

@mvollmer
Copy link
Member Author

mvollmer commented Apr 16, 2024

This is all assuming we detect data like we talked about yesterday. That is, show the warning only if:

  1. It's not a partition created in this Anaconda and/or Cockpit session

I am reluctant to implement this. We would have to identify all places in Cockpit where things get created. That's of course possible, but I hope we can find a more straighforward rule to determine whether to show the warning or not, a rule that doesn't require us to gather information as the user is using Cockpit. That would be more robust.

Right now the rule is:

  • If it is a filesystem of a recognized type (xfs, ext2, ext3, ext4, btrfs, vfat, or ntfs), we check whether it has anything in it that is not a directory. This might mount the filesystem temporarily. We say "N used, M total".
  • If it is a encrypted device that is locked, we say "Locked encrypted device might contain data" and warn about it regardless of what is in it.
  • If it is something not recognized by Cockpit in general or a filesystem not in the list above, we say "Device contains unrecognized data"

My hope is that encrypted devices that are created by Cockpit will remain open during the installation process.

The idea behind the list of recognized filesystem types is to avoid trying to mount unusual filesystems that might be supported by the kernel, but are maybe buggy.

@mvollmer mvollmer force-pushed the storage-extra-warning-for-non-empty-filesystems branch from 6aa6559 to bcecc43 Compare April 16, 2024 07:45
@mvollmer mvollmer force-pushed the storage-extra-warning-for-non-empty-filesystems branch 2 times, most recently from dd4eff0 to 219c595 Compare May 13, 2024 11:06
@mvollmer mvollmer marked this pull request as ready for review May 13, 2024 11:10
@mvollmer mvollmer requested review from garrett and jelly May 13, 2024 11:10
[decode_filename(u.block.PreferredDevice)],
{ superuser: true, err: "message" });
if (empty.trim() != "yes") {
console.log("INFO", empty);
Copy link
Member

Choose a reason for hiding this comment

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

Should this be a debug message?

Copy link
Member Author

Choose a reason for hiding this comment

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

Let's just remove this!

}
if (client.in_anaconda_mode() && !expect_single_unmount && u.block) {
if (u.block.IdUsage == "filesystem" &&
["xfs", "ext2", "ext3", "ext4", "btrfs", "vfat", "ntfs"].indexOf(u.block.IdType) >= 0) {
Copy link
Member

Choose a reason for hiding this comment

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

Are these all the filesystems udisks supports? If so Cockpit should already have a list of them somewhere right? Or can't we get this from udisks? Like http://storaged.org/doc/udisks2-api/latest/gdbus-org.freedesktop.UDisks2.Manager.html#gdbus-property-org-freedesktop-UDisks2-Manager.SupportedFilesystems

Copy link
Member Author

Choose a reason for hiding this comment

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

Are these all the filesystems udisks supports?

No, the idea is to only mount a small number of well-known filesystems, instead of just throwing everything that we find at the kernel.


if (have_data) {
usage.Teardown = true;
dlg.need_confirmation(_("I confirm I want to lose this data forever"));
Copy link
Member

Choose a reason for hiding this comment

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

Sounds a bit dramatic 😆

Copy link
Member Author

Choose a reason for hiding this comment

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

It's a dramatic situation! :-)

dev=$1

need_unmount=""
mp=$(findmnt -no TARGET "$dev" | cat)
Copy link
Member

Choose a reason for hiding this comment

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

That cat seems unnecessary:

[jelle@t14s][~/projects/cockpit/main]%x=$(findmnt -no TARGET /dev/nvme0n1p1)
[jelle@t14s][~/projects/cockpit/main]%echo $x
/boot

Copy link
Member Author

Choose a reason for hiding this comment

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

It protects against the exit code of findmnt. When $dev is not mounted, findmnt exits with code 1, which would stop the script because of set -e. In a pipeline, the last sub-command determines the exit code of the while pipeline, and cat always exits with 0.

# A filesystem is empty if it only has directories in it.

first=$(find "$mp" -not -type d | head -1)
info=$(stat -f -c '{ "unit": %S, "free": %f, "total": %b }' "$mp")
Copy link
Member

Choose a reason for hiding this comment

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

Neither of these commands is allowed to fail as then we will exit and never unmount if needed. So maybe we should use a trap for that.

(I can only get find to fail when not running as root for example but maybe it can fail on broken symlinks or pipes as root?)

Copy link
Member Author

Choose a reason for hiding this comment

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

So maybe we should use a trap for that.

Good point!

m.execute(f"echo einszweidrei | cryptsetup luksFormat --pbkdf-memory 32768 {disk}")
m.execute(f"echo einszweidrei | cryptsetup luksOpen {disk} dm-test")
m.execute("mkfs.ext4 /dev/mapper/dm-test; mount /dev/mapper/dm-test /mnt; echo Hi >/mnt/hello; umount /mnt")
m.execute("cryptsetup close dm-test")
Copy link
Member

Choose a reason for hiding this comment

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

A test for a Filesystem with only directories would be nice as well.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, agreed.

@garrett
Copy link
Member

garrett commented May 14, 2024

Are the screenshots up to date? They still vary wildly from the mockups in several ways.

@mvollmer
Copy link
Member Author

Are the screenshots up to date?

Yes.

They still vary wildly from the mockups in several ways.

Many of the changes are in #19882.

I have changed some of your UI text:

I think "a partition on this disk" is too specific, there are other cases like LVM2 logical volumes. What about "Important data might be deleted" as the header?

Also, I left the action out of the confirmation text since the confirmation is used with more than just initializing disks: "I confirm I want to lose this data forever".

@mvollmer mvollmer force-pushed the storage-extra-warning-for-non-empty-filesystems branch from 219c595 to 70f3eb3 Compare May 15, 2024 14:26
Comment on lines +1363 to +1364
} catch {
u.data_warning = _("Device contains unrecognized data");
Copy link
Contributor

Choose a reason for hiding this comment

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

These 2 added lines are not executed by any test.

@@ -68,7 +68,7 @@ export function make_legacy_vdo_page(parent, vdo, backing_block, next_card) {
}
},
Inits: [
init_active_usage_processes(client, usage)
init_teardown_usage(client, usage)
Copy link
Contributor

Choose a reason for hiding this comment

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

This added line is not executed by any test.

@@ -130,7 +130,7 @@
}
},
Inits: [
init_active_usage_processes(client, usage)
init_teardown_usage(client, usage)
Copy link
Contributor

Choose a reason for hiding this comment

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

This added line is not executed by any test.

@mvollmer mvollmer requested a review from jelly May 17, 2024 08:53
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.

None yet

4 participants