From bd380777d68816b55da85a42d4cdf7fb262b4ba2 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 23 Feb 2022 12:35:04 -0800 Subject: Make the output of 'fscrypt status' unambiguous Following the example of /proc/self/mountinfo, replace the space, newline, tab, and backslash characters with octal escape sequences so that the output can be parsed unambiguously. --- cmd/fscrypt/status.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'cmd/fscrypt/status.go') diff --git a/cmd/fscrypt/status.go b/cmd/fscrypt/status.go index 255bb2b..d10dfd8 100644 --- a/cmd/fscrypt/status.go +++ b/cmd/fscrypt/status.go @@ -114,8 +114,11 @@ func writeGlobalStatus(w io.Writer) error { continue } - fmt.Fprintf(t, "%s\t%s\t%s\t%s\t%s\n", mount.Path, mount.Device, - mount.FilesystemType, supportString, yesNoString(usingFscrypt)) + fmt.Fprintf(t, "%s\t%s\t%s\t%s\t%s\n", + filesystem.EscapeString(mount.Path), + filesystem.EscapeString(mount.Device), + filesystem.EscapeString(mount.FilesystemType), + supportString, yesNoString(usingFscrypt)) if supportErr == nil { supportCount++ -- cgit v1.2.3 From 6e355131670ad014e45f879475ddf800f0080d41 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 23 Feb 2022 12:35:04 -0800 Subject: Make 'fscrypt setup' offer a choice of directory modes World-writable directories are not appropriate for some systems, so offer a choice of single-user-writable and world-writable modes, with single-user-writable being the default. Add a new documentation section to help users decide which one to use. --- cmd/fscrypt/status.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'cmd/fscrypt/status.go') diff --git a/cmd/fscrypt/status.go b/cmd/fscrypt/status.go index d10dfd8..54c6f1f 100644 --- a/cmd/fscrypt/status.go +++ b/cmd/fscrypt/status.go @@ -165,9 +165,18 @@ func writeFilesystemStatus(w io.Writer, ctx *actions.Context) error { return err } - fmt.Fprintf(w, "%s filesystem %q has %s and %s\n\n", ctx.Mount.FilesystemType, + fmt.Fprintf(w, "%s filesystem %q has %s and %s.\n", ctx.Mount.FilesystemType, ctx.Mount.Path, pluralize(len(options), "protector"), pluralize(len(policyDescriptors), "policy")) + if setupMode, user, err := ctx.Mount.GetSetupMode(); err == nil { + switch setupMode { + case filesystem.WorldWritable: + fmt.Fprintf(w, "All users can create fscrypt metadata on this filesystem.\n") + case filesystem.SingleUserWritable: + fmt.Fprintf(w, "Only %s can create fscrypt metadata on this filesystem.\n", user.Username) + } + } + fmt.Fprintf(w, "\n") if len(options) > 0 { writeOptions(w, options) -- cgit v1.2.3 From 74e870b7bd1585b4b509da47e0e75db66336e576 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 23 Feb 2022 12:35:04 -0800 Subject: Strictly validate metadata file ownership by default The metadata validation checks introduced by the previous commits are good, but to reduce the attack surface it would be much better to avoid reading and parsing files owned by other users in the first place. There are some possible use cases for users sharing fscrypt metadata files, but I think that for the vast majority of users it is unneeded and just opens up attack surface. Thus, make fscrypt (and pam_fscrypt) not process policies or protectors owned by other users by default. Specifically, * If fscrypt or pam_fscrypt is running as a non-root user, only policies and protectors owned by the user or by root can be used. * If fscrypt is running as root, any policy or protector can be used. (This is to match user expectations -- starting a sudo session should gain rights, not remove rights.) * If pam_fscrypt is running as root, only policies and protectors owned by root can be used. Note that this only applies when the root user themselves has an fscrypt login protector, which is rare. Add an option 'allow_cross_user_metadata' to /etc/fscrypt.conf which allows restoring the old behavior for anyone who really needs it. --- cmd/fscrypt/status.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'cmd/fscrypt/status.go') diff --git a/cmd/fscrypt/status.go b/cmd/fscrypt/status.go index 54c6f1f..ed5a764 100644 --- a/cmd/fscrypt/status.go +++ b/cmd/fscrypt/status.go @@ -160,14 +160,18 @@ func writeFilesystemStatus(w io.Writer, ctx *actions.Context) error { return err } - policyDescriptors, err := ctx.Mount.ListPolicies() + policyDescriptors, err := ctx.Mount.ListPolicies(ctx.TrustedUser) if err != nil { return err } - fmt.Fprintf(w, "%s filesystem %q has %s and %s.\n", ctx.Mount.FilesystemType, + filterDescription := "" + if ctx.TrustedUser != nil { + filterDescription = fmt.Sprintf(" (only including ones owned by %s or root)", ctx.TrustedUser.Username) + } + fmt.Fprintf(w, "%s filesystem %q has %s and %s%s.\n", ctx.Mount.FilesystemType, ctx.Mount.Path, pluralize(len(options), "protector"), - pluralize(len(policyDescriptors), "policy")) + pluralize(len(policyDescriptors), "policy"), filterDescription) if setupMode, user, err := ctx.Mount.GetSetupMode(); err == nil { switch setupMode { case filesystem.WorldWritable: -- cgit v1.2.3 From 85a747493ff368a72f511619ecd391016ecb933c Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 23 Feb 2022 12:35:04 -0800 Subject: Extend ownership validation to entire directory structure A previous commit extended file ownership validation to policy and protector files (by default -- there's an opt-out in /etc/fscrypt.conf). However, that didn't apply to the parent directories: MOUNTPOINT MOUNTPOINT/.fscrypt MOUNTPOINT/.fscrypt/policies MOUNTPOINT/.fscrypt/protectors The problem is that if the parent directories aren't trusted (owned by another non-root user), then untrusted changes to their contents can be made at any time, including the introduction of symlinks and so on. While it's debatable how much of a problem this really is, given the other validations that are done, it seems to be appropriate to validate the parent directories too. Therefore, this commit applies the same ownership validations to the above four directories as are done on the metadata files themselves. In addition, it is validated that none of these directories are symlinks except for ".fscrypt" where this is explicitly supported. --- cmd/fscrypt/status.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cmd/fscrypt/status.go') diff --git a/cmd/fscrypt/status.go b/cmd/fscrypt/status.go index ed5a764..bc8f1ee 100644 --- a/cmd/fscrypt/status.go +++ b/cmd/fscrypt/status.go @@ -101,7 +101,7 @@ func writeGlobalStatus(w io.Writer) error { t := makeTableWriter(w, "MOUNTPOINT\tDEVICE\tFILESYSTEM\tENCRYPTION\tFSCRYPT") for _, mount := range mounts { // Only print mountpoints backed by devices or using fscrypt. - usingFscrypt := mount.CheckSetup() == nil + usingFscrypt := mount.CheckSetup(nil) == nil if !usingFscrypt && mount.Device == "" { continue } -- cgit v1.2.3