static int ll_get_context(struct inode *inode, void *ctx, size_t len)
{
- struct dentry *dentry = d_find_any_alias(inode);
int rc;
- rc = ll_vfs_getxattr(dentry, inode, LL_XATTR_NAME_ENCRYPTION_CONTEXT,
- ctx, len);
- if (dentry)
- dput(dentry);
+ /* Get enc context xattr directly instead of going through the VFS,
+ * as there is no xattr handler for "encryption.".
+ */
+ rc = ll_xattr_list(inode, LL_XATTR_NAME_ENCRYPTION_CONTEXT,
+ XATTR_ENCRYPTION_T, ctx, len, OBD_MD_FLXATTR);
/* used as encryption unit size */
if (S_ISREG(inode->i_mode))
* op_data, so that it will be sent along to the server with the request that
* the caller is preparing, thus saving a setxattr request.
* - inode is not NULL:
- * normal case in which passed fs_data is a struct dentry *, letting proceed
- * with setxattr operation.
+ * normal case, letting proceed with setxattr operation.
* This use case should only be used when explicitly setting a new encryption
* policy on an existing, empty directory.
*/
static int ll_set_context(struct inode *inode, const void *ctx, size_t len,
void *fs_data)
{
- struct dentry *dentry;
+ struct ptlrpc_request *req = NULL;
+ struct ll_sb_info *sbi;
int rc;
if (inode == NULL) {
if (is_root_inode(inode))
return -EPERM;
- dentry = (struct dentry *)fs_data;
- set_bit(LLIF_SET_ENC_CTX, &ll_i2info(inode)->lli_flags);
- rc = ll_vfs_setxattr(dentry, inode, LL_XATTR_NAME_ENCRYPTION_CONTEXT,
- ctx, len, XATTR_CREATE);
+ sbi = ll_i2sbi(inode);
+ /* Send setxattr request to lower layers directly instead of going
+ * through the VFS, as there is no xattr handler for "encryption.".
+ */
+ rc = md_setxattr(sbi->ll_md_exp, ll_inode2fid(inode),
+ OBD_MD_FLXATTR, LL_XATTR_NAME_ENCRYPTION_CONTEXT,
+ ctx, len, XATTR_CREATE, ll_i2suppgid(inode), &req);
if (rc)
return rc;
+ ptlrpc_req_finished(req);
return ll_set_encflags(inode, (void *)ctx, len, false);
}
+/**
+ * ll_file_open_encrypt() - overlay to llcrypt_file_open
+ * @inode: the inode being opened
+ * @filp: the struct file being set up
+ *
+ * This overlay function is necessary to handle encrypted file open without
+ * the key. We allow this access pattern to applications that know what they
+ * are doing, by using the specific flag O_FILE_ENC.
+ * This flag is only compatible with O_DIRECT IOs, to make sure ciphertext
+ * data is wiped from page cache once IOs are finished.
+ */
+int ll_file_open_encrypt(struct inode *inode, struct file *filp)
+{
+ int rc;
+
+ rc = llcrypt_file_open(inode, filp);
+ if (likely(rc != -ENOKEY))
+ return rc;
+
+ if (rc == -ENOKEY &&
+ (filp->f_flags & O_FILE_ENC) == O_FILE_ENC &&
+ filp->f_flags & O_DIRECT)
+ /* allow file open with O_FILE_ENC flag when we have O_DIRECT */
+ rc = 0;
+
+ return rc;
+}
+
void llcrypt_free_ctx(void *encctx, __u32 size)
{
if (encctx)
OBD_FREE(encctx, size);
}
-bool ll_sbi_has_test_dummy_encryption(struct ll_sb_info *sbi)
+#ifdef HAVE_FSCRYPT_DUMMY_CONTEXT_ENABLED
+bool ll_sb_has_test_dummy_encryption(struct super_block *sb)
{
- return unlikely(sbi->ll_flags & LL_SBI_TEST_DUMMY_ENCRYPTION);
+ struct ll_sb_info *sbi = s2lsi(sb)->lsi_llsbi;
+
+ return sbi ?
+ unlikely(test_bit(LL_SBI_TEST_DUMMY_ENCRYPTION, sbi->ll_flags)) :
+ false;
}
static bool ll_dummy_context(struct inode *inode)
{
- struct ll_sb_info *sbi = ll_i2sbi(inode);
+ return ll_sb_has_test_dummy_encryption(inode->i_sb);
+}
+#else
+static const union llcrypt_context *
+ll_get_dummy_context(struct super_block *sb)
+{
+ struct lustre_sb_info *lsi = s2lsi(sb);
+
+ return lsi ? lsi->lsi_dummy_enc_ctx.ctx : NULL;
+}
- return sbi ? ll_sbi_has_test_dummy_encryption(sbi) : false;
+bool ll_sb_has_test_dummy_encryption(struct super_block *sb)
+{
+ return ll_get_dummy_context(sb) != NULL;
}
+#endif
bool ll_sbi_has_encrypt(struct ll_sb_info *sbi)
{
- return sbi->ll_flags & LL_SBI_ENCRYPT;
+ return test_bit(LL_SBI_ENCRYPT, sbi->ll_flags);
}
void ll_sbi_set_encrypt(struct ll_sb_info *sbi, bool set)
{
- if (set)
- sbi->ll_flags |= LL_SBI_ENCRYPT;
- else
- sbi->ll_flags &=
- ~(LL_SBI_ENCRYPT | LL_SBI_TEST_DUMMY_ENCRYPTION);
+ if (set) {
+ set_bit(LL_SBI_ENCRYPT, sbi->ll_flags);
+ } else {
+ clear_bit(LL_SBI_ENCRYPT, sbi->ll_flags);
+ clear_bit(LL_SBI_TEST_DUMMY_ENCRYPTION, sbi->ll_flags);
+ }
}
static bool ll_empty_dir(struct inode *inode)
fid->f_ver = 0;
}
rc = llcrypt_setup_filename(dir, &dname, lookup, fname);
+ if (rc == -ENOENT && lookup) {
+ if (((is_root_inode(dir) &&
+ iname->len == strlen(dot_fscrypt_name) &&
+ strncmp(iname->name, dot_fscrypt_name, iname->len) == 0) ||
+ (!llcrypt_has_encryption_key(dir) &&
+ unlikely(filename_is_volatile(iname->name,
+ iname->len, NULL))))) {
+ /* In case of subdir mount of an encrypted directory,
+ * we allow lookup of /.fscrypt directory.
+ */
+ /* For purpose of migration or mirroring without enc key
+ * we allow lookup of volatile file without enc context.
+ */
+ memset(fname, 0, sizeof(struct llcrypt_name));
+ fname->disk_name.name = (unsigned char *)iname->name;
+ fname->disk_name.len = iname->len;
+ rc = 0;
+ } else if (!llcrypt_has_encryption_key(dir)) {
+ rc = -ENOKEY;
+ }
+ }
if (rc)
return rc;
rc = -EINVAL;
goto out_free;
}
- digest = (struct ll_digest_filename *)fname->crypto_buf.name;
+ digest = (struct ll_digest_filename *)fname->disk_name.name;
*fid = digest->ldf_fid;
if (!fid_is_sane(fid)) {
rc = -EINVAL;
goto out_free;
}
fname->disk_name.name = digest->ldf_excerpt;
- fname->disk_name.len = LLCRYPT_FNAME_DIGEST_SIZE;
+ fname->disk_name.len = sizeof(digest->ldf_excerpt);
}
if (IS_ENCRYPTED(dir) &&
!name_is_dot_or_dotdot(fname->disk_name.name,
lltr.name = buf;
lltr.len = len;
}
- if (lltr.len > LLCRYPT_FNAME_MAX_UNDIGESTED_SIZE &&
+ if (lltr.len > LL_CRYPTO_BLOCK_SIZE * 2 &&
!llcrypt_has_encryption_key(inode) &&
- likely(llcrypt_policy_has_filename_enc(inode))) {
+ llcrypt_policy_has_filename_enc(inode)) {
digested = 1;
/* Without the key for long names, set the dentry name
* to the representing struct ll_digest_filename. It
return -EINVAL;
digest.ldf_fid = *fid;
memcpy(digest.ldf_excerpt,
- LLCRYPT_FNAME_DIGEST(lltr.name, lltr.len),
- LLCRYPT_FNAME_DIGEST_SIZE);
+ LLCRYPT_EXTRACT_DIGEST(lltr.name, lltr.len),
+ sizeof(digest.ldf_excerpt));
lltr.name = (char *)&digest;
lltr.len = sizeof(digest);
* reverting to ciphertext names without evicting the directory's inode
* -- which implies eviction of the dentries in the directory.
*/
- if (!(dentry->d_flags & DCACHE_ENCRYPTED_NAME))
+ if (!llcrypt_is_nokey_name(dentry))
return 1;
/*
.key_prefix = "lustre:",
.get_context = ll_get_context,
.set_context = ll_set_context,
+#ifdef HAVE_FSCRYPT_DUMMY_CONTEXT_ENABLED
.dummy_context = ll_dummy_context,
+#else
+ .get_dummy_context = ll_get_dummy_context,
+#endif
.empty_dir = ll_empty_dir,
.max_namelen = NAME_MAX,
};
return 0;
}
+int ll_file_open_encrypt(struct inode *inode, struct file *filp)
+{
+ return llcrypt_file_open(inode, filp);
+}
+
void llcrypt_free_ctx(void *encctx, __u32 size)
{
}
-bool ll_sbi_has_test_dummy_encryption(struct ll_sb_info *sbi)
+bool ll_sb_has_test_dummy_encryption(struct super_block *sb)
{
return false;
}