Re: [RFC PATCH v7 15/24] ceph: add encrypted fname handling to ceph_mdsc_build_path

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Jun 25, 2021 at 09:58:25AM -0400, Jeff Layton wrote:
> +/*
> + * We want to encrypt filenames when creating them, but the encrypted
> + * versions of those names may have illegal characters in them. To mitigate
> + * that, we base64 encode them, but that gives us a result that can exceed
> + * NAME_MAX.
> + *
> + * Follow a similar scheme to fscrypt itself, and cap the filename to a
> + * smaller size. If the cleartext name is longer than the value below, then
> + * sha256 hash the remaining bytes.
> + *
> + * 189 bytes => 252 bytes base64-encoded, which is <= NAME_MAX (255)
> + */
> +#define CEPH_NOHASH_NAME_MAX (189 - SHA256_DIGEST_SIZE)

Shouldn't this say "If the ciphertext name is longer than the value below", not
"If the cleartext name is longer than the value below"?

It would also be helpful if the above comment mentioned that when the hashing is
done, the real encrypted name is stored separately.

> +#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
> +static int encode_encrypted_fname(const struct inode *parent, struct dentry *dentry, char *buf)
> +{
> +	u32 len;
> +	int elen;
> +	int ret;
> +	u8 *cryptbuf;
> +
> +	WARN_ON_ONCE(!fscrypt_has_encryption_key(parent));
> +
> +	/*
> +	 * convert cleartext dentry name to ciphertext
> +	 * if result is longer than CEPH_NOKEY_NAME_MAX,
> +	 * sha256 the remaining bytes
> +	 *
> +	 * See: fscrypt_setup_filename
> +	 */
> +	if (!fscrypt_fname_encrypted_size(parent, dentry->d_name.len, NAME_MAX, &len))
> +		return -ENAMETOOLONG;
> +
> +	/* If we have to hash the end, then we need a full-length buffer */
> +	if (len > CEPH_NOHASH_NAME_MAX)
> +		len = NAME_MAX;
> +
> +	cryptbuf = kmalloc(len, GFP_KERNEL);
> +	if (!cryptbuf)
> +		return -ENOMEM;
> +
> +	ret = fscrypt_fname_encrypt(parent, &dentry->d_name, cryptbuf, len);
> +	if (ret) {
> +		kfree(cryptbuf);
> +		return ret;
> +	}
> +
> +	/* hash the end if the name is long enough */
> +	if (len > CEPH_NOHASH_NAME_MAX) {
> +		u8 hash[SHA256_DIGEST_SIZE];
> +		u8 *extra = cryptbuf + CEPH_NOHASH_NAME_MAX;
> +
> +		/* hash the extra bytes and overwrite crypttext beyond that point with it */
> +		sha256(extra, len - CEPH_NOHASH_NAME_MAX, hash);
> +		memcpy(extra, hash, SHA256_DIGEST_SIZE);
> +		len = CEPH_NOHASH_NAME_MAX + SHA256_DIGEST_SIZE;
> +	}

When the ciphertext name is longer than CEPH_NOHASH_NAME_MAX, why is the
filename being padded all the way to NAME_MAX?  That can produce a totally
different ciphertext from that produced by get_fscrypt_altname() in the next
patch.

The logical thing to do would be to do the encryption in the same way as
get_fscrypt_altname(), and then replace any bytes beyond CEPH_NOHASH_NAME_MAX
with their hash.

> +
> +	/* base64 encode the encrypted name */
> +	elen = fscrypt_base64_encode(cryptbuf, len, buf);
> +	kfree(cryptbuf);
> +	dout("base64-encoded ciphertext name = %.*s\n", len, buf);
> +	return elen;

The argument to dout() should be elen, not len.

- Eric



[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux