From e8f74fb0f5c9306ee5a099133799e03e09ca8e47 Mon Sep 17 00:00:00 2001 From: Sebastien Buisson Date: Tue, 11 Aug 2020 22:36:41 +0900 Subject: [PATCH] LU-12275 sec: verify dir is empty when setting enc policy When setting an encryption policy on a directory that we want to be encrypted, make sure it is empty. Otherwise return -ENOTEMPTY from server to client doing the ioctl. Also add test to exercise the ioctl interface to get/set encryption policies on directories, thanks to the fscrypt userspace tool. And test the ability to lock an encrypted directory. Fixes: 40d91eafe257 ("LU-12275 sec: atomicity of encryption context getting/setting") Test-Parameters: testlist=sanity-sec envdefinitions=ONLY="36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 52 53 54" clientdistro=el8.1 fstype=ldiskfs mdscount=2 mdtcount=4 Test-Parameters: testlist=sanity-sec envdefinitions=ONLY="36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 52 53 54" clientdistro=el8.1 fstype=zfs mdscount=2 mdtcount=4 Signed-off-by: Sebastien Buisson Change-Id: Iabffd24800314b12908f505d7e66492be7292a16 Reviewed-on: https://review.whamcloud.com/39617 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Andreas Dilger Tested-by: Andreas Dilger Reviewed-by: Lai Siyao Reviewed-by: Oleg Drokin --- lustre/mdd/mdd_internal.h | 10 +++++-- lustre/tests/sanity-sec.sh | 75 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/lustre/mdd/mdd_internal.h b/lustre/mdd/mdd_internal.h index 9081de1..aa7016e 100644 --- a/lustre/mdd/mdd_internal.h +++ b/lustre/mdd/mdd_internal.h @@ -620,19 +620,23 @@ static inline int mdo_xattr_set(const struct lu_env *env,struct mdd_object *obj, int fl, struct thandle *handle) { struct dt_object *next = mdd_object_child(obj); - int rc; + int rc = 0; if (!mdd_object_exists(obj)) return -ENOENT; - rc = dt_xattr_set(env, next, buf, name, fl, handle); - if (rc >= 0 && strcmp(name, LL_XATTR_NAME_ENCRYPTION_CONTEXT) == 0) { + if ((strcmp(name, LL_XATTR_NAME_ENCRYPTION_CONTEXT) == 0) && + (!S_ISDIR(mdd_object_type(obj)) || + (rc = mdd_dir_is_empty(env, obj)) == 0)) { struct lu_attr la = { 0 }; la.la_valid = LA_FLAGS; la.la_flags = LUSTRE_ENCRYPT_FL; rc = dt_attr_set(env, next, &la, handle); } + if (rc >= 0) + rc = dt_xattr_set(env, next, buf, name, fl, handle); + return rc; } diff --git a/lustre/tests/sanity-sec.sh b/lustre/tests/sanity-sec.sh index b9a0e43..a866b66 100755 --- a/lustre/tests/sanity-sec.sh +++ b/lustre/tests/sanity-sec.sh @@ -3967,6 +3967,81 @@ test_53() { } run_test 53 "Mixed PAGE_SIZE clients" +test_54() { + local testdir=$DIR/$tdir/$ID0 + local testfile=$testdir/$tfile + local testfile2=$testdir/${tfile}2 + local tmpfile=$TMP/${tfile}.tmp + local resfile=$TMP/${tfile}.res + + $LCTL get_param mdc.*.import | grep -q client_encryption || + skip "client encryption not supported" + + mount.lustre --help |& grep -q "test_dummy_encryption:" || + skip "need dummy encryption support" + + which fscrypt || skip "This test needs fscrypt userspace tool" + + fscrypt setup --force --verbose || error "fscrypt global setup failed" + sed -i 's/\(.*\)policy_version\(.*\):\(.*\)\"[0-9]*\"\(.*\)/\1policy_version\2:\3"2"\4/' \ + /etc/fscrypt.conf + fscrypt setup --verbose $MOUNT || error "fscrypt setup $MOUNT failed" + mkdir -p $testdir + chown -R $ID0:$ID0 $testdir + + echo -e 'mypass\nmypass' | su - $USER0 -c "fscrypt encrypt --verbose \ + --source=custom_passphrase --name=protector $testdir" || + error "fscrypt encrypt failed" + + echo -e 'mypass\nmypass' | su - $USER0 -c "fscrypt encrypt --verbose \ + --source=custom_passphrase --name=protector2 $testdir" && + error "second fscrypt encrypt should have failed" + + mkdir -p ${testdir}2 || error "mkdir ${testdir}2 failed" + touch ${testdir}2/f || error "mkdir ${testdir}2/f failed" + cancel_lru_locks + + echo -e 'mypass\nmypass' | fscrypt encrypt --verbose \ + --source=custom_passphrase --name=protector3 ${testdir}2 && + error "fscrypt encrypt on non-empty dir should have failed" + + $RUNAS dd if=/dev/urandom of=$testfile bs=127 count=1 conv=fsync || + error "write to encrypted file $testfile failed" + cp $testfile $tmpfile + $RUNAS dd if=/dev/urandom of=$testfile2 bs=127 count=1 conv=fsync || + error "write to encrypted file $testfile2 failed" + + $RUNAS fscrypt lock --verbose $testdir || + error "fscrypt lock $testdir failed (1)" + + $RUNAS hexdump -C $testfile && + error "reading $testfile should have failed without key" + + echo mypass | $RUNAS fscrypt unlock --verbose $testdir || + error "fscrypt unlock $testdir failed (1)" + + $RUNAS cat $testfile > $resfile || + error "reading $testfile failed" + + cmp -bl $tmpfile $resfile || error "file read differs from file written" + + $RUNAS fscrypt lock --verbose $testdir || + error "fscrypt lock $testdir failed (2)" + + $RUNAS hexdump -C $testfile2 && + error "reading $testfile2 should have failed without key" + + echo mypass | $RUNAS fscrypt unlock --verbose $testdir || + error "fscrypt unlock $testdir failed (2)" + + rm -rf $testdir/* + $RUNAS fscrypt lock --verbose $testdir || + error "fscrypt lock $testdir failed (3)" + + rm -f $tmpfile $resfile +} +run_test 54 "Encryption policies with fscrypt" + log "cleanup: ======================================================" sec_unsetup() { -- 1.8.3.1