/* 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,
+ rc = ll_xattr_list(inode, xattr_for_enc(inode),
XATTR_ENCRYPTION_T, ctx, len, OBD_MD_FLXATTR);
/* used as encryption unit size */
if (encctx && encctxlen)
rc = ll_xattr_cache_insert(inode,
- LL_XATTR_NAME_ENCRYPTION_CONTEXT,
+ xattr_for_enc(inode),
encctx, encctxlen);
if (rc)
return rc;
- return preload ? llcrypt_get_encryption_info(inode) : 0;
+ return preload ? llcrypt_prepare_readdir(inode) : 0;
}
/* ll_set_context has 2 distinct behaviors, depending on the value of inode
* 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,
+ OBD_MD_FLXATTR, xattr_for_enc(inode),
ctx, len, XATTR_CREATE, ll_i2suppgid(inode), &req);
if (rc)
return rc;
*
* 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.
+ * are doing, by using the specific flag O_CIPHERTEXT.
* This flag is only compatible with O_DIRECT IOs, to make sure ciphertext
* data is wiped from page cache once IOs are finished.
*/
return rc;
if (rc == -ENOKEY &&
- (filp->f_flags & O_FILE_ENC) == O_FILE_ENC &&
+ (filp->f_flags & O_CIPHERTEXT) == O_CIPHERTEXT &&
filp->f_flags & O_DIRECT)
- /* allow file open with O_FILE_ENC flag when we have O_DIRECT */
+ /* allow open with O_CIPHERTEXT flag when we have O_DIRECT */
rc = 0;
return rc;
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(test_bit(LL_SBI_TEST_DUMMY_ENCRYPTION, sbi->ll_flags));
+ 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_policy *
+ll_get_dummy_policy(struct super_block *sb)
+{
+ struct lustre_sb_info *lsi = s2lsi(sb);
+
+#ifdef HAVE_FSCRYPT_DUMMY_POLICY
+ return lsi ? lsi->lsi_dummy_enc_policy.policy : NULL;
+#else
+ return lsi ? lsi->lsi_dummy_enc_policy.ctx : NULL;
+#endif
+}
- 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_policy(sb) != NULL;
}
+#endif
bool ll_sbi_has_encrypt(struct ll_sb_info *sbi)
{
}
}
+bool ll_sbi_has_name_encrypt(struct ll_sb_info *sbi)
+{
+ return test_bit(LL_SBI_ENCRYPT_NAME, sbi->ll_flags);
+}
+
+void ll_sbi_set_name_encrypt(struct ll_sb_info *sbi, bool set)
+{
+ if (set)
+ set_bit(LL_SBI_ENCRYPT_NAME, sbi->ll_flags);
+ else
+ clear_bit(LL_SBI_ENCRYPT_NAME, sbi->ll_flags);
+}
+
static bool ll_empty_dir(struct inode *inode)
{
/* used by llcrypt_ioctl_set_policy(), because a policy can only be set
return true;
}
-/**
- * ll_setup_filename() - overlay to llcrypt_setup_filename
- * @dir: the directory that will be searched
- * @iname: the user-provided filename being searched for
- * @lookup: 1 if we're allowed to proceed without the key because it's
- * ->lookup() or we're finding the dir_entry for deletion; 0 if we cannot
- * proceed without the key because we're going to create the dir_entry.
- * @fname: the filename information to be filled in
- * @fid: fid retrieved from user-provided filename
- *
- * This overlay function is necessary to properly encode @fname after
- * encryption, as it will be sent over the wire.
- * This overlay function is also necessary to handle the case of operations
- * carried out without the key. Normally llcrypt makes use of digested names in
- * that case. Having a digested name works for local file systems that can call
- * llcrypt_match_name(), but Lustre server side is not aware of encryption.
- * So for keyless @lookup operations on long names, for Lustre we choose to
- * present to users the encoded struct ll_digest_filename, instead of a digested
- * name. FID and name hash can then easily be extracted and put into the
- * requests sent to servers.
- */
-int ll_setup_filename(struct inode *dir, const struct qstr *iname,
- int lookup, struct llcrypt_name *fname,
- struct lu_fid *fid)
+static int ll_digest_long_name(struct inode *dir, struct llcrypt_name *fname,
+ struct lu_fid *fid, int digested)
{
- int digested = 0;
- struct qstr dname;
- int rc;
-
- if (fid && IS_ENCRYPTED(dir) && !llcrypt_has_encryption_key(dir) &&
- iname->name[0] == '_')
- digested = 1;
-
- dname.name = iname->name + digested;
- dname.len = iname->len - digested;
-
- if (fid) {
- fid->f_seq = 0;
- fid->f_oid = 0;
- fid->f_ver = 0;
- }
- rc = llcrypt_setup_filename(dir, &dname, lookup, fname);
- if (rc == -ENOENT && lookup &&
- ((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;
- }
- if (rc)
- return rc;
+ int rc = 0;
if (digested) {
/* Without the key, for long names user should have struct
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,
fname->disk_name.name = fname->crypto_buf.name;
fname->disk_name.len = fname->crypto_buf.len;
}
+out_free:
+ if (rc < 0)
+ llcrypt_free_filename(fname);
return rc;
+}
-out_free:
- llcrypt_free_filename(fname);
- return rc;
+/**
+ * ll_prepare_lookup() - overlay to llcrypt_prepare_lookup
+ * @dir: the directory that will be searched
+ * @de: the dentry contain the user-provided filename being searched for
+ * @fname: the filename information to be filled in
+ * @fid: fid retrieved from user-provided filename
+ *
+ * This overlay function is necessary to properly encode @fname after
+ * encryption, as it will be sent over the wire.
+ * This overlay function is also necessary to handle the case of operations
+ * carried out without the key. Normally llcrypt makes use of digested names in
+ * that case. Having a digested name works for local file systems that can call
+ * llcrypt_match_name(), but Lustre server side is not aware of encryption.
+ * FID and name hash can then easily be extracted and put into the
+ * requests sent to servers.
+ */
+int ll_prepare_lookup(struct inode *dir, struct dentry *de,
+ struct llcrypt_name *fname, struct lu_fid *fid)
+{
+ struct qstr iname = QSTR_INIT(de->d_name.name, de->d_name.len);
+ int digested = 0;
+ int rc;
+
+ if (fid && IS_ENCRYPTED(dir) && llcrypt_policy_has_filename_enc(dir) &&
+ !llcrypt_has_encryption_key(dir)) {
+ struct lustre_sb_info *lsi = s2lsi(dir->i_sb);
+
+ if ((!(lsi->lsi_flags & LSI_FILENAME_ENC_B64_OLD_CLI) &&
+ iname.name[0] == LLCRYPT_DIGESTED_CHAR) ||
+ ((lsi->lsi_flags & LSI_FILENAME_ENC_B64_OLD_CLI) &&
+ iname.name[0] == LLCRYPT_DIGESTED_CHAR_OLD))
+ digested = 1;
+ }
+
+ iname.name += digested;
+ iname.len -= digested;
+
+ if (fid) {
+ fid->f_seq = 0;
+ fid->f_oid = 0;
+ fid->f_ver = 0;
+ }
+ if (unlikely(filename_is_volatile(iname.name,
+ iname.len, NULL))) {
+ /* keep volatile name as-is, matters for server side */
+ memset(fname, 0, sizeof(struct llcrypt_name));
+ fname->disk_name.name = (unsigned char *)iname.name;
+ fname->disk_name.len = iname.len;
+ rc = 0;
+ } else {
+ /* We should use ll_prepare_lookup() but Lustre handles the
+ * digested form its own way, incompatible with llcrypt's
+ * digested form.
+ */
+ rc = llcrypt_setup_filename(dir, &iname, 1, fname);
+ if ((rc == 0 || rc == -ENOENT) &&
+#if defined(HAVE_FSCRYPT_NOKEY_NAME) && !defined(CONFIG_LL_ENCRYPTION)
+ fname->is_nokey_name) {
+#else
+ fname->is_ciphertext_name) {
+#endif
+ spin_lock(&de->d_lock);
+ de->d_flags |= DCACHE_NOKEY_NAME;
+ spin_unlock(&de->d_lock);
+ }
+ }
+ if (rc == -ENOENT) {
+ 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;
+
+ return ll_digest_long_name(dir, fname, fid, digested);
+}
+
+/**
+ * ll_setup_filename() - overlay to llcrypt_setup_filename
+ * @dir: the directory that will be searched
+ * @iname: the user-provided filename being searched for
+ * @lookup: 1 if we're allowed to proceed without the key because it's
+ * ->lookup() or we're finding the dir_entry for deletion; 0 if we cannot
+ * proceed without the key because we're going to create the dir_entry.
+ * @fname: the filename information to be filled in
+ * @fid: fid retrieved from user-provided filename
+ *
+ * This overlay function is necessary to properly encode @fname after
+ * encryption, as it will be sent over the wire.
+ * This overlay function is also necessary to handle the case of operations
+ * carried out without the key. Normally llcrypt makes use of digested names in
+ * that case. Having a digested name works for local file systems that can call
+ * llcrypt_match_name(), but Lustre server side is not aware of encryption.
+ * So for keyless @lookup operations on long names, for Lustre we choose to
+ * present to users the encoded struct ll_digest_filename, instead of a digested
+ * name. FID and name hash can then easily be extracted and put into the
+ * requests sent to servers.
+ */
+int ll_setup_filename(struct inode *dir, const struct qstr *iname,
+ int lookup, struct llcrypt_name *fname,
+ struct lu_fid *fid)
+{
+ int digested = 0;
+ struct qstr dname;
+ int rc;
+
+ if (fid && IS_ENCRYPTED(dir) && llcrypt_policy_has_filename_enc(dir) &&
+ !llcrypt_has_encryption_key(dir)) {
+ struct lustre_sb_info *lsi = s2lsi(dir->i_sb);
+
+ if ((!(lsi->lsi_flags & LSI_FILENAME_ENC_B64_OLD_CLI) &&
+ iname->name[0] == LLCRYPT_DIGESTED_CHAR) ||
+ ((lsi->lsi_flags & LSI_FILENAME_ENC_B64_OLD_CLI) &&
+ iname->name[0] == LLCRYPT_DIGESTED_CHAR_OLD))
+ digested = 1;
+ }
+
+ dname.name = iname->name + digested;
+ dname.len = iname->len - digested;
+
+ if (fid) {
+ fid->f_seq = 0;
+ fid->f_oid = 0;
+ fid->f_ver = 0;
+ }
+ if (unlikely(filename_is_volatile(iname->name,
+ iname->len, NULL))) {
+ /* keep volatile name as-is, matters for server side */
+ memset(fname, 0, sizeof(struct llcrypt_name));
+ fname->disk_name.name = (unsigned char *)iname->name;
+ fname->disk_name.len = iname->len;
+ rc = 0;
+ } else {
+ 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;
+
+ return ll_digest_long_name(dir, fname, fid, digested);
}
/**
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) &&
llcrypt_policy_has_filename_enc(inode)) {
+ struct lustre_sb_info *lsi = s2lsi(inode->i_sb);
+
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);
- oname->name[0] = '_';
+ if (!(lsi->lsi_flags & LSI_FILENAME_ENC_B64_OLD_CLI))
+ oname->name[0] = LLCRYPT_DIGESTED_CHAR;
+ else
+ oname->name[0] = LLCRYPT_DIGESTED_CHAR_OLD;
oname->name = oname->name + 1;
oname->len--;
}
return rc;
}
+#if !defined(HAVE_FSCRYPT_D_REVALIDATE) || defined(CONFIG_LL_ENCRYPTION)
/* Copied from llcrypt_d_revalidate, as it is not exported */
/*
* Validate dentries in encrypted directories to make sure we aren't potentially
* caching stale dentries after a key has been added.
*/
-int ll_revalidate_d_crypto(struct dentry *dentry, unsigned int flags)
+int llcrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
{
struct dentry *dir;
int err;
* 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;
/*
return -ECHILD;
dir = dget_parent(dentry);
- err = llcrypt_get_encryption_info(d_inode(dir));
+ err = llcrypt_prepare_readdir(d_inode(dir));
valid = !llcrypt_has_encryption_key(d_inode(dir));
dput(dir);
return valid;
}
+#endif /* !HAVE_FSCRYPT_D_REVALIDATE || CONFIG_LL_ENCRYPTION */
const struct llcrypt_operations lustre_cryptops = {
.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
+#ifdef HAVE_FSCRYPT_DUMMY_POLICY
+ .get_dummy_policy = ll_get_dummy_policy,
+#else
+ .get_dummy_context = ll_get_dummy_policy,
+#endif
+#endif /* !HAVE_FSCRYPT_DUMMY_CONTEXT_ENABLED */
.empty_dir = ll_empty_dir,
.max_namelen = NAME_MAX,
};
{
}
-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;
}
{
}
+bool ll_sbi_has_name_encrypt(struct ll_sb_info *sbi)
+{
+ return false;
+}
+
+void ll_sbi_set_name_encrypt(struct ll_sb_info *sbi, bool set)
+{
+}
+
+int ll_prepare_lookup(struct inode *dir, struct dentry *de,
+ struct llcrypt_name *fname, struct lu_fid *fid)
+{
+ const struct qstr *iname = &de->d_name;
+
+ if (fid) {
+ fid->f_seq = 0;
+ fid->f_oid = 0;
+ fid->f_ver = 0;
+ }
+
+ return llcrypt_setup_filename(dir, iname, 1, fname);
+}
+
int ll_setup_filename(struct inode *dir, const struct qstr *iname,
int lookup, struct llcrypt_name *fname,
struct lu_fid *fid)
return llcrypt_fname_disk_to_usr(inode, hash, minor_hash, iname, oname);
}
-int ll_revalidate_d_crypto(struct dentry *dentry, unsigned int flags)
+int llcrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
{
return 1;
}