@@ -819,7 +819,6 @@ int fscrypt_get_encryption_info(struct inode *inode, bool allow_unsupported)
IS_CASEFOLDED(inode) &&
S_ISDIR(inode->i_mode),
NULL);
-
if (res == -ENOPKG && allow_unsupported) /* Algorithm unavailable? */
res = 0;
if (res == -ENOKEY)
@@ -943,6 +942,55 @@ void fscrypt_free_extent_info(struct fscrypt_info **info_ptr)
}
EXPORT_SYMBOL_GPL(fscrypt_free_extent_info);
+/**
+ * fscrypt_load_extent_info() - set up a preexisting extent's fscrypt_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_info into. Should be
+ * a pointer to a member of the extent struct, as it will be passed
+ * back to the filesystem if key removal demands removal of the
+ * info from the extent
+ *
+ * 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_info **info_ptr)
+{
+ int res;
+ union fscrypt_context ctx;
+ union fscrypt_policy policy;
+
+ if (!fscrypt_has_encryption_key(inode))
+ return -EINVAL;
+
+ memcpy(&ctx, buf, len);
+
+ res = fscrypt_policy_from_context(&policy, &ctx, len);
+ if (res) {
+ fscrypt_warn(inode,
+ "Unrecognized or corrupt encryption context");
+ return res;
+ }
+
+ if (!fscrypt_supported_policy(&policy, inode))
+ return -EINVAL;
+
+ res = fscrypt_setup_encryption_info(inode, &policy,
+ fscrypt_context_nonce(&ctx),
+ IS_CASEFOLDED(inode) &&
+ S_ISDIR(inode->i_mode),
+ info_ptr);
+
+ if (res == -ENOPKG) /* Algorithm unavailable? */
+ res = 0;
+ return res;
+}
+EXPORT_SYMBOL_GPL(fscrypt_load_extent_info);
+
/**
* fscrypt_put_encryption_info() - free most of an inode's fscrypt data
* @inode: an inode being evicted
@@ -762,6 +762,26 @@ int fscrypt_set_context(struct inode *inode, void *fs_data)
}
EXPORT_SYMBOL_GPL(fscrypt_set_context);
+/**
+ * fscrypt_set_extent_context() - Set the fscrypt 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_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_SET_CONTEXT_MAX_SIZE bytes.
+ *
+ * Return: size of the resulting context or a negative error code.
+ */
+int fscrypt_set_extent_context(struct fscrypt_info *ci, void *ctx, size_t len)
+{
+ if (len < FSCRYPT_SET_CONTEXT_MAX_SIZE)
+ return -EINVAL;
+ return fscrypt_new_context(ctx, &ci->ci_policy, ci->ci_nonce);
+}
+EXPORT_SYMBOL_GPL(fscrypt_set_extent_context);
+
/**
* fscrypt_parse_test_dummy_encryption() - parse the test_dummy_encryption mount option
* @param: the mount option
@@ -334,6 +334,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_info *info, void *ctx,
+ size_t len);
struct fscrypt_dummy_policy {
const union fscrypt_policy *policy;
@@ -374,6 +376,8 @@ int fscrypt_drop_inode(struct inode *inode);
int fscrypt_prepare_new_extent(struct inode *inode,
struct fscrypt_info **info_ptr);
void fscrypt_free_extent_info(struct fscrypt_info **info_ptr);
+int fscrypt_load_extent_info(struct inode *inode, void *buf, size_t len,
+ struct fscrypt_info **info_ptr);
/* fname.c */
int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname,
@@ -550,6 +554,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 {
};
@@ -648,6 +658,13 @@ static inline void fscrypt_free_extent_info(struct fscrypt_info **info_ptr)
{
}
+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. Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me> --- fs/crypto/keysetup.c | 50 ++++++++++++++++++++++++++++++++++++++++- fs/crypto/policy.c | 20 +++++++++++++++++ include/linux/fscrypt.h | 17 ++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-)