Whamcloud - gitweb
LU-15858 sec: reinstate null encryption for file names
authorSebastien Buisson <sbuisson@ddn.com>
Mon, 2 May 2022 16:00:37 +0000 (18:00 +0200)
committerOleg Drokin <green@whamcloud.com>
Fri, 27 May 2022 20:40:00 +0000 (16:40 -0400)
Reinstate null encryption for file names by adding a new llite
parameter named 'enable_filename_encryption', set to 0 by default.
When this parameter is 0, new empty directories configured as
encrypted ignore the filenames_encryption_mode and use
LLCRYPT_MODE_NULL instead, which is a no-op. This LLCRYPT_MODE_NULL
mode is inherited for all subdirectories and files.
When this parameter is 1, new empty directories configured as
encrypted use the normal encryption mode.

To set this parameter globally for all clients, do on the MGS:
mgs# lctl set_param -P llite.*.enable_filename_encryption=0

Also update sanity-sec test_54 to exercise the new parameter
'enable_filename_encryption'.

Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Change-Id: I9d726ba26cc91a51690d59a81efe3eb98ee2995c
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-on: https://review.whamcloud.com/47355
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Patrick Farrell <pfarrell@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
12 files changed:
libcfs/include/libcfs/crypto/llcrypt.h
libcfs/include/libcfs/libcfs_debug.h
libcfs/libcfs/crypto/fname.c
libcfs/libcfs/crypto/hooks.c
libcfs/libcfs/crypto/policy.c
lustre/include/lustre_disk.h
lustre/llite/crypto.c
lustre/llite/file.c
lustre/llite/llite_lib.c
lustre/llite/lproc_llite.c
lustre/llite/super25.c
lustre/tests/sanity-sec.sh

index b98e551..f1b207d 100644 (file)
@@ -753,7 +753,7 @@ static inline int llcrypt_prepare_symlink(struct inode *dir,
                                          struct llcrypt_str *disk_link)
 {
        if ((IS_ENCRYPTED(dir) &&
-            likely(llcrypt_policy_has_filename_enc(dir))) ||
+            llcrypt_policy_has_filename_enc(dir)) ||
            llcrypt_dummy_context_enabled(dir))
                return __llcrypt_prepare_symlink(dir, len, max_len, disk_link);
 
index 662d290..f7d5bd9 100644 (file)
@@ -37,6 +37,7 @@
 #ifndef __LIBCFS_DEBUG_H__
 #define __LIBCFS_DEBUG_H__
 
+#include <linux/tty.h>
 #include <linux/limits.h>
 #include <uapi/linux/lnet/libcfs_debug.h>
 
@@ -307,4 +308,21 @@ do {                                                                       \
 
 void cfs_debug_init(void);
 
+static inline void cfs_tty_write_msg(const char *msg)
+{
+       struct tty_struct *tty;
+
+       tty = get_current_tty();
+       if (!tty)
+               return;
+       mutex_lock(&tty->atomic_write_lock);
+       tty_lock(tty);
+       if (tty->ops->write && tty->count > 0)
+               tty->ops->write(tty, msg, strlen(msg));
+       tty_unlock(tty);
+       mutex_unlock(&tty->atomic_write_lock);
+       wake_up_interruptible_poll(&tty->write_wait, POLL_OUT);
+       tty_kref_put(tty);
+}
+
 #endif /* __LIBCFS_DEBUG_H__ */
index 6769930..8b16c39 100644 (file)
@@ -291,7 +291,7 @@ int llcrypt_fname_disk_to_usr(struct inode *inode,
                return fname_decrypt(inode, iname, oname);
        }
 
-       if (unlikely(!llcrypt_policy_has_filename_enc(inode))) {
+       if (!llcrypt_policy_has_filename_enc(inode)) {
                memcpy(oname->name, iname->name, iname->len);
                oname->name[iname->len] = '\0';
                oname->len = iname->len;
@@ -387,7 +387,7 @@ int llcrypt_setup_filename(struct inode *dir, const struct qstr *iname,
        if (!lookup)
                return -ENOKEY;
 
-       if (unlikely(!llcrypt_policy_has_filename_enc(dir))) {
+       if (!llcrypt_policy_has_filename_enc(dir)) {
                fname->disk_name.name = (unsigned char *)iname->name;
                fname->disk_name.len = iname->len;
                return 0;
index 4e26fb3..3639951 100644 (file)
@@ -177,7 +177,7 @@ int __llcrypt_encrypt_symlink(struct inode *inode, const char *target,
        struct llcrypt_symlink_data *sd;
        unsigned int ciphertext_len;
 
-       if (unlikely(!llcrypt_policy_has_filename_enc(inode)))
+       if (!llcrypt_policy_has_filename_enc(inode))
                return 0;
 
        err = llcrypt_require_key(inode);
@@ -269,7 +269,7 @@ const char *llcrypt_get_symlink(struct inode *inode, const void *caddr,
         * the ciphertext length, even though this is redundant with i_size.
         */
 
-       if (unlikely(!llcrypt_policy_has_filename_enc(inode))) {
+       if (!llcrypt_policy_has_filename_enc(inode)) {
                cstr.name = (unsigned char *)caddr;
                cstr.len = strlen(cstr.name);
 
index 243b412..5d094d5 100644 (file)
@@ -307,6 +307,7 @@ int llcrypt_ioctl_set_policy(struct file *filp, const void __user *arg)
        union llcrypt_policy policy;
        union llcrypt_policy existing_policy;
        struct inode *inode = file_inode(filp);
+       struct lustre_sb_info *lsi = s2lsi(inode->i_sb);
        u8 version;
        int size;
        int ret;
@@ -334,6 +335,26 @@ int llcrypt_ioctl_set_policy(struct file *filp, const void __user *arg)
                return -EFAULT;
        policy.version = version;
 
+       /* Force file/directory name encryption policy to null if
+        * LSI_FILENAME_ENC flag is not set on sb.
+        * This allows enabling filename encryption separately from data
+        * encryption, and can be useful for interoperability with
+        * encryption-unaware clients.
+        */
+       if (!(lsi->lsi_flags & LSI_FILENAME_ENC)) {
+               CWARN("inode %lu: forcing policy filenames_encryption_mode to null\n",
+                     inode->i_ino);
+               cfs_tty_write_msg("\n\nForcing policy filenames_encryption_mode to null.\n\n");
+               switch (policy.version) {
+               case LLCRYPT_POLICY_V1:
+                       policy.v1.filenames_encryption_mode = LLCRYPT_MODE_NULL;
+                       break;
+               case LLCRYPT_POLICY_V2:
+                       policy.v2.filenames_encryption_mode = LLCRYPT_MODE_NULL;
+                       break;
+               }
+       }
+
        if (!inode_owner_or_capable(&init_user_ns, inode))
                return -EACCES;
 
index b7dc9d0..1f9d88c 100644 (file)
@@ -146,6 +146,10 @@ struct lustre_sb_info {
 };
 
 #define LSI_UMOUNT_FAILOVER              0x00200000
+#ifndef HAVE_SUPER_SETUP_BDI_NAME
+#define LSI_BDI_INITIALIZED             0x00400000
+#endif
+#define LSI_FILENAME_ENC                0x00800000 /* enable name encryption */
 
 #define     s2lsi(sb)        ((struct lustre_sb_info *)((sb)->s_fs_info))
 #define     s2lsi_nocast(sb) ((sb)->s_fs_info)
index 797fa3d..74f6c13 100644 (file)
@@ -358,7 +358,7 @@ int ll_fname_disk_to_usr(struct inode *inode,
                }
                if (lltr.len > LLCRYPT_FNAME_MAX_UNDIGESTED_SIZE &&
                    !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
index 15ffe4e..c9666be 100644 (file)
@@ -4846,7 +4846,6 @@ int ll_migrate(struct inode *parent, struct file *file, struct lmv_user_md *lum,
        __u64 data_version = 0;
        size_t namelen = strlen(name);
        int lumlen = lmv_user_md_size(lum->lum_stripe_count, lum->lum_magic);
-       bool oldformat = false;
        int rc;
        ENTRY;
 
@@ -4897,20 +4896,6 @@ int ll_migrate(struct inode *parent, struct file *file, struct lmv_user_md *lum,
        if (is_root_inode(child_inode))
                GOTO(out_iput, rc = -EINVAL);
 
-       if (IS_ENCRYPTED(parent)) {
-               if (unlikely(!llcrypt_policy_has_filename_enc(parent)))
-                       oldformat = true;
-       } else if (IS_ENCRYPTED(child_inode) &&
-                  unlikely(!llcrypt_policy_has_filename_enc(child_inode))) {
-               oldformat = true;
-       }
-       if (unlikely(oldformat)) {
-               CDEBUG(D_SEC,
-                      "cannot migrate old format encrypted "DFID", please move to new enc dir first\n",
-                      PFID(ll_inode2fid(child_inode)));
-               GOTO(out_iput, rc = -EUCLEAN);
-       }
-
        op_data = ll_prep_md_op_data(NULL, parent, NULL, name, namelen,
                                     child_inode->i_mode, LUSTRE_OPC_ANY, NULL);
        if (IS_ERR(op_data))
index 3d200d7..c16b67d 100644 (file)
@@ -1194,9 +1194,6 @@ void ll_lli_init(struct ll_inode_info *lli)
 #define MAX_STRING_SIZE 128
 
 #ifndef HAVE_SUPER_SETUP_BDI_NAME
-
-#define LSI_BDI_INITIALIZED    0x00400000
-
 #ifndef HAVE_BDI_CAP_MAP_COPY
 # define BDI_CAP_MAP_COPY      0
 #endif
index 29493ab..8e972c7 100644 (file)
@@ -1591,6 +1591,39 @@ static ssize_t ll_nosquash_nids_seq_write(struct file *file,
 
 LDEBUGFS_SEQ_FOPS(ll_nosquash_nids);
 
+static int ll_filename_enc_seq_show(struct seq_file *m, void *v)
+{
+       struct super_block *sb = m->private;
+       struct lustre_sb_info *lsi = s2lsi(sb);
+
+       seq_printf(m, "%u\n", lsi->lsi_flags & LSI_FILENAME_ENC ? 1 : 0);
+       return 0;
+}
+
+static ssize_t ll_filename_enc_seq_write(struct file *file,
+                                        const char __user *buffer,
+                                        size_t count, loff_t *off)
+{
+       struct seq_file *m = file->private_data;
+       struct super_block *sb = m->private;
+       struct lustre_sb_info *lsi = s2lsi(sb);
+       bool val;
+       int rc;
+
+       rc = kstrtobool_from_user(buffer, count, &val);
+       if (rc)
+               return rc;
+
+       if (val)
+               lsi->lsi_flags |= LSI_FILENAME_ENC;
+       else
+               lsi->lsi_flags &= ~LSI_FILENAME_ENC;
+
+       return count;
+}
+
+LDEBUGFS_SEQ_FOPS(ll_filename_enc);
+
 static int ll_pcc_seq_show(struct seq_file *m, void *v)
 {
        struct super_block *sb = m->private;
@@ -1645,6 +1678,8 @@ struct ldebugfs_vars lprocfs_llite_obd_vars[] = {
          .fops =       &ll_nosquash_nids_fops                  },
        { .name =       "pcc",
          .fops =       &ll_pcc_fops,                           },
+       { .name =       "enable_filename_encryption",
+         .fops =       &ll_filename_enc_fops,                  },
        { NULL }
 };
 
index c9deb45..bf4d3ea 100644 (file)
@@ -157,6 +157,8 @@ static int lustre_fill_super(struct super_block *sb, void *lmd2_data,
        }
 
        CDEBUG(D_MOUNT, "Mounting client %s\n", lmd->lmd_profile);
+       /* filename encryption is disabled by default */
+       lsi->lsi_flags &= ~LSI_FILENAME_ENC;
        rc = lustre_start_mgc(sb);
        if (rc) {
                lustre_common_put_super(sb);
index 9bf0284..5740bda 100755 (executable)
@@ -4269,6 +4269,7 @@ test_54() {
        local testfile2=$testdir/${tfile}withveryverylongnametoexercisecode
        local tmpfile=$TMP/${tfile}.tmp
        local resfile=$TMP/${tfile}.res
+       local nameenc
        local fid1
        local fid2
 
@@ -4318,6 +4319,18 @@ test_54() {
        local filecount=$($RUNAS find $testdir -type f | wc -l)
        [ $filecount -eq 3 ] || error "found $filecount files"
 
+       # check enable_filename_encryption default value
+       nameenc=$(lctl get_param -n llite.*.enable_filename_encryption |
+                       head -n1)
+       [ $nameenc -eq 0 ] ||
+               error "enable_filename_encryption should be 0 by default"
+
+       # $testfile and $testfile2 should exist because names are not encrypted
+       [ -f $testfile ] ||
+               error "$testfile should exist because name is not encrypted"
+       [ -f $testfile2 ] ||
+               error "$testfile should exist because name is not encrypted"
+
        scrambledfiles=( $(find $testdir/ -maxdepth 1 -type f) )
        $RUNAS hexdump -C ${scrambledfiles[0]} &&
                error "reading ${scrambledfiles[0]} should fail without key"
@@ -4391,6 +4404,16 @@ test_54() {
        fid1=$(path2fid $MOUNT/.fscrypt)
        echo "With FILESET $tdir, .fscrypt FID is $fid1"
 
+       # enable name encryption
+       do_facet mgs $LCTL set_param -P llite.*.enable_filename_encryption=1
+       [ $? -eq 0 ] ||
+               error "set_param -P llite.*.enable_filename_encryption failed"
+
+       wait_update_facet --verbose client \
+           "$LCTL get_param -n llite.*.enable_filename_encryption | head -n1" \
+           1 30 ||
+               error "enable_filename_encryption not set on client"
+
        # encrypt 'vault' dir inside the subdir mount
        echo -e 'mypass\nmypass' | su - $USER0 -c "fscrypt encrypt --verbose \
                --source=custom_passphrase --name=protector $testdir" ||
@@ -4403,6 +4426,11 @@ test_54() {
        $RUNAS fscrypt lock --verbose $testdir ||
                error "fscrypt lock $testdir failed (4)"
 
+       # encfile should actually have its name encrypted
+       [ -f $testdir/encfile ] && error "encfile name should be encrypted"
+       filecount=$(find $testdir -type f | wc -l)
+       [ $filecount -eq 1 ] || error "found $filecount files instead of 1"
+
        # remount client with encrypted dir as subdirectory mount
        umount_client $MOUNT || error "umount $MOUNT failed (2)"
        export FILESET=/$tdir/vault
@@ -4441,6 +4469,16 @@ test_54() {
        $RUNAS fscrypt lock --verbose $DIR/$tdir/vault ||
                error "fscrypt lock $DIR/$tdir/vault failed (5)"
 
+       # disable name encryption
+       do_facet mgs $LCTL set_param -P llite.*.enable_filename_encryption=0
+       [ $? -eq 0 ] ||
+               error "set_param -P llite.*.enable_filename_encryption failed"
+
+       wait_update_facet --verbose client \
+           "$LCTL get_param -n llite.*.enable_filename_encryption | head -n1" \
+           0 30 ||
+               error "enable_filename_encryption not set back to default"
+
        rm -rf $tmpfile $MOUNT/.fscrypt
 }
 run_test 54 "Encryption policies with fscrypt"