]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
fscrypt: Add tests for add key, remove key, set policy.
authorChristopher Hoffman <choffman@redhat.com>
Wed, 8 Nov 2023 17:56:14 +0000 (17:56 +0000)
committerChristopher Hoffman <choffman@redhat.com>
Wed, 5 Nov 2025 13:59:33 +0000 (13:59 +0000)
Signed-off-by: Christopher Hoffman <choffman@redhat.com>
src/client/FSCrypt.cc
src/include/cephfs/libcephfs.h
src/libcephfs.cc
src/test/libcephfs/fscrypt.cc

index 2a8825dfb6b0cb6bf5eb01628e5dd7c79919f3cb..1bff1bae4dee670d189909839481f600b4fca5e4 100644 (file)
@@ -334,7 +334,7 @@ int ceph_fscrypt_key_identifier::init(const char *k, int klen) {
 
 int ceph_fscrypt_key_identifier::init(const struct fscrypt_key_specifier& k) {
   if (k.type != FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
-    return -ENOTSUP;
+    return -EINVAL;
   }
 
   return init((const char *)k.u.identifier, sizeof(k.u.identifier));
@@ -430,7 +430,7 @@ int FSCryptKeyStore::maybe_remove_user(struct fscrypt_remove_key_arg* arg, std::
     removed = true;
     users->erase(it);
   } else {
-    return -ENOKEY;
+    return -EUSERS;
   }
   ldout(cct, 10) << "maybe_add_user size is now=" << users->size() << dendl;
 
index e3f3bbd39eb9e5e8e222810893c54dcabdabd34a..a304b361be6c2dd82c4505d41d4b5319d4c27901 100644 (file)
@@ -2007,21 +2007,25 @@ int ceph_debug_get_file_caps(struct ceph_mount_info *cmount, const char *path);
  * @param key_data key data
  * @param key_len key data length
  * @param kid to hold the returned key identifier
+ * @param user user id
  * @returns zero on success, other returns a negative error code.
  */
 int ceph_add_fscrypt_key(struct ceph_mount_info *cmount,
                          const char *key_data, int key_len,
-                         struct ceph_fscrypt_key_identifier *kid);
+                        struct ceph_fscrypt_key_identifier *kid,
+                        int user);
 
 /**
  * Remove fscrypt encryption key from the in-memory key manager
  *
  * @param cmount the ceph mount handle to use.
  * @param kid pointer to the key identifier
+ * @param user user id
  * @returns zero on success, other returns a negative error code.
  */
 int ceph_remove_fscrypt_key(struct ceph_mount_info *cmount,
-                            struct fscrypt_remove_key_arg *kid);
+                            struct fscrypt_remove_key_arg *kid,
+                           int user);
 
 /**
  * Set encryption policy on a directory.
index 9a9e86f52c3939ee96a3b6f29e9da7e252713590..bcd8d18e2328b8e7f77fc97855081a3245cfe306 100644 (file)
@@ -2506,21 +2506,23 @@ extern "C" void ceph_finish_reclaim(class ceph_mount_info *cmount)
 
 extern "C" int ceph_add_fscrypt_key(struct ceph_mount_info *cmount,
                                     const char *key_data, int key_len,
-                                    struct ceph_fscrypt_key_identifier *kid)
+                                   struct ceph_fscrypt_key_identifier *kid,
+                                   int user)
 {
   if (!cmount->is_mounted())
     return -CEPHFS_ENOTCONN;
 
-  return cmount->get_client()->add_fscrypt_key(key_data, key_len, kid);
+  return cmount->get_client()->add_fscrypt_key(key_data, key_len, kid, user);
 }
 
 extern "C" int ceph_remove_fscrypt_key(struct ceph_mount_info *cmount,
-                                       struct fscrypt_remove_key_arg *kid)
+                                       struct fscrypt_remove_key_arg *kid,
+                                      int user)
 {
   if (!cmount->is_mounted())
     return -CEPHFS_ENOTCONN;
 
-  return cmount->get_client()->remove_fscrypt_key(kid);
+  return cmount->get_client()->remove_fscrypt_key(kid, user);
 }
 
 extern "C" int ceph_set_fscrypt_policy_v2(struct ceph_mount_info *cmount,
index a8a36f73ba9fad77e255d14db2992ef8b30eb81e..027e6340e20a9c5b2c5ab2818dae1d9b042b8dcf 100644 (file)
@@ -73,7 +73,7 @@ int do_fscrypt_mount(struct ceph_mount_info *cmount, const char *root)
 
   struct ceph_fscrypt_key_identifier kid;
 
-  r = ceph_add_fscrypt_key(cmount, fscrypt_key, sizeof(fscrypt_key), &kid);
+  r = ceph_add_fscrypt_key(cmount, fscrypt_key, sizeof(fscrypt_key), &kid, 0);
   if (r < 0) {
     std::clog << __func__ << "() ceph_mount add_fscrypt_key r=" << r << std::endl;
     return r;
@@ -88,6 +88,42 @@ string get_unique_dir_name()
   return string("ceph_test_libcephfs_fscrypt.") + stringify(mypid) + "." + stringify(rand());
 }
 
+void generate_remove_key_arg(ceph_fscrypt_key_identifier kid, fscrypt_remove_key_arg* arg){
+  fscrypt_key_specifier key_spec;
+  key_spec.type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
+  key_spec.__reserved = 0;
+  memcpy(key_spec.u.identifier, kid.raw, 16);
+  arg->removal_status_flags = 0;
+  arg->key_spec = key_spec;
+}
+
+int init_mount(struct ceph_mount_info** cmount){
+  int r = ceph_create(cmount, NULL);
+  if (r < 0) {
+    std::clog << __func__ << "(): ceph_create() r=" << r << std::endl;
+    return r;
+  }
+
+  r = ceph_conf_read_file(*cmount, NULL);
+  if (r < 0) {
+    std::clog << __func__ << "(): ceph_conf_read_file() r=" << r << std::endl;
+    return r;
+  }
+
+  r = ceph_conf_parse_env(*cmount, NULL);
+  if (r < 0) {
+    std::clog << __func__ << "(): ceph_parse_env() r=" << r << std::endl;
+    return r;
+  }
+
+  r = ceph_mount(*cmount, NULL);
+  if (r < 0) {
+    std::clog << __func__ << "(): ceph_mount() r=" << r << std::endl;
+    return r;
+  }
+  return 0;
+}
+
 int fscrypt_encrypt(const string& dir_path)
 {
   struct ceph_mount_info *cmount;
@@ -152,7 +188,7 @@ int fscrypt_encrypt(const string& dir_path)
 
   struct ceph_fscrypt_key_identifier kid;
 
-  r = ceph_add_fscrypt_key(cmount, fscrypt_key, sizeof(fscrypt_key), &kid);
+  r = ceph_add_fscrypt_key(cmount, fscrypt_key, sizeof(fscrypt_key), &kid, 0);
   if (r < 0) {
     std::clog << __func__ << "(): ceph_add_fscrypt_key() r=" << r << std::endl;
     return r;
@@ -219,6 +255,242 @@ out:
   return r;
 }
 
+TEST(FSCrypt, MultipleUnlockLockClaims) {
+  struct ceph_fscrypt_key_identifier kid;
+  struct ceph_fscrypt_key_identifier kid2;
+
+  struct ceph_mount_info *cmount;
+  int r = init_mount(&cmount);
+  ASSERT_EQ(0, r);
+
+  r = ceph_add_fscrypt_key(cmount, fscrypt_key, sizeof(fscrypt_key), &kid, 1091);
+  ASSERT_EQ(0, r);
+
+  r = ceph_add_fscrypt_key(cmount, fscrypt_key, sizeof(fscrypt_key), &kid2, 1299);
+  ASSERT_EQ(0, r);
+  if (r < 0) {
+    std::clog << __func__ << "() 1ceph_mount add_fscrypt_key r=" << r << std::endl;
+  }
+
+  //remove user 1 of 2, should return 0, but 0x2 status_flag
+  fscrypt_remove_key_arg arg;
+  generate_remove_key_arg(kid, &arg);
+
+  r = ceph_remove_fscrypt_key(cmount, &arg, 1299);
+  ASSERT_EQ(0, r);
+  ASSERT_EQ(2, arg.removal_status_flags);
+
+   //remove suser 2 of 2, ret 0, 0x0 status_flag
+  fscrypt_remove_key_arg arg2;
+  generate_remove_key_arg(kid2, &arg2);
+
+  r = ceph_remove_fscrypt_key(cmount, &arg2, 1091);
+  ASSERT_EQ(0, r);
+  ASSERT_EQ(0, arg2.removal_status_flags);
+ ceph_shutdown(cmount);
+}
+
+TEST(FSCrypt, UnlockKeyUserDNE) {
+  struct ceph_fscrypt_key_identifier kid;
+
+  struct ceph_mount_info *cmount;
+  int r = init_mount(&cmount);
+  ASSERT_EQ(0, r);
+
+  r = ceph_add_fscrypt_key(cmount, fscrypt_key, sizeof(fscrypt_key), &kid, 1091);
+  ASSERT_EQ(0, r);
+
+  fscrypt_remove_key_arg arg;
+  generate_remove_key_arg(kid, &arg);
+
+  r = ceph_remove_fscrypt_key(cmount, &arg, 1299);
+  ASSERT_EQ(0, r);
+  ASSERT_EQ(2, arg.removal_status_flags);
+
+  ceph_shutdown(cmount);
+}
+
+TEST(FSCrypt, UnlockKeyDNE) {
+  struct ceph_fscrypt_key_identifier kid;
+
+  struct ceph_mount_info *cmount;
+  int r = init_mount(&cmount);
+  ASSERT_EQ(0, r);
+
+  r = ceph_add_fscrypt_key(cmount, fscrypt_key, sizeof(fscrypt_key), &kid, 1299);
+  ASSERT_EQ(0, r);
+
+  fscrypt_remove_key_arg arg;
+  generate_remove_key_arg(kid, &arg);
+
+  r = ceph_remove_fscrypt_key(cmount, &arg, 1299);
+  ASSERT_EQ(0, r);
+  ASSERT_EQ(0, arg.removal_status_flags);
+
+  r = ceph_remove_fscrypt_key(cmount, &arg, 1299);
+  ASSERT_EQ(-ENOKEY, r);
+  ASSERT_EQ(0, arg.removal_status_flags);
+
+  ceph_shutdown(cmount);
+}
+
+#warning key_remove todo: 'EINVAL: invalid key specifier type, or reserved bits were set' case
+
+TEST(FSCrypt, SetPolicyEmptyDir) {
+  struct ceph_fscrypt_key_identifier kid;
+
+  struct ceph_mount_info* cmount;
+  int r = init_mount(&cmount);
+  ASSERT_EQ(0, r);
+
+  r = ceph_add_fscrypt_key(cmount, fscrypt_key, sizeof(fscrypt_key), &kid, 1299);
+  ASSERT_EQ(0, r);
+
+  fscrypt_remove_key_arg arg;
+  generate_remove_key_arg(kid, &arg);
+
+  r = ceph_remove_fscrypt_key(cmount, &arg, 1299);
+  ASSERT_EQ(0, r);
+  ASSERT_EQ(0, arg.removal_status_flags);
+
+  ceph_shutdown(cmount);
+}
+
+TEST(FSCrypt, SetPolicyNotEmptyFile) {
+  struct ceph_fscrypt_key_identifier kid;
+
+  struct ceph_mount_info* cmount;
+  int r = init_mount(&cmount);
+  ASSERT_EQ(0, r);
+
+  string dir_path = "dir1";
+  ceph_mkdir(cmount, dir_path.c_str(), 0777);
+
+  string file_path = "dir1/file1";
+  int fd = ceph_open(cmount, file_path.c_str(), O_RDWR|O_CREAT|O_TRUNC, 0600);
+  r = ceph_write(cmount, fd, fscrypt_key, sizeof(fscrypt_key), 0);
+  ceph_close(cmount, fd);
+
+  int fd2 = ceph_open(cmount, dir_path.c_str(), O_DIRECTORY, 0);
+
+  r = ceph_add_fscrypt_key(cmount, fscrypt_key, sizeof(fscrypt_key), &kid, 1299);
+
+  struct fscrypt_policy_v2 policy;
+  policy.version = 2;
+  policy.contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS;
+  policy.filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS;
+  policy.flags = FSCRYPT_POLICY_FLAGS_PAD_32;
+  memcpy(policy.master_key_identifier, kid.raw, FSCRYPT_KEY_IDENTIFIER_SIZE);
+
+  r = ceph_set_fscrypt_policy_v2(cmount, fd2, &policy);
+  ASSERT_EQ(-ENOTEMPTY, r);
+
+  fscrypt_remove_key_arg arg;
+  generate_remove_key_arg(kid, &arg);
+
+  r = ceph_remove_fscrypt_key(cmount, &arg, 1299);
+  ASSERT_EQ(0, r);
+  ASSERT_EQ(0, arg.removal_status_flags);
+
+  ceph_unlink(cmount, file_path.c_str());
+  ceph_rmdir(cmount, dir_path.c_str());
+  ceph_shutdown(cmount);
+}
+
+TEST(FSCrypt, SetPolicyNotEmptyDir) {
+  struct ceph_fscrypt_key_identifier kid;
+
+  struct ceph_mount_info* cmount;
+  int r = init_mount(&cmount);
+  ASSERT_EQ(0, r);
+
+  string dir_path = "dir1";
+  ceph_mkdir(cmount, dir_path.c_str(), 0777);
+  string dir2_path = "dir1/dir2";
+  ceph_mkdir(cmount, dir2_path.c_str(), 0777);
+
+  string file_path = "dir1/file1";
+  int fd = ceph_open(cmount, file_path.c_str(), O_RDWR|O_CREAT|O_TRUNC, 0600);
+  r = ceph_write(cmount, fd, fscrypt_key, sizeof(fscrypt_key), 0);
+  ceph_close(cmount, fd);
+
+  int fd2 = ceph_open(cmount, dir_path.c_str(), O_DIRECTORY, 0);
+
+  r = ceph_add_fscrypt_key(cmount, fscrypt_key, sizeof(fscrypt_key), &kid, 1299);
+
+  struct fscrypt_policy_v2 policy;
+  policy.version = 2;
+  policy.contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS;
+  policy.filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS;
+  policy.flags = FSCRYPT_POLICY_FLAGS_PAD_32;
+  memcpy(policy.master_key_identifier, kid.raw, FSCRYPT_KEY_IDENTIFIER_SIZE);
+
+  r = ceph_set_fscrypt_policy_v2(cmount, fd2, &policy);
+  ASSERT_EQ(-ENOTEMPTY, r);
+
+  fscrypt_remove_key_arg arg;
+  generate_remove_key_arg(kid, &arg);
+
+  r = ceph_remove_fscrypt_key(cmount, &arg, 1299);
+  ASSERT_EQ(0, r);
+  ASSERT_EQ(0, arg.removal_status_flags);
+
+  ceph_unlink(cmount, file_path.c_str());
+  ceph_rmdir(cmount, dir_path.c_str());
+  ceph_shutdown(cmount);
+}
+
+TEST(FSCrypt, SetPolicyAlreadyExistSameKey) {
+  struct ceph_fscrypt_key_identifier kid;
+
+  struct ceph_mount_info* cmount;
+  int r = init_mount(&cmount);
+  ASSERT_EQ(0, r);
+  
+  string dir_path = "dir2";
+  ceph_mkdir(cmount, dir_path.c_str(), 0777);
+
+  int fd = ceph_open(cmount, dir_path.c_str(), O_DIRECTORY, 0);
+
+  r = ceph_add_fscrypt_key(cmount, fscrypt_key, sizeof(fscrypt_key), &kid, 1299);
+
+  struct fscrypt_policy_v2 policy;
+  policy.version = 2;
+  policy.contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS;
+  policy.filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS;
+  policy.flags = FSCRYPT_POLICY_FLAGS_PAD_32;
+  memcpy(policy.master_key_identifier, kid.raw, FSCRYPT_KEY_IDENTIFIER_SIZE);
+
+  r = ceph_set_fscrypt_policy_v2(cmount, fd, &policy);
+  ASSERT_EQ(0, r);
+
+  r = ceph_set_fscrypt_policy_v2(cmount, fd, &policy);
+  ASSERT_EQ(-EEXIST, r);
+  
+  ceph_rmdir(cmount, dir_path.c_str());
+  ceph_shutdown(cmount);
+}
+
+TEST(FSCrypt, SetPolicyNonDir) {
+  //can be file, symlink, hardlink, device file etc
+  struct ceph_fscrypt_key_identifier kid;
+
+  struct ceph_mount_info* cmount;
+  int r = init_mount(&cmount);
+  ASSERT_EQ(0, r);
+
+  r = ceph_add_fscrypt_key(cmount, fscrypt_key, sizeof(fscrypt_key), &kid, 1299);
+  ASSERT_EQ(-ENOTDIR, r);
+
+  fscrypt_remove_key_arg arg;
+  generate_remove_key_arg(kid, &arg);
+
+  r = ceph_remove_fscrypt_key(cmount, &arg, 1299);
+  ASSERT_EQ(0, r);
+  ASSERT_EQ(0, arg.removal_status_flags);
+
+  ceph_shutdown(cmount);
+}
 
 int main(int argc, char **argv)
 {
@@ -233,7 +505,7 @@ int main(int argc, char **argv)
   r = rados_create(&cluster, NULL);
   if (r < 0)
     exit(1);
-  
+
   r = rados_conf_read_file(cluster, NULL);
   if (r < 0)
     exit(1);