Whamcloud - gitweb
LU-13717 sec: fix handling of encrypted file with long name
authorSebastien Buisson <sbuisson@ddn.com>
Tue, 5 Oct 2021 14:51:52 +0000 (16:51 +0200)
committerAndreas Dilger <adilger@whamcloud.com>
Thu, 31 Mar 2022 04:30:55 +0000 (04:30 +0000)
The ciphertext representation of the name of an encrypted file or
directory can be up to 256 bytes of binary data, if the cleartext
name is up to NAME_MAX. But then this ciphertext is encoded via
critical_encode() before being sent to servers. Once encoded, the
length can exceed NAME_MAX because of the escaped critical
characters.
So make sure ll_prep_md_op_data() accepts those too long encoded names
if it is called for lookup or create of an encrypted file or
directory. In the other cases, the 'name' taken as input is the plain
text version, so it must conform to the NAME_MAX limit.

When carrying out operations on an encrypted file with long name, we
manipulate a digested form whose hash needs to be matched against the
content of the LinkEA. The name found in the LinkEA is not NUL
terminated, so this aspect must be taken care of.

Lustre-change: https://review.whamcloud.com/45163
Lustre-commit: 75414af6bf310244d38284958ecf037d61936726

Fixes: 4d38566a00 ("LU-13717 sec: filename encryption")
Fixes: ed4a625d88 ("LU-13717 sec: filename encryption - digest support")
Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Change-Id: I4b0e51eee5e549ab56292fe0fec3c1be1b487fc7
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Patrick Farrell <pfarrell@whamcloud.com>
Reviewed-on: https://review.whamcloud.com/46887
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
lustre/llite/llite_lib.c
lustre/mdd/mdd_dir.c
lustre/tests/sanity-sec.sh

index 638b22d..1924914 100644 (file)
@@ -3140,7 +3140,9 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data,
                if (namelen != 0)
                        return ERR_PTR(-EINVAL);
        } else {
-               if (namelen > ll_i2sbi(i1)->ll_namelen)
+               if ((!IS_ENCRYPTED(i1) ||
+                    (opc != LUSTRE_OPC_LOOKUP && opc != LUSTRE_OPC_CREATE)) &&
+                   namelen > ll_i2sbi(i1)->ll_namelen)
                        return ERR_PTR(-ENAMETOOLONG);
 
                /* "/" is not valid name, but it's allowed */
index 26abde1..f6f83e9 100644 (file)
@@ -1718,7 +1718,7 @@ static int mdd_unlink(const struct lu_env *env, struct md_object *pobj,
                      struct md_object *cobj, const struct lu_name *lname,
                      struct md_attr *ma, int no_name)
 {
-       const char *name = lname->ln_name;
+       char *name = (char *)lname->ln_name;
        struct lu_attr *pattr = MDD_ENV_VAR(env, pattr);
        struct lu_attr *cattr = MDD_ENV_VAR(env, cattr);
        struct lu_attr *la = &mdd_env_info(env)->mdi_la_for_fix;
@@ -1777,6 +1777,16 @@ static int mdd_unlink(const struct lu_env *env, struct md_object *pobj,
        if (likely(mdd_cobj != NULL))
                mdd_write_lock(env, mdd_cobj, DT_TGT_CHILD);
 
+       if (lname->ln_name[lname->ln_namelen] != '\0') {
+               /* lname->ln_name is not necessarily NUL terminated */
+               name = kmalloc(lname->ln_namelen + 1, GFP_NOFS);
+               if (!name)
+                       GOTO(cleanup, rc = -ENOMEM);
+
+               memcpy(name, lname->ln_name, lname->ln_namelen);
+               name[lname->ln_namelen] = '\0';
+       }
+
        if (likely(no_name == 0) && !OBD_FAIL_CHECK(OBD_FAIL_LFSCK_DANGLING2)) {
                rc = __mdd_index_delete(env, mdd_pobj, name, is_dir, handle);
                if (rc)
@@ -1851,6 +1861,9 @@ static int mdd_unlink(const struct lu_env *env, struct md_object *pobj,
 
        EXIT;
 cleanup:
+       if (name != lname->ln_name)
+               kfree(name);
+
        if (likely(mdd_cobj != NULL))
                mdd_write_unlock(env, mdd_cobj);
 
index f9e4898..cd001ab 100755 (executable)
@@ -3426,6 +3426,11 @@ test_46() {
        local testfile=$testdir/myfile
        local testdir2=$DIR/$tdir/mydirwithaveryverylongnametotestcodebehaviour0
        local testfile2=$testdir/myfilewithaveryverylongnametotestcodebehaviour0
+       # testdir3, testfile3, testhl3 and testsl3 names are 255 bytes long
+       local testdir3=$testdir2/dir_abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz012345678
+       local testfile3=$testdir2/file_abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz01234567
+       local testhl3=$testdir2/hl_abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789
+       local testsl3=$testdir2/sl_abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789
        local lsfile=$TMP/lsfile
        local scrambleddir
        local scrambledfile
@@ -3448,6 +3453,14 @@ test_46() {
        else
                mkdir $testdir2
        fi
+       if [ "$mds1_FSTYPE" = ldiskfs ]; then
+               # For now, restrict this part of the test to ldiskfs backend,
+               # as osd-zfs does not support 255 byte-long encrypted names.
+               mkdir $testdir3 || error "cannot mkdir $testdir3"
+               touch $testfile3 || error "cannot touch $testfile3"
+               ln $testfile3 $testhl3 || error "cannot ln $testhl3"
+               ln -s $testfile3 $testsl3 || error "cannot ln $testsl3"
+       fi
        sync ; echo 3 > /proc/sys/vm/drop_caches
 
        # remove fscrypt key from keyring
@@ -3458,6 +3471,10 @@ test_46() {
        # this is $testdir2
        scrambleddir=$(find $DIR/$tdir/ -maxdepth 1 -mindepth 1 -type d| grep _)
        stat $scrambleddir || error "stat $scrambleddir failed"
+       if [ "$mds1_FSTYPE" = ldiskfs ]; then
+               stat $scrambleddir/* || error "cannot stat in $scrambleddir"
+               rm -rf $scrambleddir/* || error "cannot clean in $scrambleddir"
+       fi
        rmdir $scrambleddir || error "rmdir $scrambleddir failed"
 
        scrambleddir=$(find $DIR/$tdir/ -maxdepth 1 -mindepth 1 -type d)