]> git.apps.os.sepia.ceph.com Git - fscrypt.git/commitdiff
filesystem: get correct device for kernel-mounted rootfs
authorEric Biggers <ebiggers@google.com>
Tue, 29 Oct 2019 07:04:39 +0000 (00:04 -0700)
committerEric Biggers <ebiggers@google.com>
Wed, 30 Oct 2019 16:11:29 +0000 (09:11 -0700)
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.

filesystem/filesystem.go
filesystem/mountpoint.go
filesystem/path.go

index 2b3383c006c1b12e53535a845a918849fcee2cf6..c37962ae5b952c46556402b1c29ab49892128050 100644 (file)
@@ -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.
index 861f5b1a4b4ac2f8538e4909c4936549c84a9f48..da6a69ab971b4cae2d24179e6c615bfed9d0712d 100644 (file)
@@ -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
index a99b743529521359b516c00dcd1bd6527ef7ef21..e421783f79955a93e8ae5cab4e3f4c6f25147dcb 100644 (file)
@@ -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.