@@ -1044,6 +1044,45 @@ int fscrypt_prepare_new_extent(struct inode *inode,
}
EXPORT_SYMBOL_GPL(fscrypt_prepare_new_extent);
+/**
+ * fscrypt_load_extent_info() - load a preexisting extent's fscrypt_extent_info
+ * @inode: the inode to which the extent belongs. Must be encrypted.
+ * @buf: a buffer containing the extent's stored context
+ * @len: the length of the @ctx buffer
+ * @info_ptr: a pointer to return the extent's fscrypt_extent_info into
+ *
+ * This is not %GFP_NOFS safe, so the caller is expected to call
+ * memalloc_nofs_save/restore() if appropriate.
+ *
+ * Return: 0 if successful, or -errno if it fails.
+ */
+int fscrypt_load_extent_info(struct inode *inode, void *buf, size_t len,
+ struct fscrypt_extent_info **info_ptr)
+{
+ int res;
+ union fscrypt_context ctx;
+ const union fscrypt_policy *policy;
+
+ if (!fscrypt_has_encryption_key(inode))
+ return -EINVAL;
+
+ if (len != FSCRYPT_FILE_NONCE_SIZE) {
+ fscrypt_warn(inode,
+ "Unrecognized or corrupt encryption context");
+ return -EINVAL;
+ }
+
+ policy = fscrypt_policy_to_inherit(inode);
+ if (policy == NULL)
+ return 0;
+ if (IS_ERR(policy))
+ return PTR_ERR(policy);
+
+ return fscrypt_setup_extent_info(inode, policy, buf,
+ info_ptr);
+}
+EXPORT_SYMBOL_GPL(fscrypt_load_extent_info);
+
/**
* fscrypt_free_extent_info() - free an extent's fscrypt_extent_info
* @info_ptr: a pointer containing the extent's fscrypt_extent_info pointer.
@@ -763,6 +763,28 @@ int fscrypt_set_context(struct inode *inode, void *fs_data)
}
EXPORT_SYMBOL_GPL(fscrypt_set_context);
+/**
+ * fscrypt_set_extent_context() - Set the fscrypt extent context for an extent
+ * @ci: info from which to fetch policy and nonce
+ * @ctx: where context should be written
+ * @len: the size of ctx
+ *
+ * Given an fscrypt_extent_info belonging to an extent (generated via
+ * fscrypt_prepare_new_extent()), generate a new context and write it to @ctx.
+ * len is checked to be at least FSCRYPT_EXTENT_CONTEXT_MAX_SIZE bytes.
+ *
+ * Return: size of the resulting context or a negative error code.
+ */
+int fscrypt_set_extent_context(struct fscrypt_extent_info *ci, void *ctx,
+ size_t len)
+{
+ if (len < FSCRYPT_EXTENT_CONTEXT_MAX_SIZE)
+ return -EINVAL;
+ memcpy(ctx, ci->info.ci_nonce, FSCRYPT_FILE_NONCE_SIZE);
+ return FSCRYPT_FILE_NONCE_SIZE;
+}
+EXPORT_SYMBOL_GPL(fscrypt_set_extent_context);
+
/**
* fscrypt_parse_test_dummy_encryption() - parse the test_dummy_encryption mount option
* @param: the mount option
@@ -57,6 +57,7 @@ struct fscrypt_name {
/* Maximum value for the third parameter of fscrypt_operations.set_context(). */
#define FSCRYPT_SET_CONTEXT_MAX_SIZE 40
+#define FSCRYPT_EXTENT_CONTEXT_MAX_SIZE 16
#ifdef CONFIG_FS_ENCRYPTION
@@ -317,6 +318,8 @@ int fscrypt_ioctl_get_nonce(struct file *filp, void __user *arg);
int fscrypt_has_permitted_context(struct inode *parent, struct inode *child);
int fscrypt_context_for_new_inode(void *ctx, struct inode *inode);
int fscrypt_set_context(struct inode *inode, void *fs_data);
+int fscrypt_set_extent_context(struct fscrypt_extent_info *info, void *ctx,
+ size_t len);
struct fscrypt_dummy_policy {
const union fscrypt_policy *policy;
@@ -357,6 +360,9 @@ int fscrypt_drop_inode(struct inode *inode);
int fscrypt_prepare_new_extent(struct inode *inode,
struct fscrypt_extent_info **info_ptr);
void fscrypt_free_extent_info(struct fscrypt_extent_info **info_ptr);
+int fscrypt_load_extent_info(struct inode *inode, void *buf, size_t len,
+ struct fscrypt_extent_info **info_ptr);
+
/* fname.c */
int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname,
@@ -533,6 +539,12 @@ static inline int fscrypt_set_context(struct inode *inode, void *fs_data)
return -EOPNOTSUPP;
}
+static inline int fscrypt_set_extent_context(struct fscrypt_info *info,
+ void *ctx, size_t len)
+{
+ return -EOPNOTSUPP;
+}
+
struct fscrypt_dummy_policy {
};
@@ -632,6 +644,13 @@ static inline void fscrypt_free_extent_info(struct fscrypt_extent_info **info_pt
{
}
+static inline int fscrypt_load_extent_info(struct inode *inode, void *buf,
+ size_t len,
+ struct fscrypt_info **info_ptr)
+{
+ return -EOPNOTSUPP;
+}
+
/* fname.c */
static inline int fscrypt_setup_filename(struct inode *dir,
const struct qstr *iname,
The other half of using per-extent infos is saving and loading them from disk. This is the one change which cares about whether a lightweight or heavyweight extent context is stored on disk. This implements the lightweight version. Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me> --- fs/crypto/keysetup.c | 39 +++++++++++++++++++++++++++++++++++++++ fs/crypto/policy.c | 22 ++++++++++++++++++++++ include/linux/fscrypt.h | 19 +++++++++++++++++++ 3 files changed, 80 insertions(+)