fs/crypto/fname.c

Source file repositories/reference/linux-study-clean/fs/crypto/fname.c

File Facts

System
Linux kernel
Corpus path
fs/crypto/fname.c
Extension
.c
Size
18005 bytes
Lines
515
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

struct fscrypt_nokey_name {
	u32 dirhash[2];
	u8 bytes[149];
	u8 sha256[SHA256_DIGEST_SIZE];
}; /* 189 bytes => 252 bytes base64url-encoded, which is <= NAME_MAX (255) */

/*
 * Decoded size of max-size no-key name, i.e. a name that was abbreviated using
 * the strong hash and thus includes the 'sha256' field.  This isn't simply
 * sizeof(struct fscrypt_nokey_name), as the padding at the end isn't included.
 */
#define FSCRYPT_NOKEY_NAME_MAX	offsetofend(struct fscrypt_nokey_name, sha256)

/* Encoded size of max-size no-key name */
#define FSCRYPT_NOKEY_NAME_MAX_ENCODED \
		BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX)

static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
{
	return name_is_dot_dotdot(str->name, str->len);
}

/**
 * fscrypt_fname_encrypt() - encrypt a filename
 * @inode: inode of the parent directory (for regular filenames)
 *	   or of the symlink (for symlink targets). Key must already be
 *	   set up.
 * @iname: the filename to encrypt
 * @out: (output) the encrypted filename
 * @olen: size of the encrypted filename.  It must be at least @iname->len.
 *	  Any extra space is filled with NUL padding before encryption.
 *
 * Return: 0 on success, -errno on failure
 */
int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname,
			  u8 *out, unsigned int olen)
{
	const struct fscrypt_inode_info *ci = fscrypt_get_inode_info_raw(inode);
	struct crypto_sync_skcipher *tfm = ci->ci_enc_key.tfm;
	SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
	union fscrypt_iv iv;
	struct scatterlist sg;
	int err;

	/*
	 * Copy the filename to the output buffer for encrypting in-place and
	 * pad it with the needed number of NUL bytes.
	 */
	if (WARN_ON_ONCE(olen < iname->len))
		return -ENOBUFS;
	memcpy(out, iname->name, iname->len);
	memset(out + iname->len, 0, olen - iname->len);

	fscrypt_generate_iv(&iv, 0, ci);

	skcipher_request_set_callback(
		req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
		NULL, NULL);
	sg_init_one(&sg, out, olen);
	skcipher_request_set_crypt(req, &sg, &sg, olen, &iv);
	err = crypto_skcipher_encrypt(req);
	if (err)
		fscrypt_err(inode, "Filename encryption failed: %d", err);
	return err;
}
EXPORT_SYMBOL_GPL(fscrypt_fname_encrypt);

/**
 * fname_decrypt() - decrypt a filename
 * @inode: inode of the parent directory (for regular filenames)
 *	   or of the symlink (for symlink targets)
 * @iname: the encrypted filename to decrypt
 * @oname: (output) the decrypted filename.  The caller must have allocated
 *	   enough space for this, e.g. using fscrypt_fname_alloc_buffer().
 *
 * Return: 0 on success, -errno on failure
 */
static int fname_decrypt(const struct inode *inode,
			 const struct fscrypt_str *iname,
			 struct fscrypt_str *oname)
{
	const struct fscrypt_inode_info *ci = fscrypt_get_inode_info_raw(inode);
	struct crypto_sync_skcipher *tfm = ci->ci_enc_key.tfm;
	SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
	union fscrypt_iv iv;
	struct scatterlist src_sg, dst_sg;
	int err;

	fscrypt_generate_iv(&iv, 0, ci);

Annotation

Implementation Notes