fs-verity: support reading signature with ioctl
authorEric Biggers <ebiggers@google.com>
Fri, 15 Jan 2021 18:18:19 +0000 (10:18 -0800)
committerEric Biggers <ebiggers@google.com>
Sun, 7 Feb 2021 22:51:19 +0000 (14:51 -0800)
Add support for FS_VERITY_METADATA_TYPE_SIGNATURE to
FS_IOC_READ_VERITY_METADATA.  This allows a userspace server program to
retrieve the built-in signature (if present) of a verity file for
serving to a client which implements fs-verity compatible verification.
See the patch which introduced FS_IOC_READ_VERITY_METADATA for more
details.

The ability for userspace to read the built-in signatures is also useful
because it allows a system that is using the in-kernel signature
verification to migrate to userspace signature verification.

This has been tested using a new xfstest which calls this ioctl via a
new subcommand for the 'fsverity' program from fsverity-utils.

Link: https://lore.kernel.org/r/20210115181819.34732-7-ebiggers@kernel.org
Reviewed-by: Victor Hsieh <victorhsieh@google.com>
Reviewed-by: Jaegeuk Kim <jaegeuk@kernel.org>
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
Documentation/filesystems/fsverity.rst
fs/verity/read_metadata.c
include/uapi/linux/fsverity.h

index 6dc5772037ef940e65cc420bb67eb5379f379bd0..1d831e3cbcb33d0623844d83bddc607501e66c0a 100644 (file)
@@ -236,6 +236,7 @@ This ioctl takes in a pointer to the following structure::
 
    #define FS_VERITY_METADATA_TYPE_MERKLE_TREE     1
    #define FS_VERITY_METADATA_TYPE_DESCRIPTOR      2
+   #define FS_VERITY_METADATA_TYPE_SIGNATURE       3
 
    struct fsverity_read_metadata_arg {
            __u64 metadata_type;
@@ -256,6 +257,10 @@ This ioctl takes in a pointer to the following structure::
 - ``FS_VERITY_METADATA_TYPE_DESCRIPTOR`` reads the fs-verity
   descriptor.  See `fs-verity descriptor`_.
 
+- ``FS_VERITY_METADATA_TYPE_SIGNATURE`` reads the signature which was
+  passed to FS_IOC_ENABLE_VERITY, if any.  See `Built-in signature
+  verification`_.
+
 The semantics are similar to those of ``pread()``.  ``offset``
 specifies the offset in bytes into the metadata item to read from, and
 ``length`` specifies the maximum number of bytes to read from the
@@ -279,7 +284,9 @@ FS_IOC_READ_VERITY_METADATA can fail with the following errors:
 - ``EINTR``: the ioctl was interrupted before any data was read
 - ``EINVAL``: reserved fields were set, or ``offset + length``
   overflowed
-- ``ENODATA``: the file is not a verity file
+- ``ENODATA``: the file is not a verity file, or
+  FS_VERITY_METADATA_TYPE_SIGNATURE was requested but the file doesn't
+  have a built-in signature
 - ``ENOTTY``: this type of filesystem does not implement fs-verity, or
   this ioctl is not yet implemented on it
 - ``EOPNOTSUPP``: the kernel was not configured with fs-verity
index 2dea6dd3bb05a3d0f49cf91f94df08dc6bee843c..7e2d0c7bdf0de36290dd226252e0ad51ba250155 100644 (file)
@@ -114,6 +114,34 @@ static int fsverity_read_descriptor(struct inode *inode,
        kfree(desc);
        return res;
 }
+
+static int fsverity_read_signature(struct inode *inode,
+                                  void __user *buf, u64 offset, int length)
+{
+       struct fsverity_descriptor *desc;
+       size_t desc_size;
+       int res;
+
+       res = fsverity_get_descriptor(inode, &desc, &desc_size);
+       if (res)
+               return res;
+
+       if (desc->sig_size == 0) {
+               res = -ENODATA;
+               goto out;
+       }
+
+       /*
+        * Include only the signature.  Note that fsverity_get_descriptor()
+        * already verified that sig_size is in-bounds.
+        */
+       res = fsverity_read_buffer(buf, offset, length, desc->signature,
+                                  le32_to_cpu(desc->sig_size));
+out:
+       kfree(desc);
+       return res;
+}
+
 /**
  * fsverity_ioctl_read_metadata() - read verity metadata from a file
  * @filp: file to read the metadata from
@@ -158,6 +186,8 @@ int fsverity_ioctl_read_metadata(struct file *filp, const void __user *uarg)
                                                 length);
        case FS_VERITY_METADATA_TYPE_DESCRIPTOR:
                return fsverity_read_descriptor(inode, buf, arg.offset, length);
+       case FS_VERITY_METADATA_TYPE_SIGNATURE:
+               return fsverity_read_signature(inode, buf, arg.offset, length);
        default:
                return -EINVAL;
        }
index 41abc283dbccb7456f0cf928412e18c8fe149564..15384e22e331e8738cf05c971f00b3fe6fdfcbb6 100644 (file)
@@ -85,6 +85,7 @@ struct fsverity_formatted_digest {
 
 #define FS_VERITY_METADATA_TYPE_MERKLE_TREE    1
 #define FS_VERITY_METADATA_TYPE_DESCRIPTOR     2
+#define FS_VERITY_METADATA_TYPE_SIGNATURE      3
 
 struct fsverity_read_metadata_arg {
        __u64 metadata_type;