mirror of
https://github.com/torvalds/linux.git
synced 2026-06-07 05:55:44 +02:00
Merge remote-tracking branch 'aosp/upstream-f2fs-stable-linux-5.10.y' into android12-5.10
* aosp/upstream-f2fs-stable-linux-5.10.y: fs-verity: move structs needed for file signing to UAPI header fs-verity: rename "file measurement" to "file digest" fs-verity: rename fsverity_signed_digest to fsverity_formatted_digest fs-verity: remove filenames from file comments fscrypt: allow deleting files with unsupported encryption policy fscrypt: unexport fscrypt_get_encryption_info() fscrypt: move fscrypt_require_key() to fscrypt_private.h fscrypt: move body of fscrypt_prepare_setattr() out-of-line fscrypt: introduce fscrypt_prepare_readdir() ext4: don't call fscrypt_get_encryption_info() from dx_show_leaf() ubifs: remove ubifs_dir_open() f2fs: remove f2fs_dir_open() ext4: remove ext4_dir_open() fscrypt: simplify master key locking fscrypt: remove unnecessary calls to fscrypt_require_key() ubifs: prevent creating duplicate encrypted filenames f2fs: prevent creating duplicate encrypted filenames ext4: prevent creating duplicate encrypted filenames fscrypt: add fscrypt_is_nokey_name() fscrypt: remove kernel-internal constants from UAPI header Conflicts: fs/crypto/hooks.c Bug: 174873661 Signed-off-by: Jaegeuk Kim <jaegeuk@google.com> Change-Id: Id56d42fc959242524628752223e9d773a2c8681c
This commit is contained in:
commit
51ca215606
|
|
@ -27,9 +27,9 @@ automatically verified against the file's Merkle tree. Reads of any
|
|||
corrupted data, including mmap reads, will fail.
|
||||
|
||||
Userspace can use another ioctl to retrieve the root hash (actually
|
||||
the "file measurement", which is a hash that includes the root hash)
|
||||
that fs-verity is enforcing for the file. This ioctl executes in
|
||||
constant time, regardless of the file size.
|
||||
the "fs-verity file digest", which is a hash that includes the Merkle
|
||||
tree root hash) that fs-verity is enforcing for the file. This ioctl
|
||||
executes in constant time, regardless of the file size.
|
||||
|
||||
fs-verity is essentially a way to hash a file in constant time,
|
||||
subject to the caveat that reads which would violate the hash will
|
||||
|
|
@ -177,9 +177,10 @@ FS_IOC_ENABLE_VERITY can fail with the following errors:
|
|||
FS_IOC_MEASURE_VERITY
|
||||
---------------------
|
||||
|
||||
The FS_IOC_MEASURE_VERITY ioctl retrieves the measurement of a verity
|
||||
file. The file measurement is a digest that cryptographically
|
||||
identifies the file contents that are being enforced on reads.
|
||||
The FS_IOC_MEASURE_VERITY ioctl retrieves the digest of a verity file.
|
||||
The fs-verity file digest is a cryptographic digest that identifies
|
||||
the file contents that are being enforced on reads; it is computed via
|
||||
a Merkle tree and is different from a traditional full-file digest.
|
||||
|
||||
This ioctl takes in a pointer to a variable-length structure::
|
||||
|
||||
|
|
@ -197,7 +198,7 @@ On success, 0 is returned and the kernel fills in the structure as
|
|||
follows:
|
||||
|
||||
- ``digest_algorithm`` will be the hash algorithm used for the file
|
||||
measurement. It will match ``fsverity_enable_arg::hash_algorithm``.
|
||||
digest. It will match ``fsverity_enable_arg::hash_algorithm``.
|
||||
- ``digest_size`` will be the size of the digest in bytes, e.g. 32
|
||||
for SHA-256. (This can be redundant with ``digest_algorithm``.)
|
||||
- ``digest`` will be the actual bytes of the digest.
|
||||
|
|
@ -257,25 +258,24 @@ non-verity one, with the following exceptions:
|
|||
with EIO (for read()) or SIGBUS (for mmap() reads).
|
||||
|
||||
- If the sysctl "fs.verity.require_signatures" is set to 1 and the
|
||||
file's verity measurement is not signed by a key in the fs-verity
|
||||
keyring, then opening the file will fail. See `Built-in signature
|
||||
verification`_.
|
||||
file is not signed by a key in the fs-verity keyring, then opening
|
||||
the file will fail. See `Built-in signature verification`_.
|
||||
|
||||
Direct access to the Merkle tree is not supported. Therefore, if a
|
||||
verity file is copied, or is backed up and restored, then it will lose
|
||||
its "verity"-ness. fs-verity is primarily meant for files like
|
||||
executables that are managed by a package manager.
|
||||
|
||||
File measurement computation
|
||||
============================
|
||||
File digest computation
|
||||
=======================
|
||||
|
||||
This section describes how fs-verity hashes the file contents using a
|
||||
Merkle tree to produce the "file measurement" which cryptographically
|
||||
identifies the file contents. This algorithm is the same for all
|
||||
filesystems that support fs-verity.
|
||||
Merkle tree to produce the digest which cryptographically identifies
|
||||
the file contents. This algorithm is the same for all filesystems
|
||||
that support fs-verity.
|
||||
|
||||
Userspace only needs to be aware of this algorithm if it needs to
|
||||
compute the file measurement itself, e.g. in order to sign the file.
|
||||
compute fs-verity file digests itself, e.g. in order to sign files.
|
||||
|
||||
.. _fsverity_merkle_tree:
|
||||
|
||||
|
|
@ -325,26 +325,22 @@ can't a distinguish a large file from a small second file whose data
|
|||
is exactly the top-level hash block of the first file. Ambiguities
|
||||
also arise from the convention of padding to the next block boundary.
|
||||
|
||||
To solve this problem, the verity file measurement is actually
|
||||
computed as a hash of the following structure, which contains the
|
||||
Merkle tree root hash as well as other fields such as the file size::
|
||||
To solve this problem, the fs-verity file digest is actually computed
|
||||
as a hash of the following structure, which contains the Merkle tree
|
||||
root hash as well as other fields such as the file size::
|
||||
|
||||
struct fsverity_descriptor {
|
||||
__u8 version; /* must be 1 */
|
||||
__u8 hash_algorithm; /* Merkle tree hash algorithm */
|
||||
__u8 log_blocksize; /* log2 of size of data and tree blocks */
|
||||
__u8 salt_size; /* size of salt in bytes; 0 if none */
|
||||
__le32 sig_size; /* must be 0 */
|
||||
__le32 __reserved_0x04; /* must be 0 */
|
||||
__le64 data_size; /* size of file the Merkle tree is built over */
|
||||
__u8 root_hash[64]; /* Merkle tree root hash */
|
||||
__u8 salt[32]; /* salt prepended to each hashed block */
|
||||
__u8 __reserved[144]; /* must be 0's */
|
||||
};
|
||||
|
||||
Note that the ``sig_size`` field must be set to 0 for the purpose of
|
||||
computing the file measurement, even if a signature was provided (or
|
||||
will be provided) to `FS_IOC_ENABLE_VERITY`_.
|
||||
|
||||
Built-in signature verification
|
||||
===============================
|
||||
|
||||
|
|
@ -359,20 +355,20 @@ kernel. Specifically, it adds support for:
|
|||
certificates from being added.
|
||||
|
||||
2. `FS_IOC_ENABLE_VERITY`_ accepts a pointer to a PKCS#7 formatted
|
||||
detached signature in DER format of the file measurement. On
|
||||
success, this signature is persisted alongside the Merkle tree.
|
||||
detached signature in DER format of the file's fs-verity digest.
|
||||
On success, this signature is persisted alongside the Merkle tree.
|
||||
Then, any time the file is opened, the kernel will verify the
|
||||
file's actual measurement against this signature, using the
|
||||
certificates in the ".fs-verity" keyring.
|
||||
file's actual digest against this signature, using the certificates
|
||||
in the ".fs-verity" keyring.
|
||||
|
||||
3. A new sysctl "fs.verity.require_signatures" is made available.
|
||||
When set to 1, the kernel requires that all verity files have a
|
||||
correctly signed file measurement as described in (2).
|
||||
correctly signed digest as described in (2).
|
||||
|
||||
File measurements must be signed in the following format, which is
|
||||
similar to the structure used by `FS_IOC_MEASURE_VERITY`_::
|
||||
fs-verity file digests must be signed in the following format, which
|
||||
is similar to the structure used by `FS_IOC_MEASURE_VERITY`_::
|
||||
|
||||
struct fsverity_signed_digest {
|
||||
struct fsverity_formatted_digest {
|
||||
char magic[8]; /* must be "FSVerity" */
|
||||
__le16 digest_algorithm;
|
||||
__le16 digest_size;
|
||||
|
|
@ -421,8 +417,8 @@ can only be set by `FS_IOC_ENABLE_VERITY`_, and it cannot be cleared.
|
|||
|
||||
ext4 also supports encryption, which can be used simultaneously with
|
||||
fs-verity. In this case, the plaintext data is verified rather than
|
||||
the ciphertext. This is necessary in order to make the file
|
||||
measurement meaningful, since every file is encrypted differently.
|
||||
the ciphertext. This is necessary in order to make the fs-verity file
|
||||
digest meaningful, since every file is encrypted differently.
|
||||
|
||||
ext4 stores the verity metadata (Merkle tree and fsverity_descriptor)
|
||||
past the end of the file, starting at the first 64K boundary beyond
|
||||
|
|
@ -592,8 +588,8 @@ weren't already directly answered in other parts of this document.
|
|||
:Q: Isn't fs-verity useless because the attacker can just modify the
|
||||
hashes in the Merkle tree, which is stored on-disk?
|
||||
:A: To verify the authenticity of an fs-verity file you must verify
|
||||
the authenticity of the "file measurement", which is basically the
|
||||
root hash of the Merkle tree. See `Use cases`_.
|
||||
the authenticity of the "fs-verity file digest", which
|
||||
incorporates the root hash of the Merkle tree. See `Use cases`_.
|
||||
|
||||
:Q: Isn't fs-verity useless because the attacker can just replace a
|
||||
verity file with a non-verity one?
|
||||
|
|
|
|||
|
|
@ -404,7 +404,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
|
|||
fname->disk_name.len = iname->len;
|
||||
return 0;
|
||||
}
|
||||
ret = fscrypt_get_encryption_info(dir);
|
||||
ret = fscrypt_get_encryption_info(dir, lookup);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -560,7 +560,11 @@ int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
|
|||
return -ECHILD;
|
||||
|
||||
dir = dget_parent(dentry);
|
||||
err = fscrypt_get_encryption_info(d_inode(dir));
|
||||
/*
|
||||
* Pass allow_unsupported=true, so that files with an unsupported
|
||||
* encryption policy can be deleted.
|
||||
*/
|
||||
err = fscrypt_get_encryption_info(d_inode(dir), true);
|
||||
valid = !fscrypt_has_encryption_key(d_inode(dir));
|
||||
dput(dir);
|
||||
|
||||
|
|
|
|||
|
|
@ -469,16 +469,9 @@ struct fscrypt_master_key {
|
|||
* FS_IOC_REMOVE_ENCRYPTION_KEY can be retried, or
|
||||
* FS_IOC_ADD_ENCRYPTION_KEY can add the secret again.
|
||||
*
|
||||
* Locking: protected by key->sem (outer) and mk_secret_sem (inner).
|
||||
* The reason for two locks is that key->sem also protects modifying
|
||||
* mk_users, which ranks it above the semaphore for the keyring key
|
||||
* type, which is in turn above page faults (via keyring_read). But
|
||||
* sometimes filesystems call fscrypt_get_encryption_info() from within
|
||||
* a transaction, which ranks it below page faults. So we need a
|
||||
* separate lock which protects mk_secret but not also mk_users.
|
||||
* Locking: protected by this master key's key->sem.
|
||||
*/
|
||||
struct fscrypt_master_key_secret mk_secret;
|
||||
struct rw_semaphore mk_secret_sem;
|
||||
|
||||
/*
|
||||
* For v1 policy keys: an arbitrary key descriptor which was assigned by
|
||||
|
|
@ -497,8 +490,8 @@ struct fscrypt_master_key {
|
|||
*
|
||||
* This is NULL for v1 policy keys; those can only be added by root.
|
||||
*
|
||||
* Locking: in addition to this keyrings own semaphore, this is
|
||||
* protected by the master key's key->sem, so we can do atomic
|
||||
* Locking: in addition to this keyring's own semaphore, this is
|
||||
* protected by this master key's key->sem, so we can do atomic
|
||||
* search+insert. It can also be searched without taking any locks, but
|
||||
* in that case the returned key may have already been removed.
|
||||
*/
|
||||
|
|
@ -540,9 +533,9 @@ is_master_key_secret_present(const struct fscrypt_master_key_secret *secret)
|
|||
/*
|
||||
* The READ_ONCE() is only necessary for fscrypt_drop_inode() and
|
||||
* fscrypt_key_describe(). These run in atomic context, so they can't
|
||||
* take ->mk_secret_sem and thus 'secret' can change concurrently which
|
||||
* would be a data race. But they only need to know whether the secret
|
||||
* *was* present at the time of check, so READ_ONCE() suffices.
|
||||
* take the key semaphore and thus 'secret' can change concurrently
|
||||
* which would be a data race. But they only need to know whether the
|
||||
* secret *was* present at the time of check, so READ_ONCE() suffices.
|
||||
*/
|
||||
return READ_ONCE(secret->size) != 0;
|
||||
}
|
||||
|
|
@ -609,6 +602,34 @@ int fscrypt_derive_dirhash_key(struct fscrypt_info *ci,
|
|||
void fscrypt_hash_inode_number(struct fscrypt_info *ci,
|
||||
const struct fscrypt_master_key *mk);
|
||||
|
||||
int fscrypt_get_encryption_info(struct inode *inode, bool allow_unsupported);
|
||||
|
||||
/**
|
||||
* fscrypt_require_key() - require an inode's encryption key
|
||||
* @inode: the inode we need the key for
|
||||
*
|
||||
* If the inode is encrypted, set up its encryption key if not already done.
|
||||
* Then require that the key be present and return -ENOKEY otherwise.
|
||||
*
|
||||
* No locks are needed, and the key will live as long as the struct inode --- so
|
||||
* it won't go away from under you.
|
||||
*
|
||||
* Return: 0 on success, -ENOKEY if the key is missing, or another -errno code
|
||||
* if a problem occurred while setting up the encryption key.
|
||||
*/
|
||||
static inline int fscrypt_require_key(struct inode *inode)
|
||||
{
|
||||
if (IS_ENCRYPTED(inode)) {
|
||||
int err = fscrypt_get_encryption_info(inode, false);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
if (!fscrypt_has_encryption_key(inode))
|
||||
return -ENOKEY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* keysetup_v1.c */
|
||||
|
||||
void fscrypt_put_direct_key(struct fscrypt_direct_key *dk);
|
||||
|
|
|
|||
|
|
@ -54,15 +54,12 @@ EXPORT_SYMBOL_GPL(fscrypt_file_open);
|
|||
int __fscrypt_prepare_link(struct inode *inode, struct inode *dir,
|
||||
struct dentry *dentry)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = fscrypt_require_key(dir);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* ... in case we looked up no-key name before key was added */
|
||||
if (fscrypt_is_nokey_name(dentry))
|
||||
return -ENOKEY;
|
||||
/*
|
||||
* We don't need to separately check that the directory inode's key is
|
||||
* available, as it's implied by the dentry not being a no-key name.
|
||||
*/
|
||||
|
||||
if (!fscrypt_has_permitted_context(dir, inode))
|
||||
return -EXDEV;
|
||||
|
|
@ -75,20 +72,13 @@ int __fscrypt_prepare_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
unsigned int flags)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = fscrypt_require_key(old_dir);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fscrypt_require_key(new_dir);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* ... in case we looked up no-key name(s) before key was added */
|
||||
if (fscrypt_is_nokey_name(old_dentry) ||
|
||||
fscrypt_is_nokey_name(new_dentry))
|
||||
return -ENOKEY;
|
||||
/*
|
||||
* We don't need to separately check that the directory inodes' keys are
|
||||
* available, as it's implied by the dentries not being no-key names.
|
||||
*/
|
||||
|
||||
if (old_dir != new_dir) {
|
||||
if (IS_ENCRYPTED(new_dir) &&
|
||||
|
|
@ -123,6 +113,20 @@ int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup);
|
||||
|
||||
int __fscrypt_prepare_readdir(struct inode *dir)
|
||||
{
|
||||
return fscrypt_get_encryption_info(dir, true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__fscrypt_prepare_readdir);
|
||||
|
||||
int __fscrypt_prepare_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
{
|
||||
if (attr->ia_valid & ATTR_SIZE)
|
||||
return fscrypt_require_key(d_inode(dentry));
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__fscrypt_prepare_setattr);
|
||||
|
||||
/**
|
||||
* fscrypt_prepare_setflags() - prepare to change flags with FS_IOC_SETFLAGS
|
||||
* @inode: the inode on which flags are being changed
|
||||
|
|
@ -138,6 +142,7 @@ int fscrypt_prepare_setflags(struct inode *inode,
|
|||
unsigned int oldflags, unsigned int flags)
|
||||
{
|
||||
struct fscrypt_info *ci;
|
||||
struct key *key;
|
||||
struct fscrypt_master_key *mk;
|
||||
int err;
|
||||
|
||||
|
|
@ -153,13 +158,14 @@ int fscrypt_prepare_setflags(struct inode *inode,
|
|||
ci = inode->i_crypt_info;
|
||||
if (ci->ci_policy.version != FSCRYPT_POLICY_V2)
|
||||
return -EINVAL;
|
||||
mk = ci->ci_master_key->payload.data[0];
|
||||
down_read(&mk->mk_secret_sem);
|
||||
key = ci->ci_master_key;
|
||||
mk = key->payload.data[0];
|
||||
down_read(&key->sem);
|
||||
if (is_master_key_secret_present(&mk->mk_secret))
|
||||
err = fscrypt_derive_dirhash_key(ci, mk);
|
||||
else
|
||||
err = -ENOKEY;
|
||||
up_read(&mk->mk_secret_sem);
|
||||
up_read(&key->sem);
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -325,7 +331,7 @@ const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
|
|||
* Try to set up the symlink's encryption key, but we can continue
|
||||
* regardless of whether the key is available or not.
|
||||
*/
|
||||
err = fscrypt_get_encryption_info(inode);
|
||||
err = fscrypt_get_encryption_info(inode, false);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
has_key = fscrypt_has_encryption_key(inode);
|
||||
|
|
|
|||
|
|
@ -347,7 +347,6 @@ static int add_new_master_key(struct fscrypt_master_key_secret *secret,
|
|||
mk->mk_spec = *mk_spec;
|
||||
|
||||
move_master_key_secret(&mk->mk_secret, secret);
|
||||
init_rwsem(&mk->mk_secret_sem);
|
||||
|
||||
refcount_set(&mk->mk_refcount, 1); /* secret is present */
|
||||
INIT_LIST_HEAD(&mk->mk_decrypted_inodes);
|
||||
|
|
@ -427,11 +426,8 @@ static int add_existing_master_key(struct fscrypt_master_key *mk,
|
|||
}
|
||||
|
||||
/* Re-add the secret if needed. */
|
||||
if (rekey) {
|
||||
down_write(&mk->mk_secret_sem);
|
||||
if (rekey)
|
||||
move_master_key_secret(&mk->mk_secret, secret);
|
||||
up_write(&mk->mk_secret_sem);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1005,10 +1001,8 @@ static int do_remove_key(struct file *filp, void __user *_uarg, bool all_users)
|
|||
/* No user claims remaining. Go ahead and wipe the secret. */
|
||||
dead = false;
|
||||
if (is_master_key_secret_present(&mk->mk_secret)) {
|
||||
down_write(&mk->mk_secret_sem);
|
||||
wipe_master_key_secret(&mk->mk_secret);
|
||||
dead = refcount_dec_and_test(&mk->mk_refcount);
|
||||
up_write(&mk->mk_secret_sem);
|
||||
}
|
||||
up_write(&key->sem);
|
||||
if (dead) {
|
||||
|
|
|
|||
|
|
@ -376,11 +376,11 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci,
|
|||
* Find the master key, then set up the inode's actual encryption key.
|
||||
*
|
||||
* If the master key is found in the filesystem-level keyring, then the
|
||||
* corresponding 'struct key' is returned in *master_key_ret with
|
||||
* ->mk_secret_sem read-locked. This is needed to ensure that only one task
|
||||
* links the fscrypt_info into ->mk_decrypted_inodes (as multiple tasks may race
|
||||
* to create an fscrypt_info for the same inode), and to synchronize the master
|
||||
* key being removed with a new inode starting to use it.
|
||||
* corresponding 'struct key' is returned in *master_key_ret with its semaphore
|
||||
* read-locked. This is needed to ensure that only one task links the
|
||||
* fscrypt_info into ->mk_decrypted_inodes (as multiple tasks may race to create
|
||||
* an fscrypt_info for the same inode), and to synchronize the master key being
|
||||
* removed with a new inode starting to use it.
|
||||
*/
|
||||
static int setup_file_encryption_key(struct fscrypt_info *ci,
|
||||
bool need_dirhash_key,
|
||||
|
|
@ -429,7 +429,7 @@ static int setup_file_encryption_key(struct fscrypt_info *ci,
|
|||
}
|
||||
|
||||
mk = key->payload.data[0];
|
||||
down_read(&mk->mk_secret_sem);
|
||||
down_read(&key->sem);
|
||||
|
||||
/* Has the secret been removed (via FS_IOC_REMOVE_ENCRYPTION_KEY)? */
|
||||
if (!is_master_key_secret_present(&mk->mk_secret)) {
|
||||
|
|
@ -476,7 +476,7 @@ static int setup_file_encryption_key(struct fscrypt_info *ci,
|
|||
return 0;
|
||||
|
||||
out_release_key:
|
||||
up_read(&mk->mk_secret_sem);
|
||||
up_read(&key->sem);
|
||||
key_put(key);
|
||||
return err;
|
||||
}
|
||||
|
|
@ -579,9 +579,7 @@ fscrypt_setup_encryption_info(struct inode *inode,
|
|||
res = 0;
|
||||
out:
|
||||
if (master_key) {
|
||||
struct fscrypt_master_key *mk = master_key->payload.data[0];
|
||||
|
||||
up_read(&mk->mk_secret_sem);
|
||||
up_read(&master_key->sem);
|
||||
key_put(master_key);
|
||||
}
|
||||
put_crypt_info(crypt_info);
|
||||
|
|
@ -591,6 +589,11 @@ fscrypt_setup_encryption_info(struct inode *inode,
|
|||
/**
|
||||
* fscrypt_get_encryption_info() - set up an inode's encryption key
|
||||
* @inode: the inode to set up the key for. Must be encrypted.
|
||||
* @allow_unsupported: if %true, treat an unsupported encryption policy (or
|
||||
* unrecognized encryption context) the same way as the key
|
||||
* being unavailable, instead of returning an error. Use
|
||||
* %false unless the operation being performed is needed in
|
||||
* order for files (or directories) to be deleted.
|
||||
*
|
||||
* Set up ->i_crypt_info, if it hasn't already been done.
|
||||
*
|
||||
|
|
@ -601,7 +604,7 @@ fscrypt_setup_encryption_info(struct inode *inode,
|
|||
* encryption key is unavailable. (Use fscrypt_has_encryption_key() to
|
||||
* distinguish these cases.) Also can return another -errno code.
|
||||
*/
|
||||
int fscrypt_get_encryption_info(struct inode *inode)
|
||||
int fscrypt_get_encryption_info(struct inode *inode, bool allow_unsupported)
|
||||
{
|
||||
int res;
|
||||
union fscrypt_context ctx;
|
||||
|
|
@ -612,29 +615,38 @@ int fscrypt_get_encryption_info(struct inode *inode)
|
|||
|
||||
res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
|
||||
if (res < 0) {
|
||||
if (res == -ERANGE && allow_unsupported)
|
||||
return 0;
|
||||
fscrypt_warn(inode, "Error %d getting encryption context", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
res = fscrypt_policy_from_context(&policy, &ctx, res);
|
||||
if (res) {
|
||||
if (allow_unsupported)
|
||||
return 0;
|
||||
fscrypt_warn(inode,
|
||||
"Unrecognized or corrupt encryption context");
|
||||
return res;
|
||||
}
|
||||
|
||||
if (!fscrypt_supported_policy(&policy, inode))
|
||||
if (!fscrypt_supported_policy(&policy, inode)) {
|
||||
if (allow_unsupported)
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
res = fscrypt_setup_encryption_info(inode, &policy,
|
||||
fscrypt_context_nonce(&ctx),
|
||||
IS_CASEFOLDED(inode) &&
|
||||
S_ISDIR(inode->i_mode));
|
||||
|
||||
if (res == -ENOPKG && allow_unsupported) /* Algorithm unavailable? */
|
||||
res = 0;
|
||||
if (res == -ENOKEY)
|
||||
res = 0;
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_get_encryption_info);
|
||||
|
||||
/**
|
||||
* fscrypt_prepare_new_inode() - prepare to create a new inode in a directory
|
||||
|
|
@ -755,7 +767,7 @@ int fscrypt_drop_inode(struct inode *inode)
|
|||
return 0;
|
||||
|
||||
/*
|
||||
* Note: since we aren't holding ->mk_secret_sem, the result here can
|
||||
* Note: since we aren't holding the key semaphore, the result here can
|
||||
* immediately become outdated. But there's no correctness problem with
|
||||
* unnecessarily evicting. Nor is there a correctness problem with not
|
||||
* evicting while iput() is racing with the key being removed, since
|
||||
|
|
|
|||
|
|
@ -590,7 +590,7 @@ EXPORT_SYMBOL_GPL(fscrypt_ioctl_get_nonce);
|
|||
int fscrypt_has_permitted_context(struct inode *parent, struct inode *child)
|
||||
{
|
||||
union fscrypt_policy parent_policy, child_policy;
|
||||
int err;
|
||||
int err, err1, err2;
|
||||
|
||||
/* No restrictions on file types which are never encrypted */
|
||||
if (!S_ISREG(child->i_mode) && !S_ISDIR(child->i_mode) &&
|
||||
|
|
@ -620,19 +620,25 @@ int fscrypt_has_permitted_context(struct inode *parent, struct inode *child)
|
|||
* In any case, if an unexpected error occurs, fall back to "forbidden".
|
||||
*/
|
||||
|
||||
err = fscrypt_get_encryption_info(parent);
|
||||
err = fscrypt_get_encryption_info(parent, true);
|
||||
if (err)
|
||||
return 0;
|
||||
err = fscrypt_get_encryption_info(child);
|
||||
err = fscrypt_get_encryption_info(child, true);
|
||||
if (err)
|
||||
return 0;
|
||||
|
||||
err = fscrypt_get_policy(parent, &parent_policy);
|
||||
if (err)
|
||||
return 0;
|
||||
err1 = fscrypt_get_policy(parent, &parent_policy);
|
||||
err2 = fscrypt_get_policy(child, &child_policy);
|
||||
|
||||
err = fscrypt_get_policy(child, &child_policy);
|
||||
if (err)
|
||||
/*
|
||||
* Allow the case where the parent and child both have an unrecognized
|
||||
* encryption policy, so that files with an unrecognized encryption
|
||||
* policy can be deleted.
|
||||
*/
|
||||
if (err1 == -EINVAL && err2 == -EINVAL)
|
||||
return 1;
|
||||
|
||||
if (err1 || err2)
|
||||
return 0;
|
||||
|
||||
return fscrypt_policies_equal(&parent_policy, &child_policy);
|
||||
|
|
|
|||
|
|
@ -139,11 +139,9 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
|
|||
struct buffer_head *bh = NULL;
|
||||
struct fscrypt_str fstr = FSTR_INIT(NULL, 0);
|
||||
|
||||
if (IS_ENCRYPTED(inode)) {
|
||||
err = fscrypt_get_encryption_info(inode);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
err = fscrypt_prepare_readdir(inode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (is_dx_dir(inode)) {
|
||||
err = ext4_dx_readdir(file, ctx);
|
||||
|
|
@ -640,13 +638,6 @@ static int ext4_dx_readdir(struct file *file, struct dir_context *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ext4_dir_open(struct inode * inode, struct file * filp)
|
||||
{
|
||||
if (IS_ENCRYPTED(inode))
|
||||
return fscrypt_get_encryption_info(inode) ? -EACCES : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ext4_release_dir(struct inode *inode, struct file *filp)
|
||||
{
|
||||
if (filp->private_data)
|
||||
|
|
@ -688,6 +679,5 @@ const struct file_operations ext4_dir_operations = {
|
|||
.compat_ioctl = ext4_compat_ioctl,
|
||||
#endif
|
||||
.fsync = ext4_sync_file,
|
||||
.open = ext4_dir_open,
|
||||
.release = ext4_release_dir,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -647,13 +647,7 @@ static struct stats dx_show_leaf(struct inode *dir,
|
|||
|
||||
name = de->name;
|
||||
len = de->name_len;
|
||||
if (IS_ENCRYPTED(dir))
|
||||
res = fscrypt_get_encryption_info(dir);
|
||||
if (res) {
|
||||
printk(KERN_WARNING "Error setting up"
|
||||
" fname crypto: %d\n", res);
|
||||
}
|
||||
if (!fscrypt_has_encryption_key(dir)) {
|
||||
if (!IS_ENCRYPTED(dir)) {
|
||||
/* Directory is not encrypted */
|
||||
ext4fs_dirhash(dir, de->name,
|
||||
de->name_len, &h);
|
||||
|
|
@ -1036,7 +1030,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
|
|||
csum ? NULL : dir));
|
||||
/* Check if the directory is encrypted */
|
||||
if (IS_ENCRYPTED(dir)) {
|
||||
err = fscrypt_get_encryption_info(dir);
|
||||
err = fscrypt_prepare_readdir(dir);
|
||||
if (err < 0) {
|
||||
brelse(bh);
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -1076,7 +1076,7 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
|
|||
int err = 0;
|
||||
|
||||
if (IS_ENCRYPTED(inode)) {
|
||||
err = fscrypt_get_encryption_info(inode);
|
||||
err = fscrypt_prepare_readdir(inode);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
|
@ -1135,19 +1135,11 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
|
|||
return err < 0 ? err : 0;
|
||||
}
|
||||
|
||||
static int f2fs_dir_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
if (IS_ENCRYPTED(inode))
|
||||
return fscrypt_get_encryption_info(inode) ? -EACCES : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct file_operations f2fs_dir_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = generic_read_dir,
|
||||
.iterate_shared = f2fs_readdir,
|
||||
.fsync = f2fs_sync_file,
|
||||
.open = f2fs_dir_open,
|
||||
.unlocked_ioctl = f2fs_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = f2fs_compat_ioctl,
|
||||
|
|
|
|||
|
|
@ -515,7 +515,7 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
|
|||
return 0;
|
||||
|
||||
if (encrypted) {
|
||||
err = fscrypt_get_encryption_info(dir);
|
||||
err = fscrypt_prepare_readdir(dir);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
@ -1620,14 +1620,6 @@ int ubifs_getattr(const struct path *path, struct kstat *stat,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ubifs_dir_open(struct inode *dir, struct file *file)
|
||||
{
|
||||
if (IS_ENCRYPTED(dir))
|
||||
return fscrypt_get_encryption_info(dir) ? -EACCES : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct inode_operations ubifs_dir_inode_operations = {
|
||||
.lookup = ubifs_lookup,
|
||||
.create = ubifs_create,
|
||||
|
|
@ -1654,7 +1646,6 @@ const struct file_operations ubifs_dir_operations = {
|
|||
.iterate_shared = ubifs_readdir,
|
||||
.fsync = ubifs_fsync,
|
||||
.unlocked_ioctl = ubifs_ioctl,
|
||||
.open = ubifs_dir_open,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = ubifs_compat_ioctl,
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* fs/verity/enable.c: ioctl to enable verity on a file
|
||||
* Ioctl to enable verity on a file
|
||||
*
|
||||
* Copyright 2019 Google LLC
|
||||
*/
|
||||
|
|
@ -398,9 +398,9 @@ int fsverity_ioctl_enable(struct file *filp, const void __user *uarg)
|
|||
* Some pages of the file may have been evicted from pagecache after
|
||||
* being used in the Merkle tree construction, then read into pagecache
|
||||
* again by another process reading from the file concurrently. Since
|
||||
* these pages didn't undergo verification against the file measurement
|
||||
* which fs-verity now claims to be enforcing, we have to wipe the
|
||||
* pagecache to ensure that all future reads are verified.
|
||||
* these pages didn't undergo verification against the file digest which
|
||||
* fs-verity now claims to be enforcing, we have to wipe the pagecache
|
||||
* to ensure that all future reads are verified.
|
||||
*/
|
||||
filemap_write_and_wait(inode->i_mapping);
|
||||
invalidate_inode_pages2(inode->i_mapping);
|
||||
|
|
|
|||
|
|
@ -67,52 +67,22 @@ struct merkle_tree_params {
|
|||
* When a verity file is first opened, an instance of this struct is allocated
|
||||
* and stored in ->i_verity_info; it remains until the inode is evicted. It
|
||||
* caches information about the Merkle tree that's needed to efficiently verify
|
||||
* data read from the file. It also caches the file measurement. The Merkle
|
||||
* tree pages themselves are not cached here, but the filesystem may cache them.
|
||||
* data read from the file. It also caches the file digest. The Merkle tree
|
||||
* pages themselves are not cached here, but the filesystem may cache them.
|
||||
*/
|
||||
struct fsverity_info {
|
||||
struct merkle_tree_params tree_params;
|
||||
u8 root_hash[FS_VERITY_MAX_DIGEST_SIZE];
|
||||
u8 measurement[FS_VERITY_MAX_DIGEST_SIZE];
|
||||
u8 file_digest[FS_VERITY_MAX_DIGEST_SIZE];
|
||||
const struct inode *inode;
|
||||
};
|
||||
|
||||
/*
|
||||
* Merkle tree properties. The file measurement is the hash of this structure
|
||||
* excluding the signature and with the sig_size field set to 0.
|
||||
*/
|
||||
struct fsverity_descriptor {
|
||||
__u8 version; /* must be 1 */
|
||||
__u8 hash_algorithm; /* Merkle tree hash algorithm */
|
||||
__u8 log_blocksize; /* log2 of size of data and tree blocks */
|
||||
__u8 salt_size; /* size of salt in bytes; 0 if none */
|
||||
__le32 sig_size; /* size of signature in bytes; 0 if none */
|
||||
__le64 data_size; /* size of file the Merkle tree is built over */
|
||||
__u8 root_hash[64]; /* Merkle tree root hash */
|
||||
__u8 salt[32]; /* salt prepended to each hashed block */
|
||||
__u8 __reserved[144]; /* must be 0's */
|
||||
__u8 signature[]; /* optional PKCS#7 signature */
|
||||
};
|
||||
|
||||
/* Arbitrary limit to bound the kmalloc() size. Can be changed. */
|
||||
#define FS_VERITY_MAX_DESCRIPTOR_SIZE 16384
|
||||
|
||||
#define FS_VERITY_MAX_SIGNATURE_SIZE (FS_VERITY_MAX_DESCRIPTOR_SIZE - \
|
||||
sizeof(struct fsverity_descriptor))
|
||||
|
||||
/*
|
||||
* Format in which verity file measurements are signed. This is the same as
|
||||
* 'struct fsverity_digest', except here some magic bytes are prepended to
|
||||
* provide some context about what is being signed in case the same key is used
|
||||
* for non-fsverity purposes, and here the fields have fixed endianness.
|
||||
*/
|
||||
struct fsverity_signed_digest {
|
||||
char magic[8]; /* must be "FSVerity" */
|
||||
__le16 digest_algorithm;
|
||||
__le16 digest_size;
|
||||
__u8 digest[];
|
||||
};
|
||||
|
||||
/* hash_algs.c */
|
||||
|
||||
extern struct fsverity_hash_alg fsverity_hash_algs[];
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* fs/verity/hash_algs.c: fs-verity hash algorithms
|
||||
* fs-verity hash algorithms
|
||||
*
|
||||
* Copyright 2019 Google LLC
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* fs/verity/init.c: fs-verity module initialization and logging
|
||||
* fs-verity module initialization and logging
|
||||
*
|
||||
* Copyright 2019 Google LLC
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* fs/verity/measure.c: ioctl to get a verity file's measurement
|
||||
* Ioctl to get a verity file's digest
|
||||
*
|
||||
* Copyright 2019 Google LLC
|
||||
*/
|
||||
|
|
@ -10,12 +10,12 @@
|
|||
#include <linux/uaccess.h>
|
||||
|
||||
/**
|
||||
* fsverity_ioctl_measure() - get a verity file's measurement
|
||||
* @filp: file to get measurement of
|
||||
* fsverity_ioctl_measure() - get a verity file's digest
|
||||
* @filp: file to get digest of
|
||||
* @_uarg: user pointer to fsverity_digest
|
||||
*
|
||||
* Retrieve the file measurement that the kernel is enforcing for reads from a
|
||||
* verity file. See the "FS_IOC_MEASURE_VERITY" section of
|
||||
* Retrieve the file digest that the kernel is enforcing for reads from a verity
|
||||
* file. See the "FS_IOC_MEASURE_VERITY" section of
|
||||
* Documentation/filesystems/fsverity.rst for the documentation.
|
||||
*
|
||||
* Return: 0 on success, -errno on failure
|
||||
|
|
@ -51,7 +51,7 @@ int fsverity_ioctl_measure(struct file *filp, void __user *_uarg)
|
|||
if (copy_to_user(uarg, &arg, sizeof(arg)))
|
||||
return -EFAULT;
|
||||
|
||||
if (copy_to_user(uarg->digest, vi->measurement, hash_alg->digest_size))
|
||||
if (copy_to_user(uarg->digest, vi->file_digest, hash_alg->digest_size))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* fs/verity/open.c: opening fs-verity files
|
||||
* Opening fs-verity files
|
||||
*
|
||||
* Copyright 2019 Google LLC
|
||||
*/
|
||||
|
|
@ -124,18 +124,18 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params,
|
|||
}
|
||||
|
||||
/*
|
||||
* Compute the file measurement by hashing the fsverity_descriptor excluding the
|
||||
* Compute the file digest by hashing the fsverity_descriptor excluding the
|
||||
* signature and with the sig_size field set to 0.
|
||||
*/
|
||||
static int compute_file_measurement(struct fsverity_hash_alg *hash_alg,
|
||||
struct fsverity_descriptor *desc,
|
||||
u8 *measurement)
|
||||
static int compute_file_digest(struct fsverity_hash_alg *hash_alg,
|
||||
struct fsverity_descriptor *desc,
|
||||
u8 *file_digest)
|
||||
{
|
||||
__le32 sig_size = desc->sig_size;
|
||||
int err;
|
||||
|
||||
desc->sig_size = 0;
|
||||
err = fsverity_hash_buffer(hash_alg, desc, sizeof(*desc), measurement);
|
||||
err = fsverity_hash_buffer(hash_alg, desc, sizeof(*desc), file_digest);
|
||||
desc->sig_size = sig_size;
|
||||
|
||||
return err;
|
||||
|
|
@ -199,15 +199,15 @@ struct fsverity_info *fsverity_create_info(const struct inode *inode,
|
|||
|
||||
memcpy(vi->root_hash, desc->root_hash, vi->tree_params.digest_size);
|
||||
|
||||
err = compute_file_measurement(vi->tree_params.hash_alg, desc,
|
||||
vi->measurement);
|
||||
err = compute_file_digest(vi->tree_params.hash_alg, desc,
|
||||
vi->file_digest);
|
||||
if (err) {
|
||||
fsverity_err(inode, "Error %d computing file measurement", err);
|
||||
fsverity_err(inode, "Error %d computing file digest", err);
|
||||
goto out;
|
||||
}
|
||||
pr_debug("Computed file measurement: %s:%*phN\n",
|
||||
pr_debug("Computed file digest: %s:%*phN\n",
|
||||
vi->tree_params.hash_alg->name,
|
||||
vi->tree_params.digest_size, vi->measurement);
|
||||
vi->tree_params.digest_size, vi->file_digest);
|
||||
|
||||
err = fsverity_verify_signature(vi, desc, desc_size);
|
||||
out:
|
||||
|
|
@ -354,7 +354,7 @@ int __init fsverity_init_info_cache(void)
|
|||
{
|
||||
fsverity_info_cachep = KMEM_CACHE_USERCOPY(fsverity_info,
|
||||
SLAB_RECLAIM_ACCOUNT,
|
||||
measurement);
|
||||
file_digest);
|
||||
if (!fsverity_info_cachep)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* fs/verity/signature.c: verification of builtin signatures
|
||||
* Verification of builtin signatures
|
||||
*
|
||||
* Copyright 2019 Google LLC
|
||||
*/
|
||||
|
|
@ -32,8 +32,8 @@ static struct key *fsverity_keyring;
|
|||
* @desc: the file's fsverity_descriptor
|
||||
* @desc_size: size of @desc
|
||||
*
|
||||
* If the file's fs-verity descriptor includes a signature of the file
|
||||
* measurement, verify it against the certificates in the fs-verity keyring.
|
||||
* If the file's fs-verity descriptor includes a signature of the file digest,
|
||||
* verify it against the certificates in the fs-verity keyring.
|
||||
*
|
||||
* Return: 0 on success (signature valid or not required); -errno on failure
|
||||
*/
|
||||
|
|
@ -44,7 +44,7 @@ int fsverity_verify_signature(const struct fsverity_info *vi,
|
|||
const struct inode *inode = vi->inode;
|
||||
const struct fsverity_hash_alg *hash_alg = vi->tree_params.hash_alg;
|
||||
const u32 sig_size = le32_to_cpu(desc->sig_size);
|
||||
struct fsverity_signed_digest *d;
|
||||
struct fsverity_formatted_digest *d;
|
||||
int err;
|
||||
|
||||
if (sig_size == 0) {
|
||||
|
|
@ -67,7 +67,7 @@ int fsverity_verify_signature(const struct fsverity_info *vi,
|
|||
memcpy(d->magic, "FSVerity", 8);
|
||||
d->digest_algorithm = cpu_to_le16(hash_alg - fsverity_hash_algs);
|
||||
d->digest_size = cpu_to_le16(hash_alg->digest_size);
|
||||
memcpy(d->digest, vi->measurement, hash_alg->digest_size);
|
||||
memcpy(d->digest, vi->file_digest, hash_alg->digest_size);
|
||||
|
||||
err = verify_pkcs7_signature(d, sizeof(*d) + hash_alg->digest_size,
|
||||
desc->signature, sig_size,
|
||||
|
|
@ -90,8 +90,8 @@ int fsverity_verify_signature(const struct fsverity_info *vi,
|
|||
return err;
|
||||
}
|
||||
|
||||
pr_debug("Valid signature for file measurement %s:%*phN\n",
|
||||
hash_alg->name, hash_alg->digest_size, vi->measurement);
|
||||
pr_debug("Valid signature for file digest %s:%*phN\n",
|
||||
hash_alg->name, hash_alg->digest_size, vi->file_digest);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* fs/verity/verify.c: data verification functions, i.e. hooks for ->readpages()
|
||||
* Data verification functions, i.e. hooks for ->readpages()
|
||||
*
|
||||
* Copyright 2019 Google LLC
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ struct fscrypt_operations {
|
|||
static inline struct fscrypt_info *fscrypt_get_info(const struct inode *inode)
|
||||
{
|
||||
/*
|
||||
* Pairs with the cmpxchg_release() in fscrypt_get_encryption_info().
|
||||
* Pairs with the cmpxchg_release() in fscrypt_setup_encryption_info().
|
||||
* I.e., another task may publish ->i_crypt_info concurrently, executing
|
||||
* a RELEASE barrier. We need to use smp_load_acquire() here to safely
|
||||
* ACQUIRE the memory the other task published.
|
||||
|
|
@ -200,7 +200,6 @@ int fscrypt_ioctl_remove_key_all_users(struct file *filp, void __user *arg);
|
|||
int fscrypt_ioctl_get_key_status(struct file *filp, void __user *arg);
|
||||
|
||||
/* keysetup.c */
|
||||
int fscrypt_get_encryption_info(struct inode *inode);
|
||||
int fscrypt_prepare_new_inode(struct inode *dir, struct inode *inode,
|
||||
bool *encrypt_ret);
|
||||
void fscrypt_put_encryption_info(struct inode *inode);
|
||||
|
|
@ -242,6 +241,8 @@ int __fscrypt_prepare_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
unsigned int flags);
|
||||
int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct fscrypt_name *fname);
|
||||
int __fscrypt_prepare_readdir(struct inode *dir);
|
||||
int __fscrypt_prepare_setattr(struct dentry *dentry, struct iattr *attr);
|
||||
int fscrypt_prepare_setflags(struct inode *inode,
|
||||
unsigned int oldflags, unsigned int flags);
|
||||
int fscrypt_prepare_symlink(struct inode *dir, const char *target,
|
||||
|
|
@ -406,10 +407,6 @@ static inline int fscrypt_ioctl_get_key_status(struct file *filp,
|
|||
}
|
||||
|
||||
/* keysetup.c */
|
||||
static inline int fscrypt_get_encryption_info(struct inode *inode)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int fscrypt_prepare_new_inode(struct inode *dir,
|
||||
struct inode *inode,
|
||||
|
|
@ -537,6 +534,17 @@ static inline int __fscrypt_prepare_lookup(struct inode *dir,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int __fscrypt_prepare_readdir(struct inode *dir)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int __fscrypt_prepare_setattr(struct dentry *dentry,
|
||||
struct iattr *attr)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int fscrypt_prepare_setflags(struct inode *inode,
|
||||
unsigned int oldflags,
|
||||
unsigned int flags)
|
||||
|
|
@ -708,32 +716,6 @@ static inline bool fscrypt_has_encryption_key(const struct inode *inode)
|
|||
return fscrypt_get_info(inode) != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* fscrypt_require_key() - require an inode's encryption key
|
||||
* @inode: the inode we need the key for
|
||||
*
|
||||
* If the inode is encrypted, set up its encryption key if not already done.
|
||||
* Then require that the key be present and return -ENOKEY otherwise.
|
||||
*
|
||||
* No locks are needed, and the key will live as long as the struct inode --- so
|
||||
* it won't go away from under you.
|
||||
*
|
||||
* Return: 0 on success, -ENOKEY if the key is missing, or another -errno code
|
||||
* if a problem occurred while setting up the encryption key.
|
||||
*/
|
||||
static inline int fscrypt_require_key(struct inode *inode)
|
||||
{
|
||||
if (IS_ENCRYPTED(inode)) {
|
||||
int err = fscrypt_get_encryption_info(inode);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
if (!fscrypt_has_encryption_key(inode))
|
||||
return -ENOKEY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fscrypt_prepare_link() - prepare to link an inode into a possibly-encrypted
|
||||
* directory
|
||||
|
|
@ -743,8 +725,7 @@ static inline int fscrypt_require_key(struct inode *inode)
|
|||
*
|
||||
* A new link can only be added to an encrypted directory if the directory's
|
||||
* encryption key is available --- since otherwise we'd have no way to encrypt
|
||||
* the filename. Therefore, we first set up the directory's encryption key (if
|
||||
* not already done) and return an error if it's unavailable.
|
||||
* the filename.
|
||||
*
|
||||
* We also verify that the link will not violate the constraint that all files
|
||||
* in an encrypted directory tree use the same encryption policy.
|
||||
|
|
@ -805,8 +786,9 @@ static inline int fscrypt_prepare_rename(struct inode *old_dir,
|
|||
*
|
||||
* Prepare for ->lookup() in a directory which may be encrypted by determining
|
||||
* the name that will actually be used to search the directory on-disk. If the
|
||||
* directory's encryption key is available, then the lookup is assumed to be by
|
||||
* plaintext name; otherwise, it is assumed to be by no-key name.
|
||||
* directory's encryption policy is supported by this kernel and its encryption
|
||||
* key is available, then the lookup is assumed to be by plaintext name;
|
||||
* otherwise, it is assumed to be by no-key name.
|
||||
*
|
||||
* This will set DCACHE_NOKEY_NAME on the dentry if the lookup is by no-key
|
||||
* name. In this case the filesystem must assign the dentry a dentry_operations
|
||||
|
|
@ -832,6 +814,26 @@ static inline int fscrypt_prepare_lookup(struct inode *dir,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fscrypt_prepare_readdir() - prepare to read a possibly-encrypted directory
|
||||
* @dir: the directory inode
|
||||
*
|
||||
* If the directory is encrypted and it doesn't already have its encryption key
|
||||
* set up, try to set it up so that the filenames will be listed in plaintext
|
||||
* form rather than in no-key form.
|
||||
*
|
||||
* Return: 0 on success; -errno on error. Note that the encryption key being
|
||||
* unavailable is not considered an error. It is also not an error if
|
||||
* the encryption policy is unsupported by this kernel; that is treated
|
||||
* like the key being unavailable, so that files can still be deleted.
|
||||
*/
|
||||
static inline int fscrypt_prepare_readdir(struct inode *dir)
|
||||
{
|
||||
if (IS_ENCRYPTED(dir))
|
||||
return __fscrypt_prepare_readdir(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fscrypt_prepare_setattr() - prepare to change a possibly-encrypted inode's
|
||||
* attributes
|
||||
|
|
@ -853,8 +855,8 @@ static inline int fscrypt_prepare_lookup(struct inode *dir,
|
|||
static inline int fscrypt_prepare_setattr(struct dentry *dentry,
|
||||
struct iattr *attr)
|
||||
{
|
||||
if (attr->ia_valid & ATTR_SIZE)
|
||||
return fscrypt_require_key(d_inode(dentry));
|
||||
if (IS_ENCRYPTED(d_inode(dentry)))
|
||||
return __fscrypt_prepare_setattr(dentry, attr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,55 @@ struct fsverity_digest {
|
|||
__u8 digest[];
|
||||
};
|
||||
|
||||
/*
|
||||
* Struct containing a file's Merkle tree properties. The fs-verity file digest
|
||||
* is the hash of this struct. A userspace program needs this struct only if it
|
||||
* needs to compute fs-verity file digests itself, e.g. in order to sign files.
|
||||
* It isn't needed just to enable fs-verity on a file.
|
||||
*
|
||||
* Note: when computing the file digest, 'sig_size' and 'signature' must be left
|
||||
* zero and empty, respectively. These fields are present only because some
|
||||
* filesystems reuse this struct as part of their on-disk format.
|
||||
*/
|
||||
struct fsverity_descriptor {
|
||||
__u8 version; /* must be 1 */
|
||||
__u8 hash_algorithm; /* Merkle tree hash algorithm */
|
||||
__u8 log_blocksize; /* log2 of size of data and tree blocks */
|
||||
__u8 salt_size; /* size of salt in bytes; 0 if none */
|
||||
#ifdef __KERNEL__
|
||||
__le32 sig_size;
|
||||
#else
|
||||
__le32 __reserved_0x04; /* must be 0 */
|
||||
#endif
|
||||
__le64 data_size; /* size of file the Merkle tree is built over */
|
||||
__u8 root_hash[64]; /* Merkle tree root hash */
|
||||
__u8 salt[32]; /* salt prepended to each hashed block */
|
||||
__u8 __reserved[144]; /* must be 0's */
|
||||
#ifdef __KERNEL__
|
||||
__u8 signature[];
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* Format in which fs-verity file digests are signed in built-in signatures.
|
||||
* This is the same as 'struct fsverity_digest', except here some magic bytes
|
||||
* are prepended to provide some context about what is being signed in case the
|
||||
* same key is used for non-fsverity purposes, and here the fields have fixed
|
||||
* endianness.
|
||||
*
|
||||
* This struct is specific to the built-in signature verification support, which
|
||||
* is optional. fs-verity users may also verify signatures in userspace, in
|
||||
* which case userspace is responsible for deciding on what bytes are signed.
|
||||
* This struct may still be used, but it doesn't have to be. For example,
|
||||
* userspace could instead use a string like "sha256:$digest_as_hex_string".
|
||||
*/
|
||||
struct fsverity_formatted_digest {
|
||||
char magic[8]; /* must be "FSVerity" */
|
||||
__le16 digest_algorithm;
|
||||
__le16 digest_size;
|
||||
__u8 digest[];
|
||||
};
|
||||
|
||||
#define FS_IOC_ENABLE_VERITY _IOW('f', 133, struct fsverity_enable_arg)
|
||||
#define FS_IOC_MEASURE_VERITY _IOWR('f', 134, struct fsverity_digest)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user