ANDROID: Incremental fs: Add FS_IOC_GETFLAGS

Add FS_IOC_GETFLAGS ioctl to incfs. Currently this will only get the
S_VERITY flag.

Bug: 160634504
Test: incfs_test passes
Signed-off-by: Paul Lawrence <paullawrence@google.com>
Change-Id: Id79add0db0d66f604ca0f222fe5faec91450ade5
This commit is contained in:
Paul Lawrence
2020-10-06 14:36:01 -07:00
parent ca9597811d
commit ab19218f50
2 changed files with 99 additions and 6 deletions

View File

@@ -4,6 +4,7 @@
*/
#include <linux/blkdev.h>
#include <linux/compat.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/fs_stack.h>
@@ -44,6 +45,11 @@ static int file_release(struct inode *inode, struct file *file);
static int read_single_page(struct file *f, struct page *page);
static long dispatch_ioctl(struct file *f, unsigned int req, unsigned long arg);
#ifdef CONFIG_COMPAT
static long incfs_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg);
#endif
static struct inode *alloc_inode(struct super_block *sb);
static void free_inode(struct inode *inode);
static void evict_inode(struct inode *inode);
@@ -109,7 +115,9 @@ const struct file_operations incfs_file_ops = {
.splice_read = generic_file_splice_read,
.llseek = generic_file_llseek,
.unlocked_ioctl = dispatch_ioctl,
.compat_ioctl = dispatch_ioctl
#ifdef CONFIG_COMPAT
.compat_ioctl = incfs_compat_ioctl,
#endif
};
const struct inode_operations incfs_file_inode_ops = {
@@ -806,6 +814,13 @@ static long ioctl_get_block_count(struct file *f, void __user *arg)
return 0;
}
static int incfs_ioctl_get_flags(struct file *f, void __user *arg)
{
u32 flags = IS_VERITY(file_inode(f)) ? FS_VERITY_FL : 0;
return put_user(flags, (int __user *) arg);
}
static long dispatch_ioctl(struct file *f, unsigned int req, unsigned long arg)
{
switch (req) {
@@ -819,11 +834,34 @@ static long dispatch_ioctl(struct file *f, unsigned int req, unsigned long arg)
return ioctl_get_block_count(f, (void __user *)arg);
case FS_IOC_ENABLE_VERITY:
return incfs_ioctl_enable_verity(f, (const void __user *)arg);
case FS_IOC_GETFLAGS:
return incfs_ioctl_get_flags(f, (void __user *) arg);
default:
return -EINVAL;
}
}
#ifdef CONFIG_COMPAT
static long incfs_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
switch (cmd) {
case FS_IOC32_GETFLAGS:
cmd = FS_IOC_GETFLAGS;
break;
case INCFS_IOC_FILL_BLOCKS:
case INCFS_IOC_READ_FILE_SIGNATURE:
case INCFS_IOC_GET_FILLED_BLOCKS:
case INCFS_IOC_GET_BLOCK_COUNT:
case FS_IOC_ENABLE_VERITY:
break;
default:
return -ENOIOCTLCMD;
}
return dispatch_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
}
#endif
static struct dentry *dir_lookup(struct inode *dir_inode, struct dentry *dentry,
unsigned int flags)
{

View File

@@ -35,6 +35,10 @@
#include "utils.h"
/* Can't include uapi/linux/fs.h because it clashes with mount.h */
#define FS_IOC_GETFLAGS _IOR('f', 1, long)
#define FS_VERITY_FL 0x00100000 /* Verity protected inode */
#define TEST_FAILURE 1
#define TEST_SUCCESS 0
@@ -3736,7 +3740,30 @@ out:
return result;
}
static int validate_verity(const char *mount_dir, struct test_file *file,
static int verity_installed(const char *mount_dir, int cmd_fd, bool *installed)
{
int result = TEST_FAILURE;
char *filename = NULL;
int fd = -1;
struct test_file *file = &get_test_files_set().files[0];
TESTEQUAL(emit_file(cmd_fd, NULL, file->name, &file->id, file->size,
NULL), 0);
TEST(filename = concat_file_name(mount_dir, file->name), filename);
TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
TESTEQUAL(ioctl(fd, FS_IOC_ENABLE_VERITY, NULL), -1);
*installed = errno != EOPNOTSUPP;
result = TEST_SUCCESS;
out:
close(fd);
if (filename)
remove(filename);
free(filename);
return result;
}
static int enable_verity(const char *mount_dir, struct test_file *file,
EVP_PKEY *key, X509 *cert, bool use_signatures)
{
int result = TEST_FAILURE;
@@ -3776,11 +3803,14 @@ static int validate_verity(const char *mount_dir, struct test_file *file,
.digest_algorithm = 1,
.digest_size = 32
};
uint64_t flags;
memcpy(fsverity_signed_digest.magic, "FSVerity", 8);
TEST(filename = concat_file_name(mount_dir, file->name), filename);
TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
TESTEQUAL(ioctl(fd, FS_IOC_GETFLAGS, &flags), 0);
TESTEQUAL(flags & FS_VERITY_FL, 0);
/* First try to enable verity with random digest */
TESTEQUAL(sign(key, cert, (void *)&fsverity_signed_digest,
@@ -3823,10 +3853,30 @@ out:
return result;
}
static int validate_verity(const char *mount_dir, struct test_file *file)
{
int result = TEST_FAILURE;
char *filename = concat_file_name(mount_dir, file->name);
int fd = -1;
uint64_t flags;
TEST(filename = concat_file_name(mount_dir, file->name), filename);
TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
TESTEQUAL(ioctl(fd, FS_IOC_GETFLAGS, &flags), 0);
TESTEQUAL(flags & FS_VERITY_FL, FS_VERITY_FL);
result = TEST_SUCCESS;
out:
close(fd);
free(filename);
return result;
}
static int verity_test_optional_sigs(const char *mount_dir, bool use_signatures)
{
int result = TEST_FAILURE;
char *backing_dir = NULL;
bool installed;
int cmd_fd = -1;
int i;
struct test_files_set test = get_test_files_set();
@@ -3845,6 +3895,11 @@ static int verity_test_optional_sigs(const char *mount_dir, bool use_signatures)
TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "readahead=0", false),
0);
TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
TESTEQUAL(verity_installed(mount_dir, cmd_fd, &installed), 0);
if (!installed) {
result = TEST_SUCCESS;
goto out;
}
TEST(key = create_key(), key);
TEST(cert = get_cert(key), cert);
@@ -3869,15 +3924,15 @@ static int verity_test_optional_sigs(const char *mount_dir, bool use_signatures)
file->sig.add_data), 0);
TESTEQUAL(emit_partial_test_file_hash(mount_dir, file), 0);
TESTEQUAL(enable_verity(mount_dir, file, key, cert,
use_signatures),
0);
}
for (i = 0; i < file_num; i++)
TESTEQUAL(validate_verity(mount_dir, &test.files[i], key, cert,
use_signatures),
0);
TESTEQUAL(validate_verity(mount_dir, &test.files[i]), 0);
result = TEST_SUCCESS;
out:
free(line);
BIO_free(mem);