diff options
| author | Eric Biggers <ebiggers@google.com> | 2019-10-29 00:04:39 -0700 |
|---|---|---|
| committer | Eric Biggers <ebiggers@google.com> | 2019-10-30 09:11:29 -0700 |
| commit | c7da2443d6ffa51727db09f8ef1df6aea8c7612c (patch) | |
| tree | 0684f76af89150371c7fc69092b978492d89f5e7 | |
| parent | d9d2b32f9fa9e39b154b71b2abc9eda43d5aaa3c (diff) | |
filesystem: get correct device for kernel-mounted rootfs
A root filesystem mounted via the kernel command line always has a
source of "/dev/root", which isn't a real device node. This makes
fscrypt think this filesystem doesn't have a source device, which breaks
creating login passphrase-protected directories on other filesystems:
fscrypt encrypt: filesystem /: no device for mount "/": system error: cannot create filesystem link
This also makes 'fscrypt status' show a blank source device:
MOUNTPOINT DEVICE FILESYSTEM ENCRYPTION FSCRYPT
/ ext4 supported Yes
To fix this case, update loadMountInfo() to map the device number to the
device name via sysfs rather than use the mount source field.
| -rw-r--r-- | filesystem/filesystem.go | 4 | ||||
| -rw-r--r-- | filesystem/mountpoint.go | 26 | ||||
| -rw-r--r-- | filesystem/path.go | 6 |
3 files changed, 23 insertions, 13 deletions
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go index 2b3383c..c37962a 100644 --- a/filesystem/filesystem.go +++ b/filesystem/filesystem.go @@ -67,6 +67,9 @@ var ( // Path - Absolute path where the directory is mounted // FilesystemType - Type of the mounted filesystem, e.g. "ext4" // Device - Device for filesystem (empty string if we cannot find one) +// DeviceNumber - Device number of the filesystem. This is set even if +// Device isn't, since all filesystems have a device +// number assigned by the kernel, even pseudo-filesystems. // // In order to use a Mount to store fscrypt metadata, some directories must be // setup first. Specifically, the directories created look like: @@ -92,6 +95,7 @@ type Mount struct { Path string FilesystemType string Device string + DeviceNumber DeviceNumber } // PathSorter allows mounts to be sorted by Path. diff --git a/filesystem/mountpoint.go b/filesystem/mountpoint.go index 861f5b1..da6a69a 100644 --- a/filesystem/mountpoint.go +++ b/filesystem/mountpoint.go @@ -69,6 +69,18 @@ func unescapeString(str string) string { return sb.String() } +// We get the device name via the device number rather than use the mount source +// field directly. This is necessary to handle a rootfs that was mounted via +// the kernel command line, since mountinfo always shows /dev/root for that. +// This assumes that the device nodes are in the standard location. +func getDeviceName(num DeviceNumber) string { + linkPath := fmt.Sprintf("/sys/dev/block/%v", num) + if target, err := os.Readlink(linkPath); err == nil { + return fmt.Sprintf("/dev/%s", filepath.Base(target)) + } + return "" +} + // Parse one line of /proc/self/mountinfo. // // The line contains the following space-separated fields: @@ -105,9 +117,14 @@ func parseMountInfoLine(line string) *Mount { } var mnt *Mount = &Mount{} + var err error + mnt.DeviceNumber, err = newDeviceNumberFromString(fields[2]) + if err != nil { + return nil + } mnt.Path = unescapeString(fields[4]) mnt.FilesystemType = unescapeString(fields[n+1]) - mnt.Device = unescapeString(fields[n+2]) + mnt.Device = getDeviceName(mnt.DeviceNumber) return mnt } @@ -145,13 +162,8 @@ func loadMountInfo() error { // filesystems are listed in mount order. mountsByPath[mnt.Path] = mnt - var err error - mnt.Device, err = canonicalizePath(mnt.Device) - // Only use real valid devices (unlike cgroups, tmpfs, ...) - if err == nil && isDevice(mnt.Device) { + if mnt.Device != "" { mountsByDevice[mnt.Device] = append(mountsByDevice[mnt.Device], mnt) - } else { - mnt.Device = "" } } mountsInitialized = true diff --git a/filesystem/path.go b/filesystem/path.go index a99b743..e421783 100644 --- a/filesystem/path.go +++ b/filesystem/path.go @@ -73,12 +73,6 @@ func isDir(path string) bool { return err == nil && info.IsDir() } -// isDevice returns true if the path exists and is that of a device. -func isDevice(path string) bool { - info, err := loggedStat(path) - return err == nil && info.Mode()&os.ModeDevice != 0 -} - // isDirCheckPerm returns true if the path exists and is a directory. If the // specified permissions and sticky bit of mode do not match the path, an error // is logged. |