ANDROID: Incremental fs: Store fs-verity state in backing file
Now fsverity state is preserved across inode eviction. Added incfs.verity xattr to track when a file is fs-verity enabled. Bug: 160634504 Test: incfs_test passes Signed-off-by: Paul Lawrence <paullawrence@google.com> Change-Id: I41d90abd55527884d9eff642c9834ad837ff6918
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
#include <linux/crc32.h>
|
#include <linux/crc32.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/file.h>
|
#include <linux/file.h>
|
||||||
|
#include <linux/fsverity.h>
|
||||||
#include <linux/gfp.h>
|
#include <linux/gfp.h>
|
||||||
#include <linux/ktime.h>
|
#include <linux/ktime.h>
|
||||||
#include <linux/lz4.h>
|
#include <linux/lz4.h>
|
||||||
@@ -18,6 +19,7 @@
|
|||||||
#include "data_mgmt.h"
|
#include "data_mgmt.h"
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
#include "integrity.h"
|
#include "integrity.h"
|
||||||
|
#include "verity.h"
|
||||||
|
|
||||||
static int incfs_scan_metadata_chain(struct data_file *df);
|
static int incfs_scan_metadata_chain(struct data_file *df);
|
||||||
|
|
||||||
@@ -332,6 +334,7 @@ void incfs_free_data_file(struct data_file *df)
|
|||||||
incfs_free_bfc(df->df_backing_file_context);
|
incfs_free_bfc(df->df_backing_file_context);
|
||||||
kfree(df->df_signature);
|
kfree(df->df_signature);
|
||||||
kfree(df->df_verity_file_digest.data);
|
kfree(df->df_verity_file_digest.data);
|
||||||
|
kfree(df->df_verity_signature);
|
||||||
mutex_destroy(&df->df_enable_verity);
|
mutex_destroy(&df->df_enable_verity);
|
||||||
kfree(df);
|
kfree(df);
|
||||||
}
|
}
|
||||||
@@ -1471,7 +1474,31 @@ static int process_status_md(struct incfs_status *is,
|
|||||||
df->df_initial_hash_blocks_written);
|
df->df_initial_hash_blocks_written);
|
||||||
|
|
||||||
df->df_status_offset = handler->md_record_offset;
|
df->df_status_offset = handler->md_record_offset;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int process_file_verity_signature_md(
|
||||||
|
struct incfs_file_verity_signature *vs,
|
||||||
|
struct metadata_handler *handler)
|
||||||
|
{
|
||||||
|
struct data_file *df = handler->context;
|
||||||
|
struct incfs_df_verity_signature *verity_signature;
|
||||||
|
|
||||||
|
if (!df)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
verity_signature = kzalloc(sizeof(*verity_signature), GFP_NOFS);
|
||||||
|
if (!verity_signature)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
verity_signature->offset = le64_to_cpu(vs->vs_offset);
|
||||||
|
verity_signature->size = le32_to_cpu(vs->vs_size);
|
||||||
|
if (verity_signature->size > FS_VERITY_MAX_SIGNATURE_SIZE) {
|
||||||
|
kfree(verity_signature);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
df->df_verity_signature = verity_signature;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1497,6 +1524,7 @@ static int incfs_scan_metadata_chain(struct data_file *df)
|
|||||||
handler->handle_blockmap = process_blockmap_md;
|
handler->handle_blockmap = process_blockmap_md;
|
||||||
handler->handle_signature = process_file_signature_md;
|
handler->handle_signature = process_file_signature_md;
|
||||||
handler->handle_status = process_status_md;
|
handler->handle_status = process_status_md;
|
||||||
|
handler->handle_verity_signature = process_file_verity_signature_md;
|
||||||
|
|
||||||
while (handler->md_record_offset > 0) {
|
while (handler->md_record_offset > 0) {
|
||||||
error = incfs_read_next_metadata_record(bfc, handler);
|
error = incfs_read_next_metadata_record(bfc, handler);
|
||||||
|
|||||||
@@ -297,6 +297,8 @@ struct data_file {
|
|||||||
* been opened
|
* been opened
|
||||||
*/
|
*/
|
||||||
struct mem_range df_verity_file_digest;
|
struct mem_range df_verity_file_digest;
|
||||||
|
|
||||||
|
struct incfs_df_verity_signature *df_verity_signature;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dir_file {
|
struct dir_file {
|
||||||
|
|||||||
@@ -324,9 +324,6 @@ static int write_new_status_to_backing_file(struct backing_file_context *bfc,
|
|||||||
.is_hash_blocks_written = cpu_to_le32(hash_blocks_written),
|
.is_hash_blocks_written = cpu_to_le32(hash_blocks_written),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!bfc)
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
LOCK_REQUIRED(bfc->bc_mutex);
|
LOCK_REQUIRED(bfc->bc_mutex);
|
||||||
rollback_pos = incfs_get_end_offset(bfc->bc_file);
|
rollback_pos = incfs_get_end_offset(bfc->bc_file);
|
||||||
result = append_md_to_backing_file(bfc, &is.is_header);
|
result = append_md_to_backing_file(bfc, &is.is_header);
|
||||||
@@ -344,6 +341,9 @@ int incfs_write_status_to_backing_file(struct backing_file_context *bfc,
|
|||||||
struct incfs_status is;
|
struct incfs_status is;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
if (!bfc)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
if (status_offset == 0)
|
if (status_offset == 0)
|
||||||
return write_new_status_to_backing_file(bfc,
|
return write_new_status_to_backing_file(bfc,
|
||||||
data_blocks_written, hash_blocks_written);
|
data_blocks_written, hash_blocks_written);
|
||||||
@@ -361,6 +361,46 @@ int incfs_write_status_to_backing_file(struct backing_file_context *bfc,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int incfs_write_verity_signature_to_backing_file(
|
||||||
|
struct backing_file_context *bfc, struct mem_range signature,
|
||||||
|
loff_t *offset)
|
||||||
|
{
|
||||||
|
struct incfs_file_verity_signature vs = {};
|
||||||
|
int result;
|
||||||
|
loff_t pos;
|
||||||
|
|
||||||
|
/* No verity signature section is equivalent to an empty section */
|
||||||
|
if (signature.data == NULL || signature.len == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
pos = incfs_get_end_offset(bfc->bc_file);
|
||||||
|
|
||||||
|
vs = (struct incfs_file_verity_signature) {
|
||||||
|
.vs_header = (struct incfs_md_header) {
|
||||||
|
.h_md_entry_type = INCFS_MD_VERITY_SIGNATURE,
|
||||||
|
.h_record_size = cpu_to_le16(sizeof(vs)),
|
||||||
|
.h_next_md_offset = cpu_to_le64(0),
|
||||||
|
},
|
||||||
|
.vs_size = cpu_to_le32(signature.len),
|
||||||
|
.vs_offset = cpu_to_le64(pos),
|
||||||
|
};
|
||||||
|
|
||||||
|
result = write_to_bf(bfc, signature.data, signature.len, pos);
|
||||||
|
if (result)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
result = append_md_to_backing_file(bfc, &vs.vs_header);
|
||||||
|
if (result)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
*offset = pos;
|
||||||
|
err:
|
||||||
|
if (result)
|
||||||
|
/* Error, rollback file changes */
|
||||||
|
truncate_backing_file(bfc, pos);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write a backing file header
|
* Write a backing file header
|
||||||
* It should always be called only on empty file.
|
* It should always be called only on empty file.
|
||||||
@@ -660,6 +700,11 @@ int incfs_read_next_metadata_record(struct backing_file_context *bfc,
|
|||||||
res = handler->handle_status(
|
res = handler->handle_status(
|
||||||
&handler->md_buffer.status, handler);
|
&handler->md_buffer.status, handler);
|
||||||
break;
|
break;
|
||||||
|
case INCFS_MD_VERITY_SIGNATURE:
|
||||||
|
if (handler->handle_verity_signature)
|
||||||
|
res = handler->handle_verity_signature(
|
||||||
|
&handler->md_buffer.verity_signature, handler);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
res = -ENOTSUPP;
|
res = -ENOTSUPP;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ enum incfs_metadata_type {
|
|||||||
INCFS_MD_FILE_ATTR = 2,
|
INCFS_MD_FILE_ATTR = 2,
|
||||||
INCFS_MD_SIGNATURE = 3,
|
INCFS_MD_SIGNATURE = 3,
|
||||||
INCFS_MD_STATUS = 4,
|
INCFS_MD_STATUS = 4,
|
||||||
|
INCFS_MD_VERITY_SIGNATURE = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum incfs_file_header_flags {
|
enum incfs_file_header_flags {
|
||||||
@@ -228,7 +229,14 @@ struct incfs_blockmap {
|
|||||||
__le32 m_block_count;
|
__le32 m_block_count;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
/* Metadata record for file signature. Type = INCFS_MD_SIGNATURE */
|
/*
|
||||||
|
* Metadata record for file signature. Type = INCFS_MD_SIGNATURE
|
||||||
|
*
|
||||||
|
* The signature stored here is the APK V4 signature data blob. See the
|
||||||
|
* definition of incfs_new_file_args::signature_info for an explanation of this
|
||||||
|
* blob. Specifically, it contains the root hash, but it does *not* contain
|
||||||
|
* anything that the kernel treats as a signature.
|
||||||
|
*/
|
||||||
struct incfs_file_signature {
|
struct incfs_file_signature {
|
||||||
struct incfs_md_header sg_header;
|
struct incfs_md_header sg_header;
|
||||||
|
|
||||||
@@ -259,6 +267,29 @@ struct incfs_status {
|
|||||||
__le32 is_dummy[6]; /* Spare fields */
|
__le32 is_dummy[6]; /* Spare fields */
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Metadata record for verity signature. Type = INCFS_MD_VERITY_SIGNATURE
|
||||||
|
*
|
||||||
|
* This record will only exist for verity-enabled files with signatures. Verity
|
||||||
|
* enabled files without signatures do not have this record. This signature is
|
||||||
|
* checked by fs-verity identically to any other fs-verity signature.
|
||||||
|
*/
|
||||||
|
struct incfs_file_verity_signature {
|
||||||
|
struct incfs_md_header vs_header;
|
||||||
|
|
||||||
|
/* The size of the signature */
|
||||||
|
__le32 vs_size;
|
||||||
|
|
||||||
|
/* Signature's offset in the backing file */
|
||||||
|
__le64 vs_offset;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
/* In memory version of above */
|
||||||
|
struct incfs_df_verity_signature {
|
||||||
|
u32 size;
|
||||||
|
u64 offset;
|
||||||
|
};
|
||||||
|
|
||||||
/* State of the backing file. */
|
/* State of the backing file. */
|
||||||
struct backing_file_context {
|
struct backing_file_context {
|
||||||
/* Protects writes to bc_file */
|
/* Protects writes to bc_file */
|
||||||
@@ -291,6 +322,7 @@ struct metadata_handler {
|
|||||||
struct incfs_blockmap blockmap;
|
struct incfs_blockmap blockmap;
|
||||||
struct incfs_file_signature signature;
|
struct incfs_file_signature signature;
|
||||||
struct incfs_status status;
|
struct incfs_status status;
|
||||||
|
struct incfs_file_verity_signature verity_signature;
|
||||||
} md_buffer;
|
} md_buffer;
|
||||||
|
|
||||||
int (*handle_blockmap)(struct incfs_blockmap *bm,
|
int (*handle_blockmap)(struct incfs_blockmap *bm,
|
||||||
@@ -299,6 +331,8 @@ struct metadata_handler {
|
|||||||
struct metadata_handler *handler);
|
struct metadata_handler *handler);
|
||||||
int (*handle_status)(struct incfs_status *sig,
|
int (*handle_status)(struct incfs_status *sig,
|
||||||
struct metadata_handler *handler);
|
struct metadata_handler *handler);
|
||||||
|
int (*handle_verity_signature)(struct incfs_file_verity_signature *s,
|
||||||
|
struct metadata_handler *handler);
|
||||||
};
|
};
|
||||||
#define INCFS_MAX_METADATA_RECORD_SIZE \
|
#define INCFS_MAX_METADATA_RECORD_SIZE \
|
||||||
sizeof_field(struct metadata_handler, md_buffer)
|
sizeof_field(struct metadata_handler, md_buffer)
|
||||||
@@ -339,6 +373,9 @@ int incfs_write_status_to_backing_file(struct backing_file_context *bfc,
|
|||||||
loff_t status_offset,
|
loff_t status_offset,
|
||||||
u32 data_blocks_written,
|
u32 data_blocks_written,
|
||||||
u32 hash_blocks_written);
|
u32 hash_blocks_written);
|
||||||
|
int incfs_write_verity_signature_to_backing_file(
|
||||||
|
struct backing_file_context *bfc, struct mem_range signature,
|
||||||
|
loff_t *offset);
|
||||||
|
|
||||||
/* Reading stuff */
|
/* Reading stuff */
|
||||||
int incfs_read_file_header(struct backing_file_context *bfc,
|
int incfs_read_file_header(struct backing_file_context *bfc,
|
||||||
|
|||||||
@@ -49,6 +49,7 @@
|
|||||||
#include "verity.h"
|
#include "verity.h"
|
||||||
|
|
||||||
#include "data_mgmt.h"
|
#include "data_mgmt.h"
|
||||||
|
#include "format.h"
|
||||||
#include "integrity.h"
|
#include "integrity.h"
|
||||||
#include "vfs.h"
|
#include "vfs.h"
|
||||||
|
|
||||||
@@ -67,12 +68,59 @@ static int incfs_get_root_hash(struct file *filp, u8 *root_hash)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int incfs_end_enable_verity(struct file *filp)
|
static int incfs_end_enable_verity(struct file *filp, u8 *sig, size_t sig_size)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(filp);
|
struct inode *inode = file_inode(filp);
|
||||||
|
struct mem_range signature = {
|
||||||
|
.data = sig,
|
||||||
|
.len = sig_size,
|
||||||
|
};
|
||||||
|
struct data_file *df = get_incfs_data_file(filp);
|
||||||
|
struct backing_file_context *bfc;
|
||||||
|
int error;
|
||||||
|
struct incfs_df_verity_signature *vs;
|
||||||
|
loff_t offset;
|
||||||
|
|
||||||
|
if (!df || !df->df_backing_file_context)
|
||||||
|
return -EFSCORRUPTED;
|
||||||
|
|
||||||
|
vs = kzalloc(sizeof(*vs), GFP_NOFS);
|
||||||
|
if (!vs)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
bfc = df->df_backing_file_context;
|
||||||
|
error = mutex_lock_interruptible(&bfc->bc_mutex);
|
||||||
|
if (error)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
error = incfs_write_verity_signature_to_backing_file(bfc, signature,
|
||||||
|
&offset);
|
||||||
|
mutex_unlock(&bfc->bc_mutex);
|
||||||
|
if (error)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set verity xattr so we can set S_VERITY without opening backing file
|
||||||
|
*/
|
||||||
|
error = vfs_setxattr(bfc->bc_file->f_path.dentry,
|
||||||
|
INCFS_XATTR_VERITY_NAME, NULL, 0, XATTR_CREATE);
|
||||||
|
if (error) {
|
||||||
|
pr_warn("incfs: error setting verity xattr: %d\n", error);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
*vs = (struct incfs_df_verity_signature) {
|
||||||
|
.size = signature.len,
|
||||||
|
.offset = offset,
|
||||||
|
};
|
||||||
|
|
||||||
|
df->df_verity_signature = vs;
|
||||||
|
vs = NULL;
|
||||||
inode_set_flags(inode, S_VERITY, S_VERITY);
|
inode_set_flags(inode, S_VERITY, S_VERITY);
|
||||||
return 0;
|
|
||||||
|
out:
|
||||||
|
kfree(vs);
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int incfs_compute_file_digest(struct incfs_hash_alg *alg,
|
static int incfs_compute_file_digest(struct incfs_hash_alg *alg,
|
||||||
@@ -246,6 +294,11 @@ static int incfs_enable_verity(struct file *filp,
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
if (IS_VERITY(inode)) {
|
||||||
|
err = -EEXIST;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the signature if the user provided one */
|
/* Get the signature if the user provided one */
|
||||||
if (arg->sig_size) {
|
if (arg->sig_size) {
|
||||||
signature = memdup_user(u64_to_user_ptr(arg->sig_ptr),
|
signature = memdup_user(u64_to_user_ptr(arg->sig_ptr),
|
||||||
@@ -265,7 +318,7 @@ static int incfs_enable_verity(struct file *filp,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = incfs_end_enable_verity(filp);
|
err = incfs_end_enable_verity(filp, signature, arg->sig_size);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@@ -316,3 +369,94 @@ int incfs_ioctl_enable_verity(struct file *filp, const void __user *uarg)
|
|||||||
|
|
||||||
return incfs_enable_verity(filp, &arg);
|
return incfs_enable_verity(filp, &arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u8 *incfs_get_verity_signature(struct file *filp, size_t *sig_size)
|
||||||
|
{
|
||||||
|
struct data_file *df = get_incfs_data_file(filp);
|
||||||
|
struct incfs_df_verity_signature *vs;
|
||||||
|
u8 *signature;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (!df || !df->df_backing_file_context)
|
||||||
|
return ERR_PTR(-EFSCORRUPTED);
|
||||||
|
|
||||||
|
vs = df->df_verity_signature;
|
||||||
|
if (!vs) {
|
||||||
|
*sig_size = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
signature = kzalloc(vs->size, GFP_KERNEL);
|
||||||
|
if (!signature)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
res = incfs_kread(df->df_backing_file_context,
|
||||||
|
signature, vs->size, vs->offset);
|
||||||
|
|
||||||
|
if (res < 0)
|
||||||
|
goto err_out;
|
||||||
|
|
||||||
|
if (res != vs->size) {
|
||||||
|
res = -EINVAL;
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
*sig_size = vs->size;
|
||||||
|
return signature;
|
||||||
|
|
||||||
|
err_out:
|
||||||
|
kfree(signature);
|
||||||
|
return ERR_PTR(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure data_file->df_verity_file_digest is populated */
|
||||||
|
static int ensure_verity_info(struct inode *inode, struct file *filp)
|
||||||
|
{
|
||||||
|
struct mem_range verity_file_digest;
|
||||||
|
u8 *signature = NULL;
|
||||||
|
size_t sig_size;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
/* See if this file's verity file digest is already cached */
|
||||||
|
verity_file_digest = incfs_get_verity_digest(inode);
|
||||||
|
if (verity_file_digest.data)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
signature = incfs_get_verity_signature(filp, &sig_size);
|
||||||
|
if (IS_ERR(signature))
|
||||||
|
return PTR_ERR(signature);
|
||||||
|
|
||||||
|
verity_file_digest = incfs_calc_verity_digest(inode, filp, signature,
|
||||||
|
sig_size,
|
||||||
|
FS_VERITY_HASH_ALG_SHA256);
|
||||||
|
if (IS_ERR(verity_file_digest.data)) {
|
||||||
|
err = PTR_ERR(verity_file_digest.data);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
incfs_set_verity_digest(inode, verity_file_digest);
|
||||||
|
|
||||||
|
out:
|
||||||
|
kfree(signature);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* incfs_fsverity_file_open() - prepare to open a file that may be
|
||||||
|
* verity-enabled
|
||||||
|
* @inode: the inode being opened
|
||||||
|
* @filp: the struct file being set up
|
||||||
|
*
|
||||||
|
* When opening a verity file, set up data_file->df_verity_file_digest if not
|
||||||
|
* already done. Note that incfs does not allow opening for writing, so there is
|
||||||
|
* no need for that check.
|
||||||
|
*
|
||||||
|
* Return: 0 on success, -errno on failure
|
||||||
|
*/
|
||||||
|
int incfs_fsverity_file_open(struct inode *inode, struct file *filp)
|
||||||
|
{
|
||||||
|
if (IS_VERITY(inode))
|
||||||
|
return ensure_verity_info(inode, filp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,10 +6,15 @@
|
|||||||
#ifndef _INCFS_VERITY_H
|
#ifndef _INCFS_VERITY_H
|
||||||
#define _INCFS_VERITY_H
|
#define _INCFS_VERITY_H
|
||||||
|
|
||||||
|
/* Arbitrary limit to bound the kmalloc() size. Can be changed. */
|
||||||
|
#define FS_VERITY_MAX_SIGNATURE_SIZE 16128
|
||||||
|
|
||||||
#ifdef CONFIG_FS_VERITY
|
#ifdef CONFIG_FS_VERITY
|
||||||
|
|
||||||
int incfs_ioctl_enable_verity(struct file *filp, const void __user *uarg);
|
int incfs_ioctl_enable_verity(struct file *filp, const void __user *uarg);
|
||||||
|
|
||||||
|
int incfs_fsverity_file_open(struct inode *inode, struct file *filp);
|
||||||
|
|
||||||
#else /* !CONFIG_FS_VERITY */
|
#else /* !CONFIG_FS_VERITY */
|
||||||
|
|
||||||
static inline int incfs_ioctl_enable_verity(struct file *filp,
|
static inline int incfs_ioctl_enable_verity(struct file *filp,
|
||||||
@@ -18,6 +23,12 @@ static inline int incfs_ioctl_enable_verity(struct file *filp,
|
|||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int incfs_fsverity_file_open(struct inode *inode,
|
||||||
|
struct file *filp)
|
||||||
|
{
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* !CONFIG_FS_VERITY */
|
#endif /* !CONFIG_FS_VERITY */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -159,6 +159,8 @@ struct inode_search {
|
|||||||
struct dentry *backing_dentry;
|
struct dentry *backing_dentry;
|
||||||
|
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
|
bool verity;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum parse_parameter {
|
enum parse_parameter {
|
||||||
@@ -255,6 +257,13 @@ static u64 read_size_attr(struct dentry *backing_dentry)
|
|||||||
return le64_to_cpu(attr_value);
|
return le64_to_cpu(attr_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read verity flag from the attribute. Quicker than reading the header */
|
||||||
|
static bool read_verity_attr(struct dentry *backing_dentry)
|
||||||
|
{
|
||||||
|
return vfs_getxattr(backing_dentry, INCFS_XATTR_VERITY_NAME, NULL, 0)
|
||||||
|
>= 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int inode_test(struct inode *inode, void *opaque)
|
static int inode_test(struct inode *inode, void *opaque)
|
||||||
{
|
{
|
||||||
struct inode_search *search = opaque;
|
struct inode_search *search = opaque;
|
||||||
@@ -285,6 +294,8 @@ static int inode_set(struct inode *inode, void *opaque)
|
|||||||
inode->i_op = &incfs_file_inode_ops;
|
inode->i_op = &incfs_file_inode_ops;
|
||||||
inode->i_fop = &incfs_file_ops;
|
inode->i_fop = &incfs_file_ops;
|
||||||
inode->i_mode &= ~0222;
|
inode->i_mode &= ~0222;
|
||||||
|
if (search->verity)
|
||||||
|
inode_set_flags(inode, S_VERITY, S_VERITY);
|
||||||
} else if (S_ISDIR(inode->i_mode)) {
|
} else if (S_ISDIR(inode->i_mode)) {
|
||||||
inode->i_size = 0;
|
inode->i_size = 0;
|
||||||
inode->i_blocks = 1;
|
inode->i_blocks = 1;
|
||||||
@@ -319,6 +330,7 @@ static struct inode *fetch_regular_inode(struct super_block *sb,
|
|||||||
.ino = backing_inode->i_ino,
|
.ino = backing_inode->i_ino,
|
||||||
.backing_dentry = backing_dentry,
|
.backing_dentry = backing_dentry,
|
||||||
.size = read_size_attr(backing_dentry),
|
.size = read_size_attr(backing_dentry),
|
||||||
|
.verity = read_verity_attr(backing_dentry),
|
||||||
};
|
};
|
||||||
struct inode *inode = iget5_locked(sb, search.ino, inode_test,
|
struct inode *inode = iget5_locked(sb, search.ino, inode_test,
|
||||||
inode_set, &search);
|
inode_set, &search);
|
||||||
@@ -1370,7 +1382,12 @@ static int file_open(struct inode *inode, struct file *file)
|
|||||||
file->private_data = fd;
|
file->private_data = fd;
|
||||||
|
|
||||||
err = make_inode_ready_for_data_ops(mi, inode, backing_file);
|
err = make_inode_ready_for_data_ops(mi, inode, backing_file);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
err = incfs_fsverity_file_open(inode, file);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
} else if (S_ISDIR(inode->i_mode)) {
|
} else if (S_ISDIR(inode->i_mode)) {
|
||||||
struct dir_file *dir = NULL;
|
struct dir_file *dir = NULL;
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
#define INCFS_XATTR_ID_NAME (XATTR_USER_PREFIX "incfs.id")
|
#define INCFS_XATTR_ID_NAME (XATTR_USER_PREFIX "incfs.id")
|
||||||
#define INCFS_XATTR_SIZE_NAME (XATTR_USER_PREFIX "incfs.size")
|
#define INCFS_XATTR_SIZE_NAME (XATTR_USER_PREFIX "incfs.size")
|
||||||
#define INCFS_XATTR_METADATA_NAME (XATTR_USER_PREFIX "incfs.metadata")
|
#define INCFS_XATTR_METADATA_NAME (XATTR_USER_PREFIX "incfs.metadata")
|
||||||
|
#define INCFS_XATTR_VERITY_NAME (XATTR_USER_PREFIX "incfs.verity")
|
||||||
|
|
||||||
#define INCFS_MAX_SIGNATURE_SIZE 8096
|
#define INCFS_MAX_SIGNATURE_SIZE 8096
|
||||||
#define INCFS_SIGNATURE_VERSION 2
|
#define INCFS_SIGNATURE_VERSION 2
|
||||||
|
|||||||
@@ -3929,6 +3929,15 @@ static int verity_test_optional_sigs(const char *mount_dir, bool use_signatures)
|
|||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < file_num; i++)
|
||||||
|
TESTEQUAL(validate_verity(mount_dir, &test.files[i]), 0);
|
||||||
|
|
||||||
|
close(cmd_fd);
|
||||||
|
cmd_fd = -1;
|
||||||
|
TESTEQUAL(umount(mount_dir), 0);
|
||||||
|
TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "readahead=0", false),
|
||||||
|
0);
|
||||||
|
|
||||||
for (i = 0; i < file_num; i++)
|
for (i = 0; i < file_num; i++)
|
||||||
TESTEQUAL(validate_verity(mount_dir, &test.files[i]), 0);
|
TESTEQUAL(validate_verity(mount_dir, &test.files[i]), 0);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user