Project

General

Profile

Actions

Tasks #70194

closed

Tasks #63293: Implement fscrypt in libcephfs and cephfs-fuse

Tasks #69975: Sepia Lab Test Runs

Tasks #70192: choffman-2025-02-25_14:26:50-fs:fscrypt-wip-choffman-fscrypt-distro-default-smithi

pjd fails

Added by Christopher Hoffman about 1 year ago. Updated about 1 year ago.

Status:
Resolved
Priority:
Normal
Category:
-
Target version:
-
% Done:

0%

Reviewed:
Affected Versions:
Component(FS):
Labels (FS):
Pull request ID:
Tags (freeform):
Merge Commit:
Fixed In:
Released In:
Upkeep Timestamp:

Actions #1

Updated by Christopher Hoffman about 1 year ago

  • Status changed from In Progress to Resolved

Tests are failing when symlinks are created and targets are longer than 255 in size.

Fscrypt spec states:
The maximum length of an encrypted symlink is 2 bytes shorter than the maximum length of an unencrypted symlink. For example, on an EXT4 filesystem with a 4K block size, unencrypted symlinks can be up to 4095 bytes long, while encrypted symlinks can only be up to 4093 bytes long (both lengths excluding the terminating null).

Currently, link max length is set to NAME_MAX (255). That is incorrect as it should be set to PATH_MAX.

commit e024038d3ed1333bbb3bac76798b58f90b3ccf8a (HEAD -> wip-fscrypt)
Author: Christopher Hoffman <choffman@redhat.com>
Date:   Wed Feb 26 22:24:28 2025 +0000

    client: Use PATH_MAX for max size of fscrypt enabled symlinks

    Fixes: https://tracker.ceph.com/issues/70194
    Signed-off-by: Christopher Hoffman <choffman@redhat.com>

diff --git a/src/client/FSCrypt.cc b/src/client/FSCrypt.cc
index cea679d4372..ea5344216ed 100644
--- a/src/client/FSCrypt.cc
+++ b/src/client/FSCrypt.cc
@@ -735,6 +735,16 @@ int FSCryptFNameDenc::get_encrypted_name_length(const int& plain_size) const
   return padded_size;
 }

+int FSCryptFNameDenc::get_encrypted_symlink_length(const int& plain_size) const
+{
+   int padding_size = ctx->get_filename_padding_bytes();
+   int padded_size = (plain_size + padding_size - 1) & ~ (padding_size - 1);
+   if (padded_size > PATH_MAX) {
+    padded_size = PATH_MAX;
+  }
+  return padded_size;
+}
+
 int FSCryptFNameDenc::get_encrypted_fname(const std::string& plain, std::string *encrypted, std::string *alt_name)
 {
   if (plain == "." || plain == ".." ) {
@@ -809,13 +819,13 @@ int FSCryptFNameDenc::get_decrypted_fname(const std::string& b64enc, const std::

 struct fscrypt_slink_data {
   ceph_le16 len;
-  char enc[NAME_MAX - 2];
+  char enc[PATH_MAX - 2];
 };

 int FSCryptFNameDenc::get_encrypted_symlink(const std::string& plain, std::string *encrypted)
 {
   auto plain_size = plain.size();
-  auto symlink_padded_size = get_encrypted_name_length(plain_size);
+  auto symlink_padded_size = get_encrypted_symlink_length(plain_size);

   char orig[symlink_padded_size];
   memcpy(orig, plain.c_str(), plain_size);
@@ -832,7 +842,7 @@ int FSCryptFNameDenc::get_encrypted_symlink(const std::string& plain, std::strin

   slink_data.len = r;

-  int b64_len = NAME_MAX * 2; // name.size() * 2;
+  int b64_len = PATH_MAX * 2; // name.size() * 2;
   char b64_name[b64_len]; // large enough
   int len = fscrypt_fname_armor((const char *)&slink_data, slink_data.len + sizeof(slink_data.len), b64_name, b64_len);

@@ -848,7 +858,7 @@ int FSCryptFNameDenc::get_decrypted_symlink(const std::string& b64enc, std::stri
   int len = fscrypt_fname_unarmor(b64enc.c_str(), b64enc.size(),
                                   (char *)&slink_data, sizeof(slink_data));

-  char dec_fname[NAME_MAX + 64]; /* some extra just in case */
+  char dec_fname[PATH_MAX + 64]; /* some extra just in case */

   if (slink_data.len > len) { /* should never happen */
     ldout(cct, 0) << __FILE__ << ":" << __LINE__ << ":" << __func__ << "(): ERROR: slink_data.len greater than decrypted buffer (slink_data.len=" << slink_data.len << ", len=" << len << ")" << dendl;
diff --git a/src/client/FSCrypt.h b/src/client/FSCrypt.h
index 53d3a8afa76..e49b4ac8ce6 100644
--- a/src/client/FSCrypt.h
+++ b/src/client/FSCrypt.h
@@ -283,6 +283,7 @@ public:
   int get_decrypted_symlink(const std::string& b64enc, std::string *decrypted);
 private:
   int get_encrypted_name_length(const int& plain_size) const;
+  int get_encrypted_symlink_length(const int& plain_size) const;
 };

 using FSCryptFNameDencRef = std::shared_ptr<FSCryptFNameDenc>;

Actions

Also available in: Atom PDF