Skip to content

Commit cd35820

Browse files
committed
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
2 parents 87045e6 + 38ef66b commit cd35820

File tree

7 files changed

+260
-58
lines changed

7 files changed

+260
-58
lines changed

Documentation/filesystems/fscrypt.rst

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,11 +1063,6 @@ astute users may notice some differences in behavior:
10631063

10641064
- DAX (Direct Access) is not supported on encrypted files.
10651065

1066-
- The st_size of an encrypted symlink will not necessarily give the
1067-
length of the symlink target as required by POSIX. It will actually
1068-
give the length of the ciphertext, which will be slightly longer
1069-
than the plaintext due to NUL-padding and an extra 2-byte overhead.
1070-
10711066
- The maximum length of an encrypted symlink is 2 bytes shorter than
10721067
the maximum length of an unencrypted symlink. For example, on an
10731068
EXT4 filesystem with a 4K block size, unencrypted symlinks can be up
@@ -1235,12 +1230,12 @@ the user-supplied name to get the ciphertext.
12351230

12361231
Lookups without the key are more complicated. The raw ciphertext may
12371232
contain the ``\0`` and ``/`` characters, which are illegal in
1238-
filenames. Therefore, readdir() must base64-encode the ciphertext for
1239-
presentation. For most filenames, this works fine; on ->lookup(), the
1240-
filesystem just base64-decodes the user-supplied name to get back to
1241-
the raw ciphertext.
1233+
filenames. Therefore, readdir() must base64url-encode the ciphertext
1234+
for presentation. For most filenames, this works fine; on ->lookup(),
1235+
the filesystem just base64url-decodes the user-supplied name to get
1236+
back to the raw ciphertext.
12421237

1243-
However, for very long filenames, base64 encoding would cause the
1238+
However, for very long filenames, base64url encoding would cause the
12441239
filename length to exceed NAME_MAX. To prevent this, readdir()
12451240
actually presents long filenames in an abbreviated form which encodes
12461241
a strong "hash" of the ciphertext filename, along with the optional

fs/crypto/fname.c

Lines changed: 65 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
* it to find the directory entry again if requested. Naively, that would just
2727
* mean using the ciphertext filenames. However, since the ciphertext filenames
2828
* can contain illegal characters ('\0' and '/'), they must be encoded in some
29-
* way. We use base64. But that can cause names to exceed NAME_MAX (255
29+
* way. We use base64url. But that can cause names to exceed NAME_MAX (255
3030
* bytes), so we also need to use a strong hash to abbreviate long names.
3131
*
3232
* The filesystem may also need another kind of hash, the "dirhash", to quickly
@@ -38,7 +38,7 @@
3838
* casefolded directories use this type of dirhash. At least in these cases,
3939
* each no-key name must include the name's dirhash too.
4040
*
41-
* To meet all these requirements, we base64-encode the following
41+
* To meet all these requirements, we base64url-encode the following
4242
* variable-length structure. It contains the dirhash, or 0's if the filesystem
4343
* didn't provide one; up to 149 bytes of the ciphertext name; and for
4444
* ciphertexts longer than 149 bytes, also the SHA-256 of the remaining bytes.
@@ -52,15 +52,19 @@ struct fscrypt_nokey_name {
5252
u32 dirhash[2];
5353
u8 bytes[149];
5454
u8 sha256[SHA256_DIGEST_SIZE];
55-
}; /* 189 bytes => 252 bytes base64-encoded, which is <= NAME_MAX (255) */
55+
}; /* 189 bytes => 252 bytes base64url-encoded, which is <= NAME_MAX (255) */
5656

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

64+
/* Encoded size of max-size no-key name */
65+
#define FSCRYPT_NOKEY_NAME_MAX_ENCODED \
66+
FSCRYPT_BASE64URL_CHARS(FSCRYPT_NOKEY_NAME_MAX)
67+
6468
static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
6569
{
6670
if (str->len == 1 && str->name[0] == '.')
@@ -175,62 +179,82 @@ static int fname_decrypt(const struct inode *inode,
175179
return 0;
176180
}
177181

178-
static const char lookup_table[65] =
179-
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
182+
static const char base64url_table[65] =
183+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
180184

181-
#define BASE64_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3)
185+
#define FSCRYPT_BASE64URL_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3)
182186

183187
/**
184-
* base64_encode() - base64-encode some bytes
185-
* @src: the bytes to encode
186-
* @len: number of bytes to encode
187-
* @dst: (output) the base64-encoded string. Not NUL-terminated.
188+
* fscrypt_base64url_encode() - base64url-encode some binary data
189+
* @src: the binary data to encode
190+
* @srclen: the length of @src in bytes
191+
* @dst: (output) the base64url-encoded string. Not NUL-terminated.
188192
*
189-
* Encodes the input string using characters from the set [A-Za-z0-9+,].
190-
* The encoded string is roughly 4/3 times the size of the input string.
193+
* Encodes data using base64url encoding, i.e. the "Base 64 Encoding with URL
194+
* and Filename Safe Alphabet" specified by RFC 4648. '='-padding isn't used,
195+
* as it's unneeded and not required by the RFC. base64url is used instead of
196+
* base64 to avoid the '/' character, which isn't allowed in filenames.
191197
*
192-
* Return: length of the encoded string
198+
* Return: the length of the resulting base64url-encoded string in bytes.
199+
* This will be equal to FSCRYPT_BASE64URL_CHARS(srclen).
193200
*/
194-
static int base64_encode(const u8 *src, int len, char *dst)
201+
static int fscrypt_base64url_encode(const u8 *src, int srclen, char *dst)
195202
{
196-
int i, bits = 0, ac = 0;
203+
u32 ac = 0;
204+
int bits = 0;
205+
int i;
197206
char *cp = dst;
198207

199-
for (i = 0; i < len; i++) {
200-
ac += src[i] << bits;
208+
for (i = 0; i < srclen; i++) {
209+
ac = (ac << 8) | src[i];
201210
bits += 8;
202211
do {
203-
*cp++ = lookup_table[ac & 0x3f];
204-
ac >>= 6;
205212
bits -= 6;
213+
*cp++ = base64url_table[(ac >> bits) & 0x3f];
206214
} while (bits >= 6);
207215
}
208216
if (bits)
209-
*cp++ = lookup_table[ac & 0x3f];
217+
*cp++ = base64url_table[(ac << (6 - bits)) & 0x3f];
210218
return cp - dst;
211219
}
212220

213-
static int base64_decode(const char *src, int len, u8 *dst)
221+
/**
222+
* fscrypt_base64url_decode() - base64url-decode a string
223+
* @src: the string to decode. Doesn't need to be NUL-terminated.
224+
* @srclen: the length of @src in bytes
225+
* @dst: (output) the decoded binary data
226+
*
227+
* Decodes a string using base64url encoding, i.e. the "Base 64 Encoding with
228+
* URL and Filename Safe Alphabet" specified by RFC 4648. '='-padding isn't
229+
* accepted, nor are non-encoding characters such as whitespace.
230+
*
231+
* This implementation hasn't been optimized for performance.
232+
*
233+
* Return: the length of the resulting decoded binary data in bytes,
234+
* or -1 if the string isn't a valid base64url string.
235+
*/
236+
static int fscrypt_base64url_decode(const char *src, int srclen, u8 *dst)
214237
{
215-
int i, bits = 0, ac = 0;
216-
const char *p;
217-
u8 *cp = dst;
238+
u32 ac = 0;
239+
int bits = 0;
240+
int i;
241+
u8 *bp = dst;
242+
243+
for (i = 0; i < srclen; i++) {
244+
const char *p = strchr(base64url_table, src[i]);
218245

219-
for (i = 0; i < len; i++) {
220-
p = strchr(lookup_table, src[i]);
221246
if (p == NULL || src[i] == 0)
222-
return -2;
223-
ac += (p - lookup_table) << bits;
247+
return -1;
248+
ac = (ac << 6) | (p - base64url_table);
224249
bits += 6;
225250
if (bits >= 8) {
226-
*cp++ = ac & 0xff;
227-
ac >>= 8;
228251
bits -= 8;
252+
*bp++ = (u8)(ac >> bits);
229253
}
230254
}
231-
if (ac)
255+
if (ac & ((1 << bits) - 1))
232256
return -1;
233-
return cp - dst;
257+
return bp - dst;
234258
}
235259

236260
bool fscrypt_fname_encrypted_size(const union fscrypt_policy *policy,
@@ -263,10 +287,8 @@ bool fscrypt_fname_encrypted_size(const union fscrypt_policy *policy,
263287
int fscrypt_fname_alloc_buffer(u32 max_encrypted_len,
264288
struct fscrypt_str *crypto_str)
265289
{
266-
const u32 max_encoded_len = BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX);
267-
u32 max_presented_len;
268-
269-
max_presented_len = max(max_encoded_len, max_encrypted_len);
290+
u32 max_presented_len = max_t(u32, FSCRYPT_NOKEY_NAME_MAX_ENCODED,
291+
max_encrypted_len);
270292

271293
crypto_str->name = kmalloc(max_presented_len + 1, GFP_NOFS);
272294
if (!crypto_str->name)
@@ -342,7 +364,7 @@ int fscrypt_fname_disk_to_usr(const struct inode *inode,
342364
offsetof(struct fscrypt_nokey_name, bytes));
343365
BUILD_BUG_ON(offsetofend(struct fscrypt_nokey_name, bytes) !=
344366
offsetof(struct fscrypt_nokey_name, sha256));
345-
BUILD_BUG_ON(BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX) > NAME_MAX);
367+
BUILD_BUG_ON(FSCRYPT_NOKEY_NAME_MAX_ENCODED > NAME_MAX);
346368

347369
nokey_name.dirhash[0] = hash;
348370
nokey_name.dirhash[1] = minor_hash;
@@ -358,7 +380,8 @@ int fscrypt_fname_disk_to_usr(const struct inode *inode,
358380
nokey_name.sha256);
359381
size = FSCRYPT_NOKEY_NAME_MAX;
360382
}
361-
oname->len = base64_encode((const u8 *)&nokey_name, size, oname->name);
383+
oname->len = fscrypt_base64url_encode((const u8 *)&nokey_name, size,
384+
oname->name);
362385
return 0;
363386
}
364387
EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
@@ -432,14 +455,15 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
432455
* user-supplied name
433456
*/
434457

435-
if (iname->len > BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX))
458+
if (iname->len > FSCRYPT_NOKEY_NAME_MAX_ENCODED)
436459
return -ENOENT;
437460

438461
fname->crypto_buf.name = kmalloc(FSCRYPT_NOKEY_NAME_MAX, GFP_KERNEL);
439462
if (fname->crypto_buf.name == NULL)
440463
return -ENOMEM;
441464

442-
ret = base64_decode(iname->name, iname->len, fname->crypto_buf.name);
465+
ret = fscrypt_base64url_decode(iname->name, iname->len,
466+
fname->crypto_buf.name);
443467
if (ret < (int)offsetof(struct fscrypt_nokey_name, bytes[1]) ||
444468
(ret > offsetof(struct fscrypt_nokey_name, sha256) &&
445469
ret != FSCRYPT_NOKEY_NAME_MAX)) {

fs/crypto/hooks.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,3 +384,47 @@ const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
384384
return ERR_PTR(err);
385385
}
386386
EXPORT_SYMBOL_GPL(fscrypt_get_symlink);
387+
388+
/**
389+
* fscrypt_symlink_getattr() - set the correct st_size for encrypted symlinks
390+
* @path: the path for the encrypted symlink being queried
391+
* @stat: the struct being filled with the symlink's attributes
392+
*
393+
* Override st_size of encrypted symlinks to be the length of the decrypted
394+
* symlink target (or the no-key encoded symlink target, if the key is
395+
* unavailable) rather than the length of the encrypted symlink target. This is
396+
* necessary for st_size to match the symlink target that userspace actually
397+
* sees. POSIX requires this, and some userspace programs depend on it.
398+
*
399+
* This requires reading the symlink target from disk if needed, setting up the
400+
* inode's encryption key if possible, and then decrypting or encoding the
401+
* symlink target. This makes lstat() more heavyweight than is normally the
402+
* case. However, decrypted symlink targets will be cached in ->i_link, so
403+
* usually the symlink won't have to be read and decrypted again later if/when
404+
* it is actually followed, readlink() is called, or lstat() is called again.
405+
*
406+
* Return: 0 on success, -errno on failure
407+
*/
408+
int fscrypt_symlink_getattr(const struct path *path, struct kstat *stat)
409+
{
410+
struct dentry *dentry = path->dentry;
411+
struct inode *inode = d_inode(dentry);
412+
const char *link;
413+
DEFINE_DELAYED_CALL(done);
414+
415+
/*
416+
* To get the symlink target that userspace will see (whether it's the
417+
* decrypted target or the no-key encoded target), we can just get it in
418+
* the same way the VFS does during path resolution and readlink().
419+
*/
420+
link = READ_ONCE(inode->i_link);
421+
if (!link) {
422+
link = inode->i_op->get_link(dentry, inode, &done);
423+
if (IS_ERR(link))
424+
return PTR_ERR(link);
425+
}
426+
stat->size = strlen(link);
427+
do_delayed_call(&done);
428+
return 0;
429+
}
430+
EXPORT_SYMBOL_GPL(fscrypt_symlink_getattr);

fs/ext4/symlink.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,20 @@ static const char *ext4_encrypted_get_link(struct dentry *dentry,
5252
return paddr;
5353
}
5454

55+
static int ext4_encrypted_symlink_getattr(struct user_namespace *mnt_userns,
56+
const struct path *path,
57+
struct kstat *stat, u32 request_mask,
58+
unsigned int query_flags)
59+
{
60+
ext4_getattr(mnt_userns, path, stat, request_mask, query_flags);
61+
62+
return fscrypt_symlink_getattr(path, stat);
63+
}
64+
5565
const struct inode_operations ext4_encrypted_symlink_inode_operations = {
5666
.get_link = ext4_encrypted_get_link,
5767
.setattr = ext4_setattr,
58-
.getattr = ext4_getattr,
68+
.getattr = ext4_encrypted_symlink_getattr,
5969
.listxattr = ext4_listxattr,
6070
};
6171

fs/f2fs/namei.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1323,9 +1323,19 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
13231323
return target;
13241324
}
13251325

1326+
static int f2fs_encrypted_symlink_getattr(struct user_namespace *mnt_userns,
1327+
const struct path *path,
1328+
struct kstat *stat, u32 request_mask,
1329+
unsigned int query_flags)
1330+
{
1331+
f2fs_getattr(mnt_userns, path, stat, request_mask, query_flags);
1332+
1333+
return fscrypt_symlink_getattr(path, stat);
1334+
}
1335+
13261336
const struct inode_operations f2fs_encrypted_symlink_inode_operations = {
13271337
.get_link = f2fs_encrypted_get_link,
1328-
.getattr = f2fs_getattr,
1338+
.getattr = f2fs_encrypted_symlink_getattr,
13291339
.setattr = f2fs_setattr,
13301340
.listxattr = f2fs_listxattr,
13311341
};

fs/ubifs/file.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1630,6 +1630,17 @@ static const char *ubifs_get_link(struct dentry *dentry,
16301630
return fscrypt_get_symlink(inode, ui->data, ui->data_len, done);
16311631
}
16321632

1633+
static int ubifs_symlink_getattr(struct user_namespace *mnt_userns,
1634+
const struct path *path, struct kstat *stat,
1635+
u32 request_mask, unsigned int query_flags)
1636+
{
1637+
ubifs_getattr(mnt_userns, path, stat, request_mask, query_flags);
1638+
1639+
if (IS_ENCRYPTED(d_inode(path->dentry)))
1640+
return fscrypt_symlink_getattr(path, stat);
1641+
return 0;
1642+
}
1643+
16331644
const struct address_space_operations ubifs_file_address_operations = {
16341645
.readpage = ubifs_readpage,
16351646
.writepage = ubifs_writepage,
@@ -1655,7 +1666,7 @@ const struct inode_operations ubifs_file_inode_operations = {
16551666
const struct inode_operations ubifs_symlink_inode_operations = {
16561667
.get_link = ubifs_get_link,
16571668
.setattr = ubifs_setattr,
1658-
.getattr = ubifs_getattr,
1669+
.getattr = ubifs_symlink_getattr,
16591670
.listxattr = ubifs_listxattr,
16601671
.update_time = ubifs_update_time,
16611672
};

0 commit comments

Comments
 (0)