Actions
Tasks #70194
closedTasks #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
% Done:
0%
Reviewed:
Affected Versions:
Component(FS):
Labels (FS):
Pull request ID:
Tags (freeform):
Merge Commit:
Fixed In:
Released In:
Upkeep Timestamp:
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