Commit cd358208 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'fscrypt-for-linus' of git://git.kernel.org/pub/scm/fs/fscrypt/fscrypt

Pull fscrypt updates from Eric Biggers:
 "Some small fixes and cleanups for fs/crypto/:

   - Fix ->getattr() for ext4, f2fs, and ubifs to report the correct
     st_size for encrypted symlinks

   - Use base64url instead of a custom Base64 variant

   - Document struct fscrypt_operations"

* tag 'fscrypt-for-linus' of git://git.kernel.org/pub/scm/fs/fscrypt/fscrypt:
  fscrypt: document struct fscrypt_operations
  fscrypt: align Base64 encoding with RFC 4648 base64url
  fscrypt: remove mention of symlink st_size quirk from documentation
  ubifs: report correct st_size for encrypted symlinks
  f2fs: report correct st_size for encrypted symlinks
  ext4: report correct st_size for encrypted symlinks
  fscrypt: add fscrypt_symlink_getattr() for computing st_size
parents 87045e65 38ef66b0
......@@ -1063,11 +1063,6 @@ astute users may notice some differences in behavior:
- DAX (Direct Access) is not supported on encrypted files.
- The st_size of an encrypted symlink will not necessarily give the
length of the symlink target as required by POSIX. It will actually
give the length of the ciphertext, which will be slightly longer
than the plaintext due to NUL-padding and an extra 2-byte overhead.
- 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
......@@ -1235,12 +1230,12 @@ the user-supplied name to get the ciphertext.
Lookups without the key are more complicated. The raw ciphertext may
contain the ``\0`` and ``/`` characters, which are illegal in
filenames. Therefore, readdir() must base64-encode the ciphertext for
presentation. For most filenames, this works fine; on ->lookup(), the
filesystem just base64-decodes the user-supplied name to get back to
the raw ciphertext.
filenames. Therefore, readdir() must base64url-encode the ciphertext
for presentation. For most filenames, this works fine; on ->lookup(),
the filesystem just base64url-decodes the user-supplied name to get
back to the raw ciphertext.
However, for very long filenames, base64 encoding would cause the
However, for very long filenames, base64url encoding would cause the
filename length to exceed NAME_MAX. To prevent this, readdir()
actually presents long filenames in an abbreviated form which encodes
a strong "hash" of the ciphertext filename, along with the optional
......
......@@ -26,7 +26,7 @@
* it to find the directory entry again if requested. Naively, that would just
* mean using the ciphertext filenames. However, since the ciphertext filenames
* can contain illegal characters ('\0' and '/'), they must be encoded in some
* way. We use base64. But that can cause names to exceed NAME_MAX (255
* way. We use base64url. But that can cause names to exceed NAME_MAX (255
* bytes), so we also need to use a strong hash to abbreviate long names.
*
* The filesystem may also need another kind of hash, the "dirhash", to quickly
......@@ -38,7 +38,7 @@
* casefolded directories use this type of dirhash. At least in these cases,
* each no-key name must include the name's dirhash too.
*
* To meet all these requirements, we base64-encode the following
* To meet all these requirements, we base64url-encode the following
* variable-length structure. It contains the dirhash, or 0's if the filesystem
* didn't provide one; up to 149 bytes of the ciphertext name; and for
* ciphertexts longer than 149 bytes, also the SHA-256 of the remaining bytes.
......@@ -52,15 +52,19 @@ struct fscrypt_nokey_name {
u32 dirhash[2];
u8 bytes[149];
u8 sha256[SHA256_DIGEST_SIZE];
}; /* 189 bytes => 252 bytes base64-encoded, which is <= NAME_MAX (255) */
}; /* 189 bytes => 252 bytes base64url-encoded, which is <= NAME_MAX (255) */
/*
* Decoded size of max-size nokey name, i.e. a name that was abbreviated using
* 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 \
FSCRYPT_BASE64URL_CHARS(FSCRYPT_NOKEY_NAME_MAX)
static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
{
if (str->len == 1 && str->name[0] == '.')
......@@ -175,62 +179,82 @@ static int fname_decrypt(const struct inode *inode,
return 0;
}
static const char lookup_table[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
static const char base64url_table[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
#define BASE64_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3)
#define FSCRYPT_BASE64URL_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3)
/**
* base64_encode() - base64-encode some bytes
* @src: the bytes to encode
* @len: number of bytes to encode
* @dst: (output) the base64-encoded string. Not NUL-terminated.
* fscrypt_base64url_encode() - base64url-encode some binary data
* @src: the binary data to encode
* @srclen: the length of @src in bytes
* @dst: (output) the base64url-encoded string. Not NUL-terminated.
*
* Encodes the input string using characters from the set [A-Za-z0-9+,].
* The encoded string is roughly 4/3 times the size of the input string.
* Encodes data using base64url encoding, i.e. the "Base 64 Encoding with URL
* and Filename Safe Alphabet" specified by RFC 4648. '='-padding isn't used,
* as it's unneeded and not required by the RFC. base64url is used instead of
* base64 to avoid the '/' character, which isn't allowed in filenames.
*
* Return: length of the encoded string
* Return: the length of the resulting base64url-encoded string in bytes.
* This will be equal to FSCRYPT_BASE64URL_CHARS(srclen).
*/
static int base64_encode(const u8 *src, int len, char *dst)
static int fscrypt_base64url_encode(const u8 *src, int srclen, char *dst)
{
int i, bits = 0, ac = 0;
u32 ac = 0;
int bits = 0;
int i;
char *cp = dst;
for (i = 0; i < len; i++) {
ac += src[i] << bits;
for (i = 0; i < srclen; i++) {
ac = (ac << 8) | src[i];
bits += 8;
do {
*cp++ = lookup_table[ac & 0x3f];
ac >>= 6;
bits -= 6;
*cp++ = base64url_table[(ac >> bits) & 0x3f];
} while (bits >= 6);
}
if (bits)
*cp++ = lookup_table[ac & 0x3f];
*cp++ = base64url_table[(ac << (6 - bits)) & 0x3f];
return cp - dst;
}
static int base64_decode(const char *src, int len, u8 *dst)
/**
* fscrypt_base64url_decode() - base64url-decode a string
* @src: the string to decode. Doesn't need to be NUL-terminated.
* @srclen: the length of @src in bytes
* @dst: (output) the decoded binary data
*
* Decodes a string using base64url encoding, i.e. the "Base 64 Encoding with
* URL and Filename Safe Alphabet" specified by RFC 4648. '='-padding isn't
* accepted, nor are non-encoding characters such as whitespace.
*
* This implementation hasn't been optimized for performance.
*
* Return: the length of the resulting decoded binary data in bytes,
* or -1 if the string isn't a valid base64url string.
*/
static int fscrypt_base64url_decode(const char *src, int srclen, u8 *dst)
{
int i, bits = 0, ac = 0;
const char *p;
u8 *cp = dst;
u32 ac = 0;
int bits = 0;
int i;
u8 *bp = dst;
for (i = 0; i < srclen; i++) {
const char *p = strchr(base64url_table, src[i]);
for (i = 0; i < len; i++) {
p = strchr(lookup_table, src[i]);
if (p == NULL || src[i] == 0)
return -2;
ac += (p - lookup_table) << bits;
return -1;
ac = (ac << 6) | (p - base64url_table);
bits += 6;
if (bits >= 8) {
*cp++ = ac & 0xff;
ac >>= 8;
bits -= 8;
*bp++ = (u8)(ac >> bits);
}
}
if (ac)
if (ac & ((1 << bits) - 1))
return -1;
return cp - dst;
return bp - dst;
}
bool fscrypt_fname_encrypted_size(const union fscrypt_policy *policy,
......@@ -263,10 +287,8 @@ bool fscrypt_fname_encrypted_size(const union fscrypt_policy *policy,
int fscrypt_fname_alloc_buffer(u32 max_encrypted_len,
struct fscrypt_str *crypto_str)
{
const u32 max_encoded_len = BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX);
u32 max_presented_len;
max_presented_len = max(max_encoded_len, max_encrypted_len);
u32 max_presented_len = max_t(u32, FSCRYPT_NOKEY_NAME_MAX_ENCODED,
max_encrypted_len);
crypto_str->name = kmalloc(max_presented_len + 1, GFP_NOFS);
if (!crypto_str->name)
......@@ -342,7 +364,7 @@ int fscrypt_fname_disk_to_usr(const struct inode *inode,
offsetof(struct fscrypt_nokey_name, bytes));
BUILD_BUG_ON(offsetofend(struct fscrypt_nokey_name, bytes) !=
offsetof(struct fscrypt_nokey_name, sha256));
BUILD_BUG_ON(BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX) > NAME_MAX);
BUILD_BUG_ON(FSCRYPT_NOKEY_NAME_MAX_ENCODED > NAME_MAX);
nokey_name.dirhash[0] = hash;
nokey_name.dirhash[1] = minor_hash;
......@@ -358,7 +380,8 @@ int fscrypt_fname_disk_to_usr(const struct inode *inode,
nokey_name.sha256);
size = FSCRYPT_NOKEY_NAME_MAX;
}
oname->len = base64_encode((const u8 *)&nokey_name, size, oname->name);
oname->len = fscrypt_base64url_encode((const u8 *)&nokey_name, size,
oname->name);
return 0;
}
EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
......@@ -432,14 +455,15 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
* user-supplied name
*/
if (iname->len > BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX))
if (iname->len > FSCRYPT_NOKEY_NAME_MAX_ENCODED)
return -ENOENT;
fname->crypto_buf.name = kmalloc(FSCRYPT_NOKEY_NAME_MAX, GFP_KERNEL);
if (fname->crypto_buf.name == NULL)
return -ENOMEM;
ret = base64_decode(iname->name, iname->len, fname->crypto_buf.name);
ret = fscrypt_base64url_decode(iname->name, iname->len,
fname->crypto_buf.name);
if (ret < (int)offsetof(struct fscrypt_nokey_name, bytes[1]) ||
(ret > offsetof(struct fscrypt_nokey_name, sha256) &&
ret != FSCRYPT_NOKEY_NAME_MAX)) {
......
......@@ -384,3 +384,47 @@ const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(fscrypt_get_symlink);
/**
* fscrypt_symlink_getattr() - set the correct st_size for encrypted symlinks
* @path: the path for the encrypted symlink being queried
* @stat: the struct being filled with the symlink's attributes
*
* Override st_size of encrypted symlinks to be the length of the decrypted
* symlink target (or the no-key encoded symlink target, if the key is
* unavailable) rather than the length of the encrypted symlink target. This is
* necessary for st_size to match the symlink target that userspace actually
* sees. POSIX requires this, and some userspace programs depend on it.
*
* This requires reading the symlink target from disk if needed, setting up the
* inode's encryption key if possible, and then decrypting or encoding the
* symlink target. This makes lstat() more heavyweight than is normally the
* case. However, decrypted symlink targets will be cached in ->i_link, so
* usually the symlink won't have to be read and decrypted again later if/when
* it is actually followed, readlink() is called, or lstat() is called again.
*
* Return: 0 on success, -errno on failure
*/
int fscrypt_symlink_getattr(const struct path *path, struct kstat *stat)
{
struct dentry *dentry = path->dentry;
struct inode *inode = d_inode(dentry);
const char *link;
DEFINE_DELAYED_CALL(done);
/*
* To get the symlink target that userspace will see (whether it's the
* decrypted target or the no-key encoded target), we can just get it in
* the same way the VFS does during path resolution and readlink().
*/
link = READ_ONCE(inode->i_link);
if (!link) {
link = inode->i_op->get_link(dentry, inode, &done);
if (IS_ERR(link))
return PTR_ERR(link);
}
stat->size = strlen(link);
do_delayed_call(&done);
return 0;
}
EXPORT_SYMBOL_GPL(fscrypt_symlink_getattr);
......@@ -52,10 +52,20 @@ static const char *ext4_encrypted_get_link(struct dentry *dentry,
return paddr;
}
static int ext4_encrypted_symlink_getattr(struct user_namespace *mnt_userns,
const struct path *path,
struct kstat *stat, u32 request_mask,
unsigned int query_flags)
{
ext4_getattr(mnt_userns, path, stat, request_mask, query_flags);
return fscrypt_symlink_getattr(path, stat);
}
const struct inode_operations ext4_encrypted_symlink_inode_operations = {
.get_link = ext4_encrypted_get_link,
.setattr = ext4_setattr,
.getattr = ext4_getattr,
.getattr = ext4_encrypted_symlink_getattr,
.listxattr = ext4_listxattr,
};
......
......@@ -1323,9 +1323,19 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
return target;
}
static int f2fs_encrypted_symlink_getattr(struct user_namespace *mnt_userns,
const struct path *path,
struct kstat *stat, u32 request_mask,
unsigned int query_flags)
{
f2fs_getattr(mnt_userns, path, stat, request_mask, query_flags);
return fscrypt_symlink_getattr(path, stat);
}
const struct inode_operations f2fs_encrypted_symlink_inode_operations = {
.get_link = f2fs_encrypted_get_link,
.getattr = f2fs_getattr,
.getattr = f2fs_encrypted_symlink_getattr,
.setattr = f2fs_setattr,
.listxattr = f2fs_listxattr,
};
......
......@@ -1630,6 +1630,17 @@ static const char *ubifs_get_link(struct dentry *dentry,
return fscrypt_get_symlink(inode, ui->data, ui->data_len, done);
}
static int ubifs_symlink_getattr(struct user_namespace *mnt_userns,
const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int query_flags)
{
ubifs_getattr(mnt_userns, path, stat, request_mask, query_flags);
if (IS_ENCRYPTED(d_inode(path->dentry)))
return fscrypt_symlink_getattr(path, stat);
return 0;
}
const struct address_space_operations ubifs_file_address_operations = {
.readpage = ubifs_readpage,
.writepage = ubifs_writepage,
......@@ -1655,7 +1666,7 @@ const struct inode_operations ubifs_file_inode_operations = {
const struct inode_operations ubifs_symlink_inode_operations = {
.get_link = ubifs_get_link,
.setattr = ubifs_setattr,
.getattr = ubifs_getattr,
.getattr = ubifs_symlink_getattr,
.listxattr = ubifs_listxattr,
.update_time = ubifs_update_time,
};
......
......@@ -47,27 +47,128 @@ struct fscrypt_name {
#define FSCRYPT_SET_CONTEXT_MAX_SIZE 40
#ifdef CONFIG_FS_ENCRYPTION
/*
* fscrypt superblock flags
* If set, the fscrypt bounce page pool won't be allocated (unless another
* filesystem needs it). Set this if the filesystem always uses its own bounce
* pages for writes and therefore won't need the fscrypt bounce page pool.
*/
#define FS_CFLG_OWN_PAGES (1U << 1)
/*
* crypto operations for filesystems
*/
/* Crypto operations for filesystems */
struct fscrypt_operations {
/* Set of optional flags; see above for allowed flags */
unsigned int flags;
/*
* If set, this is a filesystem-specific key description prefix that
* will be accepted for "logon" keys for v1 fscrypt policies, in
* addition to the generic prefix "fscrypt:". This functionality is
* deprecated, so new filesystems shouldn't set this field.
*/
const char *key_prefix;
/*
* Get the fscrypt context of the given inode.
*
* @inode: the inode whose context to get
* @ctx: the buffer into which to get the context
* @len: length of the @ctx buffer in bytes
*
* Return: On success, returns the length of the context in bytes; this
* may be less than @len. On failure, returns -ENODATA if the
* inode doesn't have a context, -ERANGE if the context is
* longer than @len, or another -errno code.
*/
int (*get_context)(struct inode *inode, void *ctx, size_t len);
/*
* Set an fscrypt context on the given inode.
*
* @inode: the inode whose context to set. The inode won't already have
* an fscrypt context.
* @ctx: the context to set
* @len: length of @ctx in bytes (at most FSCRYPT_SET_CONTEXT_MAX_SIZE)
* @fs_data: If called from fscrypt_set_context(), this will be the
* value the filesystem passed to fscrypt_set_context().
* Otherwise (i.e. when called from
* FS_IOC_SET_ENCRYPTION_POLICY) this will be NULL.
*
* i_rwsem will be held for write.
*
* Return: 0 on success, -errno on failure.
*/
int (*set_context)(struct inode *inode, const void *ctx, size_t len,
void *fs_data);
/*
* Get the dummy fscrypt policy in use on the filesystem (if any).
*
* Filesystems only need to implement this function if they support the
* test_dummy_encryption mount option.
*
* Return: A pointer to the dummy fscrypt policy, if the filesystem is
* mounted with test_dummy_encryption; otherwise NULL.
*/
const union fscrypt_policy *(*get_dummy_policy)(struct super_block *sb);
/*
* Check whether a directory is empty. i_rwsem will be held for write.
*/
bool (*empty_dir)(struct inode *inode);
/* The filesystem's maximum ciphertext filename length, in bytes */
unsigned int max_namelen;
/*
* Check whether the filesystem's inode numbers and UUID are stable,
* meaning that they will never be changed even by offline operations
* such as filesystem shrinking and therefore can be used in the
* encryption without the possibility of files becoming unreadable.
*
* Filesystems only need to implement this function if they want to
* support the FSCRYPT_POLICY_FLAG_IV_INO_LBLK_{32,64} flags. These
* flags are designed to work around the limitations of UFS and eMMC
* inline crypto hardware, and they shouldn't be used in scenarios where
* such hardware isn't being used.
*
* Leaving this NULL is equivalent to always returning false.
*/
bool (*has_stable_inodes)(struct super_block *sb);
/*
* Get the number of bits that the filesystem uses to represent inode
* numbers and file logical block numbers.
*
* By default, both of these are assumed to be 64-bit. This function
* can be implemented to declare that either or both of these numbers is
* shorter, which may allow the use of the
* FSCRYPT_POLICY_FLAG_IV_INO_LBLK_{32,64} flags and/or the use of
* inline crypto hardware whose maximum DUN length is less than 64 bits
* (e.g., eMMC v5.2 spec compliant hardware). This function only needs
* to be implemented if support for one of these features is needed.
*/
void (*get_ino_and_lblk_bits)(struct super_block *sb,
int *ino_bits_ret, int *lblk_bits_ret);
/*
* Return the number of block devices to which the filesystem may write
* encrypted file contents.
*
* If the filesystem can use multiple block devices (other than block
* devices that aren't used for encrypted file contents, such as
* external journal devices), and wants to support inline encryption,
* then it must implement this function. Otherwise it's not needed.
*/
int (*get_num_devices)(struct super_block *sb);
/*
* If ->get_num_devices() returns a value greater than 1, then this
* function is called to get the array of request_queues that the
* filesystem is using -- one per block device. (There may be duplicate
* entries in this array, as block devices can share a request_queue.)
*/
void (*get_devices)(struct super_block *sb,
struct request_queue **devs);
};
......@@ -253,6 +354,7 @@ int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
unsigned int max_size,
struct delayed_call *done);
int fscrypt_symlink_getattr(const struct path *path, struct kstat *stat);
static inline void fscrypt_set_ops(struct super_block *sb,
const struct fscrypt_operations *s_cop)
{
......@@ -583,6 +685,12 @@ static inline const char *fscrypt_get_symlink(struct inode *inode,
return ERR_PTR(-EOPNOTSUPP);
}
static inline int fscrypt_symlink_getattr(const struct path *path,
struct kstat *stat)
{
return -EOPNOTSUPP;
}
static inline void fscrypt_set_ops(struct super_block *sb,
const struct fscrypt_operations *s_cop)
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment