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 /filesystem | |
| 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.
Diffstat (limited to 'filesystem')
| -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. |