Whamcloud - gitweb
LU-13717 sec: fix handling of encrypted file with long name 63/45163/3
authorSebastien Buisson <sbuisson@ddn.com>
Tue, 5 Oct 2021 14:51:52 +0000 (16:51 +0200)
committerOleg Drokin <green@whamcloud.com>
Thu, 23 Dec 2021 07:18:30 +0000 (07:18 +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.

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-on: https://review.whamcloud.com/45163
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
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>
lustre/llite/llite_lib.c
lustre/mdd/mdd_dir.c
lustre/tests/sanity-sec.sh

index d5c3c94..e818e1e 100644 (file)
@@ -3221,7 +3221,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 fcad947..03b308d 100644 (file)
@@ -1717,7 +1717,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;
@@ -1776,6 +1776,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)
@@ -1850,6 +1860,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 0f38097..579a30b 100755 (executable)
@@ -3374,6 +3374,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
@@ -3396,6 +3401,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
@@ -3406,6 +3419,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)