aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2019-10-29 00:04:39 -0700
committerEric Biggers <ebiggers@google.com>2019-10-30 09:11:29 -0700
commitc7da2443d6ffa51727db09f8ef1df6aea8c7612c (patch)
tree0684f76af89150371c7fc69092b978492d89f5e7
parentd9d2b32f9fa9e39b154b71b2abc9eda43d5aaa3c (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.go4
-rw-r--r--filesystem/mountpoint.go26
-rw-r--r--filesystem/path.go6
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.