Whamcloud - gitweb
LU-15855 enc: enc-unaware clients get ENOKEY if file not found
[fs/lustre-release.git] / lustre / llite / crypto.c
index 7a073c9..acd7f16 100644 (file)
 
 static int ll_get_context(struct inode *inode, void *ctx, size_t len)
 {
-       struct dentry *dentry = d_find_any_alias(inode);
-       struct lu_env *env;
-       __u16 refcheck;
        int rc;
 
-       env = cl_env_get(&refcheck);
-       if (IS_ERR(env))
-               return PTR_ERR(env);
-
-       /* Set lcc_getencctx=1 to allow this thread to read
-        * LL_XATTR_NAME_ENCRYPTION_CONTEXT xattr, as requested by llcrypt.
+       /* Get enc context xattr directly instead of going through the VFS,
+        * as there is no xattr handler for "encryption.".
         */
-       ll_cl_add(inode, env, NULL, LCC_RW);
-       ll_env_info(env)->lti_io_ctx.lcc_getencctx = 1;
-
-       rc = ll_vfs_getxattr(dentry, inode, LL_XATTR_NAME_ENCRYPTION_CONTEXT,
-                            ctx, len);
-
-       ll_cl_remove(inode, env);
-       cl_env_put(env, &refcheck);
-
-       if (dentry)
-               dput(dentry);
+       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))
@@ -92,15 +76,15 @@ int ll_set_encflags(struct inode *inode, void *encctx, __u32 encctxlen,
  *   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) {
@@ -121,34 +105,83 @@ static int ll_set_context(struct inode *inode, const void *ctx, size_t len,
        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(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_context *
+ll_get_dummy_context(struct super_block *sb)
+{
+       struct lustre_sb_info *lsi = s2lsi(sb);
 
-       return sbi ? ll_sbi_has_test_dummy_encryption(sbi) : false;
+       return lsi ? lsi->lsi_dummy_enc_ctx.ctx : NULL;
 }
 
+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 test_bit(LL_SBI_ENCRYPT, sbi->ll_flags);
@@ -218,6 +251,27 @@ int ll_setup_filename(struct inode *dir, const struct qstr *iname,
                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;
 
@@ -233,14 +287,14 @@ int ll_setup_filename(struct inode *dir, const struct qstr *iname,
                        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,
@@ -324,9 +378,9 @@ int ll_fname_disk_to_usr(struct inode *inode,
                        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
@@ -337,8 +391,8 @@ int ll_fname_disk_to_usr(struct inode *inode,
                                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);
@@ -374,7 +428,7 @@ int ll_revalidate_d_crypto(struct dentry *dentry, unsigned int flags)
         * 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;
 
        /*
@@ -407,7 +461,11 @@ 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
+       .get_dummy_context      = ll_get_dummy_context,
+#endif
        .empty_dir              = ll_empty_dir,
        .max_namelen            = NAME_MAX,
 };
@@ -418,11 +476,16 @@ int ll_set_encflags(struct inode *inode, void *encctx, __u32 encctxlen,
        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;
 }