Skip to content

fix: restrict EFI partition permissions with fmask/dmask=0077#4506

Open
0xdeadd wants to merge 2 commits into
archlinux:masterfrom
0xdeadd:fix/efi-random-seed-permissions
Open

fix: restrict EFI partition permissions with fmask/dmask=0077#4506
0xdeadd wants to merge 2 commits into
archlinux:masterfrom
0xdeadd:fix/efi-random-seed-permissions

Conversation

@0xdeadd
Copy link
Copy Markdown

@0xdeadd 0xdeadd commented Apr 30, 2026

Summary

  • Mount the ESP with fmask=0077 and dmask=0077 to prevent world-readable files like /efi/loader/random-seed
  • Options are added at mount time in _mount_partition() and carried into the installed system via genfstab
  • Existing user-specified mount options are preserved; the restrictive masks are only appended if not already present

Closes #4241

Test plan

  • Install with default EFI partition layout, verify /efi/loader/random-seed is not world-readable
  • Verify fstab entry for ESP includes fmask=0077,dmask=0077
  • Install with custom mount options on EFI partition, verify no duplicate fmask/dmask entries

Mount the ESP with fmask=0077 and dmask=0077 to prevent world-readable
files like /efi/loader/random-seed.

Closes archlinux#4241
@0xdeadd 0xdeadd requested a review from Torxed as a code owner April 30, 2026 21:16
@h8d13
Copy link
Copy Markdown
Contributor

h8d13 commented May 12, 2026

Have you tried the patch ? @0xdeadd

Does pacstrap warn on permissions differing during install ?

@0xdeadd
Copy link
Copy Markdown
Author

0xdeadd commented May 12, 2026

Yep, tested it.

Mount mechanics + genfstab (FAT32 loop image in a container, same image mounted both ways):

loader/random-seed perms readable by other?
current archinstall (ESP mounted with no options) -rwxr-xr-x (755) yes, this is #4241
with this PR (-o fmask=0077,dmask=0077) -rwx------ (700) no

genfstab -U /mnt then carries it through to the installed /etc/fstab:

# before: /dev/loopN  /efi  vfat  rw,relatime,fmask=0022,dmask=0022,...  0 2
# after:  /dev/loopN  /efi  vfat  rw,relatime,fmask=0077,dmask=0077,...  0 2

Unit suite passes on the branch (20 passed).

On the pacstrap question: I haven't done a full bare-metal / QEMU install yet, so I can't speak to that first-hand. But pacstrap doesn't inspect the ESP's mount options; the only thing that writes into /efi during a normal install is bootctl install (creates random-seed), and that's fine with fmask=0077. Happy to run a full QEMU install if you want that confirmed too, just say the word.

One thing I noticed while testing: the guard is an exact-string check (if opt not in options), so if someone has already set a different mask on the ESP in their disk config (e.g. fmask=0022), they'd end up with both fmask=0022 and fmask=0077 in the options. vfat takes the last one so the result is still restrictive, but it's a little untidy. Want me to dedupe by option key instead?

@h8d13
Copy link
Copy Markdown
Contributor

h8d13 commented May 12, 2026

Thanks for the details, I already had patched this in my fork and I'm guessing I had made a mistake originally:

pacstrap would warn: warning: directory permissions differ filesystem: 700 package: 755 or something similar but this must have just been my mistake.

About a QEMU/VM test is always worth it just for sanity check and check end result / expected outcome(s) in target.

@0xdeadd
Copy link
Copy Markdown
Author

0xdeadd commented May 13, 2026

QEMU install run complete. UEFI + GPT, ESP at /boot, systemd-boot, archinstall 4.3 with the PR's _mount_partition change applied verbatim. Recording it here for the record:

check result
patched _mount_partition() fires for the ESP /proc/mounts: /dev/vda1 /mnt/boot vfat rw,relatime,fmask=0077,dmask=0077,…
/boot/loader/random-seed perms after bootctl install -rwx------ (0700), not world-readable
/boot and /boot/loader dir perms drwx------ (0700)
install completes end-to-end ✅ pacstrap, bootctl install, minimal profile, users all OK

One thing worth flagging though: your memory of the pacstrap warning was correct, it wasn't a mistake on your side. With the patch applied, pacstrap emits:

( 2/153) installing filesystem  [######################] 100%
warning: directory permissions differ on /mnt/boot/
filesystem: 700  package: 755

The filesystem package ships /boot expecting 0755; with fmask=0077,dmask=0077 the vfat mount reports 0700; pacstrap notices and warns. Purely informational — install proceeds, no errors — but a new warning users will see.

If you want to suppress it that'd be a separate change (and it'd be cosmetic — chmod doesn't stick on vfat anyway, so the warning is honest about a real-but-harmless mismatch). My read is: leave it, the warning is accurate and the security win is worth it.

@Torxed
Copy link
Copy Markdown
Member

Torxed commented May 13, 2026

I know it's a cheap "out" to comment this, but would it be worth additionally to this — supply a patch to filesystem package to improve this? To remove the warning that is.

Comment thread archinstall/lib/installer.py Outdated

if part_mod.is_efi():
for opt in ('fmask=0077', 'dmask=0077'):
if opt not in options:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Coding on my phone here so apologies if syntax is borked.. but could we not do something like:

list(set(part_mod.mount_options + ('fmask=0077', 'dmask=0077')))

To avoid the loop and if checks. If all we want to do is make we don't add duplicate entries?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Pushed 6ed42e3 with this idea. Used dict.fromkeys instead of set so insertion order is preserved (sets have implementation-defined iteration order, which would make the resulting /etc/fstab entry order undefined). Same dedup semantics as the loop for the dup-string case.

if part_mod.is_efi():
    options = list(dict.fromkeys(options + ['fmask=0077', 'dmask=0077']))

Note it still doesn't dedup by key, so a pre-existing fmask=0022 in mount_options would coexist with the appended fmask=0077 (vfat picks the last one, so the result is still restrictive). I think that's fine for this PR but happy to layer on a parse-by-key version if you'd prefer.

Per @Torxed's review feedback. Same semantics as the previous loop
(dedupe by exact-string match) but shorter. dict.fromkeys preserves
insertion order, where set() would not.
@0xdeadd
Copy link
Copy Markdown
Author

0xdeadd commented May 13, 2026

Worth doing, I think. /boot/loader/random-seed being world-readable is the security bug we're fixing here, and the filesystem package's /boot perm being 0755 is exactly what's emitting the cosmetic warning during pacstrap. Bumping that side too is the clean end state.

Happy to open an MR against the filesystem package (gitlab.archlinux.org) once this PR lands. Will reference back here so the link's preserved. Want me to wait until this is merged, or file the filesystem MR now so it can ride alongside?

if part_mod.mountpoint:
target = self.target / part_mod.relative_mountpoint
mount(part_mod.dev_path, target, options=part_mod.mount_options)
options = list(part_mod.mount_options)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

mount_options is already a list?

options = list(part_mod.mount_options)

if part_mod.is_efi():
options = list(dict.fromkeys(options + ['fmask=0077', 'dmask=0077']))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

change to options += ['fmask=0077', 'dmask=0077']

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

/efi/loader/random-seed is world readable

4 participants