License cleanup: add SPDX GPL-2.0 license identifier to files with no license
Many source files in the tree are missing licensing information, which
makes it harder for compliance tools to determine the correct license.
By default all files without license information are under the default
license of the kernel, which is GPL version 2.
Update the files which contain no license information with the 'GPL-2.0'
SPDX license identifier. The SPDX identifier is a legally binding
shorthand, which can be used instead of the full boiler plate text.
This patch is based on work done by Thomas Gleixner and Kate Stewart and
Philippe Ombredanne.
How this work was done:
Patches were generated and checked against linux-4.14-rc6 for a subset of
the use cases:
- file had no licensing information it it.
- file was a */uapi/* one with no licensing information in it,
- file was a */uapi/* one with existing licensing information,
Further patches will be generated in subsequent months to fix up cases
where non-standard license headers were used, and references to license
had to be inferred by heuristics based on keywords.
The analysis to determine which SPDX License Identifier to be applied to
a file was done in a spreadsheet of side by side results from of the
output of two independent scanners (ScanCode & Windriver) producing SPDX
tag:value files created by Philippe Ombredanne. Philippe prepared the
base worksheet, and did an initial spot review of a few 1000 files.
The 4.13 kernel was the starting point of the analysis with 60,537 files
assessed. Kate Stewart did a file by file comparison of the scanner
results in the spreadsheet to determine which SPDX license identifier(s)
to be applied to the file. She confirmed any determination that was not
immediately clear with lawyers working with the Linux Foundation.
Criteria used to select files for SPDX license identifier tagging was:
- Files considered eligible had to be source code files.
- Make and config files were included as candidates if they contained >5
lines of source
- File already had some variant of a license header in it (even if <5
lines).
All documentation files were explicitly excluded.
The following heuristics were used to determine which SPDX license
identifiers to apply.
- when both scanners couldn't find any license traces, file was
considered to have no license information in it, and the top level
COPYING file license applied.
For non */uapi/* files that summary was:
SPDX license identifier # files
---------------------------------------------------|-------
GPL-2.0 11139
and resulted in the first patch in this series.
If that file was a */uapi/* path one, it was "GPL-2.0 WITH
Linux-syscall-note" otherwise it was "GPL-2.0". Results of that was:
SPDX license identifier # files
---------------------------------------------------|-------
GPL-2.0 WITH Linux-syscall-note 930
and resulted in the second patch in this series.
- if a file had some form of licensing information in it, and was one
of the */uapi/* ones, it was denoted with the Linux-syscall-note if
any GPL family license was found in the file or had no licensing in
it (per prior point). Results summary:
SPDX license identifier # files
---------------------------------------------------|------
GPL-2.0 WITH Linux-syscall-note 270
GPL-2.0+ WITH Linux-syscall-note 169
((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) 21
((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 17
LGPL-2.1+ WITH Linux-syscall-note 15
GPL-1.0+ WITH Linux-syscall-note 14
((GPL-2.0+ WITH Linux-syscall-note) OR BSD-3-Clause) 5
LGPL-2.0+ WITH Linux-syscall-note 4
LGPL-2.1 WITH Linux-syscall-note 3
((GPL-2.0 WITH Linux-syscall-note) OR MIT) 3
((GPL-2.0 WITH Linux-syscall-note) AND MIT) 1
and that resulted in the third patch in this series.
- when the two scanners agreed on the detected license(s), that became
the concluded license(s).
- when there was disagreement between the two scanners (one detected a
license but the other didn't, or they both detected different
licenses) a manual inspection of the file occurred.
- In most cases a manual inspection of the information in the file
resulted in a clear resolution of the license that should apply (and
which scanner probably needed to revisit its heuristics).
- When it was not immediately clear, the license identifier was
confirmed with lawyers working with the Linux Foundation.
- If there was any question as to the appropriate license identifier,
the file was flagged for further research and to be revisited later
in time.
In total, over 70 hours of logged manual review was done on the
spreadsheet to determine the SPDX license identifiers to apply to the
source files by Kate, Philippe, Thomas and, in some cases, confirmation
by lawyers working with the Linux Foundation.
Kate also obtained a third independent scan of the 4.13 code base from
FOSSology, and compared selected files where the other two scanners
disagreed against that SPDX file, to see if there was new insights. The
Windriver scanner is based on an older version of FOSSology in part, so
they are related.
Thomas did random spot checks in about 500 files from the spreadsheets
for the uapi headers and agreed with SPDX license identifier in the
files he inspected. For the non-uapi files Thomas did random spot checks
in about 15000 files.
In initial set of patches against 4.14-rc6, 3 files were found to have
copy/paste license identifier errors, and have been fixed to reflect the
correct identifier.
Additionally Philippe spent 10 hours this week doing a detailed manual
inspection and review of the 12,461 patched files from the initial patch
version early this week with:
- a full scancode scan run, collecting the matched texts, detected
license ids and scores
- reviewing anything where there was a license detected (about 500+
files) to ensure that the applied SPDX license was correct
- reviewing anything where there was no detection but the patch license
was not GPL-2.0 WITH Linux-syscall-note to ensure that the applied
SPDX license was correct
This produced a worksheet with 20 files needing minor correction. This
worksheet was then exported into 3 different .csv files for the
different types of files to be modified.
These .csv files were then reviewed by Greg. Thomas wrote a script to
parse the csv files and add the proper SPDX tag to the file, in the
format that the file expected. This script was further refined by Greg
based on the output to detect more types of files automatically and to
distinguish between header and source .c files (which need different
comment types.) Finally Greg ran the script using the .csv files to
generate the patches.
Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org>
Reviewed-by: Philippe Ombredanne <pombredanne@nexb.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-11-01 22:07:57 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2015-04-26 15:12:50 +08:00
|
|
|
/*
|
2015-05-16 07:26:10 +08:00
|
|
|
* This contains functions for filename crypto management
|
2015-04-26 15:12:50 +08:00
|
|
|
*
|
|
|
|
* Copyright (C) 2015, Google, Inc.
|
|
|
|
* Copyright (C) 2015, Motorola Mobility
|
|
|
|
*
|
|
|
|
* Written by Uday Savagaonkar, 2014.
|
2015-05-16 07:26:10 +08:00
|
|
|
* Modified by Jaegeuk Kim, 2015.
|
2015-04-26 15:12:50 +08:00
|
|
|
*
|
|
|
|
* This has not yet undergone a rigorous security audit.
|
|
|
|
*/
|
2015-05-16 07:26:10 +08:00
|
|
|
|
2019-12-10 04:43:59 +08:00
|
|
|
#include <linux/namei.h>
|
2015-04-26 15:12:50 +08:00
|
|
|
#include <linux/scatterlist.h>
|
fscrypt: improve format of no-key names
When an encrypted directory is listed without the key, the filesystem
must show "no-key names" that uniquely identify directory entries, are
at most 255 (NAME_MAX) bytes long, and don't contain '/' or '\0'.
Currently, for short names the no-key name is the base64 encoding of the
ciphertext filename, while for long names it's the base64 encoding of
the ciphertext filename's dirhash and second-to-last 16-byte block.
This format has the following problems:
- Since it doesn't always include the dirhash, it's incompatible with
directories that will use a secret-keyed dirhash over the plaintext
filenames. In this case, the dirhash won't be computable from the
ciphertext name without the key, so it instead must be retrieved from
the directory entry and always included in the no-key name.
Casefolded encrypted directories will use this type of dirhash.
- It's ambiguous: it's possible to craft two filenames that map to the
same no-key name, since the method used to abbreviate long filenames
doesn't use a proper cryptographic hash function.
Solve both these problems by switching to a new no-key name format that
is the base64 encoding of a variable-length structure that contains the
dirhash, up to 149 bytes of the ciphertext filename, and (if any bytes
remain) the SHA-256 of the remaining bytes of the ciphertext filename.
This ensures that each no-key name contains everything needed to find
the directory entry again, contains only legal characters, doesn't
exceed NAME_MAX, is unambiguous unless there's a SHA-256 collision, and
that we only take the performance hit of SHA-256 on very long filenames.
Note: this change does *not* address the existing issue where users can
modify the 'dirhash' part of a no-key name and the filesystem may still
accept the name.
Signed-off-by: Daniel Rosenberg <drosen@google.com>
[EB: improved comments and commit message, fixed checking return value
of base64_decode(), check for SHA-256 error, continue to set disk_name
for short names to keep matching simpler, and many other cleanups]
Link: https://lore.kernel.org/r/20200120223201.241390-7-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-01-21 06:32:01 +08:00
|
|
|
#include <crypto/hash.h>
|
2020-11-13 13:20:21 +08:00
|
|
|
#include <crypto/sha2.h>
|
2018-01-06 02:45:00 +08:00
|
|
|
#include <crypto/skcipher.h>
|
2016-11-27 09:32:46 +08:00
|
|
|
#include "fscrypt_private.h"
|
2015-04-26 15:12:50 +08:00
|
|
|
|
2020-05-12 03:13:56 +08:00
|
|
|
/*
|
fscrypt: improve format of no-key names
When an encrypted directory is listed without the key, the filesystem
must show "no-key names" that uniquely identify directory entries, are
at most 255 (NAME_MAX) bytes long, and don't contain '/' or '\0'.
Currently, for short names the no-key name is the base64 encoding of the
ciphertext filename, while for long names it's the base64 encoding of
the ciphertext filename's dirhash and second-to-last 16-byte block.
This format has the following problems:
- Since it doesn't always include the dirhash, it's incompatible with
directories that will use a secret-keyed dirhash over the plaintext
filenames. In this case, the dirhash won't be computable from the
ciphertext name without the key, so it instead must be retrieved from
the directory entry and always included in the no-key name.
Casefolded encrypted directories will use this type of dirhash.
- It's ambiguous: it's possible to craft two filenames that map to the
same no-key name, since the method used to abbreviate long filenames
doesn't use a proper cryptographic hash function.
Solve both these problems by switching to a new no-key name format that
is the base64 encoding of a variable-length structure that contains the
dirhash, up to 149 bytes of the ciphertext filename, and (if any bytes
remain) the SHA-256 of the remaining bytes of the ciphertext filename.
This ensures that each no-key name contains everything needed to find
the directory entry again, contains only legal characters, doesn't
exceed NAME_MAX, is unambiguous unless there's a SHA-256 collision, and
that we only take the performance hit of SHA-256 on very long filenames.
Note: this change does *not* address the existing issue where users can
modify the 'dirhash' part of a no-key name and the filesystem may still
accept the name.
Signed-off-by: Daniel Rosenberg <drosen@google.com>
[EB: improved comments and commit message, fixed checking return value
of base64_decode(), check for SHA-256 error, continue to set disk_name
for short names to keep matching simpler, and many other cleanups]
Link: https://lore.kernel.org/r/20200120223201.241390-7-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-01-21 06:32:01 +08:00
|
|
|
* struct fscrypt_nokey_name - identifier for directory entry when key is absent
|
|
|
|
*
|
|
|
|
* When userspace lists an encrypted directory without access to the key, the
|
|
|
|
* filesystem must present a unique "no-key name" for each filename that allows
|
|
|
|
* 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
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
* way. We use base64url. But that can cause names to exceed NAME_MAX (255
|
fscrypt: improve format of no-key names
When an encrypted directory is listed without the key, the filesystem
must show "no-key names" that uniquely identify directory entries, are
at most 255 (NAME_MAX) bytes long, and don't contain '/' or '\0'.
Currently, for short names the no-key name is the base64 encoding of the
ciphertext filename, while for long names it's the base64 encoding of
the ciphertext filename's dirhash and second-to-last 16-byte block.
This format has the following problems:
- Since it doesn't always include the dirhash, it's incompatible with
directories that will use a secret-keyed dirhash over the plaintext
filenames. In this case, the dirhash won't be computable from the
ciphertext name without the key, so it instead must be retrieved from
the directory entry and always included in the no-key name.
Casefolded encrypted directories will use this type of dirhash.
- It's ambiguous: it's possible to craft two filenames that map to the
same no-key name, since the method used to abbreviate long filenames
doesn't use a proper cryptographic hash function.
Solve both these problems by switching to a new no-key name format that
is the base64 encoding of a variable-length structure that contains the
dirhash, up to 149 bytes of the ciphertext filename, and (if any bytes
remain) the SHA-256 of the remaining bytes of the ciphertext filename.
This ensures that each no-key name contains everything needed to find
the directory entry again, contains only legal characters, doesn't
exceed NAME_MAX, is unambiguous unless there's a SHA-256 collision, and
that we only take the performance hit of SHA-256 on very long filenames.
Note: this change does *not* address the existing issue where users can
modify the 'dirhash' part of a no-key name and the filesystem may still
accept the name.
Signed-off-by: Daniel Rosenberg <drosen@google.com>
[EB: improved comments and commit message, fixed checking return value
of base64_decode(), check for SHA-256 error, continue to set disk_name
for short names to keep matching simpler, and many other cleanups]
Link: https://lore.kernel.org/r/20200120223201.241390-7-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-01-21 06:32:01 +08:00
|
|
|
* 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
|
|
|
|
* find the directory entry. Since filesystems normally compute the dirhash
|
|
|
|
* over the on-disk filename (i.e. the ciphertext), it's not computable from
|
|
|
|
* no-key names that abbreviate the ciphertext using the strong hash to fit in
|
|
|
|
* NAME_MAX. It's also not computable if it's a keyed hash taken over the
|
|
|
|
* plaintext (but it may still be available in the on-disk directory entry);
|
|
|
|
* casefolded directories use this type of dirhash. At least in these cases,
|
|
|
|
* each no-key name must include the name's dirhash too.
|
|
|
|
*
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
* To meet all these requirements, we base64url-encode the following
|
fscrypt: improve format of no-key names
When an encrypted directory is listed without the key, the filesystem
must show "no-key names" that uniquely identify directory entries, are
at most 255 (NAME_MAX) bytes long, and don't contain '/' or '\0'.
Currently, for short names the no-key name is the base64 encoding of the
ciphertext filename, while for long names it's the base64 encoding of
the ciphertext filename's dirhash and second-to-last 16-byte block.
This format has the following problems:
- Since it doesn't always include the dirhash, it's incompatible with
directories that will use a secret-keyed dirhash over the plaintext
filenames. In this case, the dirhash won't be computable from the
ciphertext name without the key, so it instead must be retrieved from
the directory entry and always included in the no-key name.
Casefolded encrypted directories will use this type of dirhash.
- It's ambiguous: it's possible to craft two filenames that map to the
same no-key name, since the method used to abbreviate long filenames
doesn't use a proper cryptographic hash function.
Solve both these problems by switching to a new no-key name format that
is the base64 encoding of a variable-length structure that contains the
dirhash, up to 149 bytes of the ciphertext filename, and (if any bytes
remain) the SHA-256 of the remaining bytes of the ciphertext filename.
This ensures that each no-key name contains everything needed to find
the directory entry again, contains only legal characters, doesn't
exceed NAME_MAX, is unambiguous unless there's a SHA-256 collision, and
that we only take the performance hit of SHA-256 on very long filenames.
Note: this change does *not* address the existing issue where users can
modify the 'dirhash' part of a no-key name and the filesystem may still
accept the name.
Signed-off-by: Daniel Rosenberg <drosen@google.com>
[EB: improved comments and commit message, fixed checking return value
of base64_decode(), check for SHA-256 error, continue to set disk_name
for short names to keep matching simpler, and many other cleanups]
Link: https://lore.kernel.org/r/20200120223201.241390-7-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-01-21 06:32:01 +08:00
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* This ensures that each no-key name contains everything needed to find the
|
|
|
|
* directory entry again, contains only legal characters, doesn't exceed
|
|
|
|
* NAME_MAX, is unambiguous unless there's a SHA-256 collision, and that we only
|
|
|
|
* take the performance hit of SHA-256 on very long filenames (which are rare).
|
|
|
|
*/
|
|
|
|
struct fscrypt_nokey_name {
|
|
|
|
u32 dirhash[2];
|
|
|
|
u8 bytes[149];
|
|
|
|
u8 sha256[SHA256_DIGEST_SIZE];
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
}; /* 189 bytes => 252 bytes base64url-encoded, which is <= NAME_MAX (255) */
|
fscrypt: improve format of no-key names
When an encrypted directory is listed without the key, the filesystem
must show "no-key names" that uniquely identify directory entries, are
at most 255 (NAME_MAX) bytes long, and don't contain '/' or '\0'.
Currently, for short names the no-key name is the base64 encoding of the
ciphertext filename, while for long names it's the base64 encoding of
the ciphertext filename's dirhash and second-to-last 16-byte block.
This format has the following problems:
- Since it doesn't always include the dirhash, it's incompatible with
directories that will use a secret-keyed dirhash over the plaintext
filenames. In this case, the dirhash won't be computable from the
ciphertext name without the key, so it instead must be retrieved from
the directory entry and always included in the no-key name.
Casefolded encrypted directories will use this type of dirhash.
- It's ambiguous: it's possible to craft two filenames that map to the
same no-key name, since the method used to abbreviate long filenames
doesn't use a proper cryptographic hash function.
Solve both these problems by switching to a new no-key name format that
is the base64 encoding of a variable-length structure that contains the
dirhash, up to 149 bytes of the ciphertext filename, and (if any bytes
remain) the SHA-256 of the remaining bytes of the ciphertext filename.
This ensures that each no-key name contains everything needed to find
the directory entry again, contains only legal characters, doesn't
exceed NAME_MAX, is unambiguous unless there's a SHA-256 collision, and
that we only take the performance hit of SHA-256 on very long filenames.
Note: this change does *not* address the existing issue where users can
modify the 'dirhash' part of a no-key name and the filesystem may still
accept the name.
Signed-off-by: Daniel Rosenberg <drosen@google.com>
[EB: improved comments and commit message, fixed checking return value
of base64_decode(), check for SHA-256 error, continue to set disk_name
for short names to keep matching simpler, and many other cleanups]
Link: https://lore.kernel.org/r/20200120223201.241390-7-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-01-21 06:32:01 +08:00
|
|
|
|
|
|
|
/*
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
* Decoded size of max-size no-key name, i.e. a name that was abbreviated using
|
fscrypt: improve format of no-key names
When an encrypted directory is listed without the key, the filesystem
must show "no-key names" that uniquely identify directory entries, are
at most 255 (NAME_MAX) bytes long, and don't contain '/' or '\0'.
Currently, for short names the no-key name is the base64 encoding of the
ciphertext filename, while for long names it's the base64 encoding of
the ciphertext filename's dirhash and second-to-last 16-byte block.
This format has the following problems:
- Since it doesn't always include the dirhash, it's incompatible with
directories that will use a secret-keyed dirhash over the plaintext
filenames. In this case, the dirhash won't be computable from the
ciphertext name without the key, so it instead must be retrieved from
the directory entry and always included in the no-key name.
Casefolded encrypted directories will use this type of dirhash.
- It's ambiguous: it's possible to craft two filenames that map to the
same no-key name, since the method used to abbreviate long filenames
doesn't use a proper cryptographic hash function.
Solve both these problems by switching to a new no-key name format that
is the base64 encoding of a variable-length structure that contains the
dirhash, up to 149 bytes of the ciphertext filename, and (if any bytes
remain) the SHA-256 of the remaining bytes of the ciphertext filename.
This ensures that each no-key name contains everything needed to find
the directory entry again, contains only legal characters, doesn't
exceed NAME_MAX, is unambiguous unless there's a SHA-256 collision, and
that we only take the performance hit of SHA-256 on very long filenames.
Note: this change does *not* address the existing issue where users can
modify the 'dirhash' part of a no-key name and the filesystem may still
accept the name.
Signed-off-by: Daniel Rosenberg <drosen@google.com>
[EB: improved comments and commit message, fixed checking return value
of base64_decode(), check for SHA-256 error, continue to set disk_name
for short names to keep matching simpler, and many other cleanups]
Link: https://lore.kernel.org/r/20200120223201.241390-7-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-01-21 06:32:01 +08:00
|
|
|
* 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)
|
|
|
|
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
/* Encoded size of max-size no-key name */
|
|
|
|
#define FSCRYPT_NOKEY_NAME_MAX_ENCODED \
|
|
|
|
FSCRYPT_BASE64URL_CHARS(FSCRYPT_NOKEY_NAME_MAX)
|
|
|
|
|
2018-01-06 02:44:59 +08:00
|
|
|
static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
|
|
|
|
{
|
|
|
|
if (str->len == 1 && str->name[0] == '.')
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-04-26 15:12:50 +08:00
|
|
|
/**
|
2020-01-20 15:17:36 +08:00
|
|
|
* fscrypt_fname_encrypt() - encrypt a filename
|
2020-05-12 03:13:56 +08:00
|
|
|
* @inode: inode of the parent directory (for regular filenames)
|
|
|
|
* or of the symlink (for symlink targets)
|
|
|
|
* @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.
|
2016-09-16 05:25:55 +08:00
|
|
|
*
|
|
|
|
* Return: 0 on success, -errno on failure
|
2015-04-26 15:12:50 +08:00
|
|
|
*/
|
2020-01-20 15:17:36 +08:00
|
|
|
int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname,
|
|
|
|
u8 *out, unsigned int olen)
|
2015-04-26 15:12:50 +08:00
|
|
|
{
|
2016-01-24 21:17:49 +08:00
|
|
|
struct skcipher_request *req = NULL;
|
2017-10-18 15:00:44 +08:00
|
|
|
DECLARE_CRYPTO_WAIT(wait);
|
2019-12-16 05:39:47 +08:00
|
|
|
const struct fscrypt_info *ci = inode->i_crypt_info;
|
2020-07-02 09:56:05 +08:00
|
|
|
struct crypto_skcipher *tfm = ci->ci_enc_key.tfm;
|
fscrypt: add Adiantum support
Add support for the Adiantum encryption mode to fscrypt. Adiantum is a
tweakable, length-preserving encryption mode with security provably
reducible to that of XChaCha12 and AES-256, subject to a security bound.
It's also a true wide-block mode, unlike XTS. See the paper
"Adiantum: length-preserving encryption for entry-level processors"
(https://eprint.iacr.org/2018/720.pdf) for more details. Also see
commit 059c2a4d8e16 ("crypto: adiantum - add Adiantum support").
On sufficiently long messages, Adiantum's bottlenecks are XChaCha12 and
the NH hash function. These algorithms are fast even on processors
without dedicated crypto instructions. Adiantum makes it feasible to
enable storage encryption on low-end mobile devices that lack AES
instructions; currently such devices are unencrypted. On ARM Cortex-A7,
on 4096-byte messages Adiantum encryption is about 4 times faster than
AES-256-XTS encryption; decryption is about 5 times faster.
In fscrypt, Adiantum is suitable for encrypting both file contents and
names. With filenames, it fixes a known weakness: when two filenames in
a directory share a common prefix of >= 16 bytes, with CTS-CBC their
encrypted filenames share a common prefix too, leaking information.
Adiantum does not have this problem.
Since Adiantum also accepts long tweaks (IVs), it's also safe to use the
master key directly for Adiantum encryption rather than deriving
per-file keys, provided that the per-file nonce is included in the IVs
and the master key isn't used for any other encryption mode. This
configuration saves memory and improves performance. A new fscrypt
policy flag is added to allow users to opt-in to this configuration.
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2019-01-06 21:36:21 +08:00
|
|
|
union fscrypt_iv iv;
|
2016-11-14 09:35:52 +08:00
|
|
|
struct scatterlist sg;
|
fscrypt: add Adiantum support
Add support for the Adiantum encryption mode to fscrypt. Adiantum is a
tweakable, length-preserving encryption mode with security provably
reducible to that of XChaCha12 and AES-256, subject to a security bound.
It's also a true wide-block mode, unlike XTS. See the paper
"Adiantum: length-preserving encryption for entry-level processors"
(https://eprint.iacr.org/2018/720.pdf) for more details. Also see
commit 059c2a4d8e16 ("crypto: adiantum - add Adiantum support").
On sufficiently long messages, Adiantum's bottlenecks are XChaCha12 and
the NH hash function. These algorithms are fast even on processors
without dedicated crypto instructions. Adiantum makes it feasible to
enable storage encryption on low-end mobile devices that lack AES
instructions; currently such devices are unencrypted. On ARM Cortex-A7,
on 4096-byte messages Adiantum encryption is about 4 times faster than
AES-256-XTS encryption; decryption is about 5 times faster.
In fscrypt, Adiantum is suitable for encrypting both file contents and
names. With filenames, it fixes a known weakness: when two filenames in
a directory share a common prefix of >= 16 bytes, with CTS-CBC their
encrypted filenames share a common prefix too, leaking information.
Adiantum does not have this problem.
Since Adiantum also accepts long tweaks (IVs), it's also safe to use the
master key directly for Adiantum encryption rather than deriving
per-file keys, provided that the per-file nonce is included in the IVs
and the master key isn't used for any other encryption mode. This
configuration saves memory and improves performance. A new fscrypt
policy flag is added to allow users to opt-in to this configuration.
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2019-01-06 21:36:21 +08:00
|
|
|
int res;
|
2015-04-26 15:12:50 +08:00
|
|
|
|
2016-11-14 09:35:52 +08:00
|
|
|
/*
|
|
|
|
* Copy the filename to the output buffer for encrypting in-place and
|
|
|
|
* pad it with the needed number of NUL bytes.
|
|
|
|
*/
|
2018-01-12 12:30:08 +08:00
|
|
|
if (WARN_ON(olen < iname->len))
|
fscrypt: new helper functions for ->symlink()
Currently, filesystems supporting fscrypt need to implement some tricky
logic when creating encrypted symlinks, including handling a peculiar
on-disk format (struct fscrypt_symlink_data) and correctly calculating
the size of the encrypted symlink. Introduce helper functions to make
things a bit easier:
- fscrypt_prepare_symlink() computes and validates the size the symlink
target will require on-disk.
- fscrypt_encrypt_symlink() creates the encrypted target if needed.
The new helpers actually fix some subtle bugs. First, when checking
whether the symlink target was too long, filesystems didn't account for
the fact that the NUL padding is meant to be truncated if it would cause
the maximum length to be exceeded, as is done for filenames in
directories. Consequently users would receive ENAMETOOLONG when
creating symlinks close to what is supposed to be the maximum length.
For example, with EXT4 with a 4K block size, the maximum symlink target
length in an encrypted directory is supposed to be 4093 bytes (in
comparison to 4095 in an unencrypted directory), but in
FS_POLICY_FLAGS_PAD_32-mode only up to 4064 bytes were accepted.
Second, symlink targets of "." and ".." were not being encrypted, even
though they should be, as these names are special in *directory entries*
but not in symlink targets. Fortunately, we can fix this simply by
starting to encrypt them, as old kernels already accept them in
encrypted form.
Third, the output string length the filesystems were providing when
doing the actual encryption was incorrect, as it was forgotten to
exclude 'sizeof(struct fscrypt_symlink_data)'. Fortunately though, this
bug didn't make a difference.
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2018-01-06 02:45:01 +08:00
|
|
|
return -ENOBUFS;
|
2018-01-12 12:30:08 +08:00
|
|
|
memcpy(out, iname->name, iname->len);
|
|
|
|
memset(out + iname->len, 0, olen - iname->len);
|
2015-04-26 15:12:50 +08:00
|
|
|
|
2016-11-14 09:35:52 +08:00
|
|
|
/* Initialize the IV */
|
fscrypt: add Adiantum support
Add support for the Adiantum encryption mode to fscrypt. Adiantum is a
tweakable, length-preserving encryption mode with security provably
reducible to that of XChaCha12 and AES-256, subject to a security bound.
It's also a true wide-block mode, unlike XTS. See the paper
"Adiantum: length-preserving encryption for entry-level processors"
(https://eprint.iacr.org/2018/720.pdf) for more details. Also see
commit 059c2a4d8e16 ("crypto: adiantum - add Adiantum support").
On sufficiently long messages, Adiantum's bottlenecks are XChaCha12 and
the NH hash function. These algorithms are fast even on processors
without dedicated crypto instructions. Adiantum makes it feasible to
enable storage encryption on low-end mobile devices that lack AES
instructions; currently such devices are unencrypted. On ARM Cortex-A7,
on 4096-byte messages Adiantum encryption is about 4 times faster than
AES-256-XTS encryption; decryption is about 5 times faster.
In fscrypt, Adiantum is suitable for encrypting both file contents and
names. With filenames, it fixes a known weakness: when two filenames in
a directory share a common prefix of >= 16 bytes, with CTS-CBC their
encrypted filenames share a common prefix too, leaking information.
Adiantum does not have this problem.
Since Adiantum also accepts long tweaks (IVs), it's also safe to use the
master key directly for Adiantum encryption rather than deriving
per-file keys, provided that the per-file nonce is included in the IVs
and the master key isn't used for any other encryption mode. This
configuration saves memory and improves performance. A new fscrypt
policy flag is added to allow users to opt-in to this configuration.
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2019-01-06 21:36:21 +08:00
|
|
|
fscrypt_generate_iv(&iv, 0, ci);
|
2015-04-26 15:12:50 +08:00
|
|
|
|
2016-11-14 09:35:52 +08:00
|
|
|
/* Set up the encryption request */
|
2016-01-24 21:17:49 +08:00
|
|
|
req = skcipher_request_alloc(tfm, GFP_NOFS);
|
2018-05-01 06:51:38 +08:00
|
|
|
if (!req)
|
2015-04-26 15:12:50 +08:00
|
|
|
return -ENOMEM;
|
2016-01-24 21:17:49 +08:00
|
|
|
skcipher_request_set_callback(req,
|
2015-04-26 15:12:50 +08:00
|
|
|
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
|
2017-10-18 15:00:44 +08:00
|
|
|
crypto_req_done, &wait);
|
2018-01-12 12:30:08 +08:00
|
|
|
sg_init_one(&sg, out, olen);
|
fscrypt: add Adiantum support
Add support for the Adiantum encryption mode to fscrypt. Adiantum is a
tweakable, length-preserving encryption mode with security provably
reducible to that of XChaCha12 and AES-256, subject to a security bound.
It's also a true wide-block mode, unlike XTS. See the paper
"Adiantum: length-preserving encryption for entry-level processors"
(https://eprint.iacr.org/2018/720.pdf) for more details. Also see
commit 059c2a4d8e16 ("crypto: adiantum - add Adiantum support").
On sufficiently long messages, Adiantum's bottlenecks are XChaCha12 and
the NH hash function. These algorithms are fast even on processors
without dedicated crypto instructions. Adiantum makes it feasible to
enable storage encryption on low-end mobile devices that lack AES
instructions; currently such devices are unencrypted. On ARM Cortex-A7,
on 4096-byte messages Adiantum encryption is about 4 times faster than
AES-256-XTS encryption; decryption is about 5 times faster.
In fscrypt, Adiantum is suitable for encrypting both file contents and
names. With filenames, it fixes a known weakness: when two filenames in
a directory share a common prefix of >= 16 bytes, with CTS-CBC their
encrypted filenames share a common prefix too, leaking information.
Adiantum does not have this problem.
Since Adiantum also accepts long tweaks (IVs), it's also safe to use the
master key directly for Adiantum encryption rather than deriving
per-file keys, provided that the per-file nonce is included in the IVs
and the master key isn't used for any other encryption mode. This
configuration saves memory and improves performance. A new fscrypt
policy flag is added to allow users to opt-in to this configuration.
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2019-01-06 21:36:21 +08:00
|
|
|
skcipher_request_set_crypt(req, &sg, &sg, olen, &iv);
|
2015-04-26 15:12:50 +08:00
|
|
|
|
2016-11-14 09:35:52 +08:00
|
|
|
/* Do the encryption */
|
2017-10-18 15:00:44 +08:00
|
|
|
res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
|
2016-01-24 21:17:49 +08:00
|
|
|
skcipher_request_free(req);
|
2016-09-16 05:25:55 +08:00
|
|
|
if (res < 0) {
|
2019-07-25 02:07:58 +08:00
|
|
|
fscrypt_err(inode, "Filename encryption failed: %d", res);
|
2016-09-16 05:25:55 +08:00
|
|
|
return res;
|
|
|
|
}
|
2015-05-16 07:26:10 +08:00
|
|
|
|
2016-09-16 05:25:55 +08:00
|
|
|
return 0;
|
2015-04-26 15:12:50 +08:00
|
|
|
}
|
|
|
|
|
2016-09-16 05:25:55 +08:00
|
|
|
/**
|
|
|
|
* fname_decrypt() - decrypt a filename
|
2020-05-12 03:13:56 +08:00
|
|
|
* @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().
|
2016-09-16 05:25:55 +08:00
|
|
|
*
|
|
|
|
* Return: 0 on success, -errno on failure
|
2015-04-26 15:12:50 +08:00
|
|
|
*/
|
2019-12-16 05:39:47 +08:00
|
|
|
static int fname_decrypt(const struct inode *inode,
|
|
|
|
const struct fscrypt_str *iname,
|
|
|
|
struct fscrypt_str *oname)
|
2015-04-26 15:12:50 +08:00
|
|
|
{
|
2016-01-24 21:17:49 +08:00
|
|
|
struct skcipher_request *req = NULL;
|
2017-10-18 15:00:44 +08:00
|
|
|
DECLARE_CRYPTO_WAIT(wait);
|
2015-04-26 15:12:50 +08:00
|
|
|
struct scatterlist src_sg, dst_sg;
|
2019-12-16 05:39:47 +08:00
|
|
|
const struct fscrypt_info *ci = inode->i_crypt_info;
|
2020-07-02 09:56:05 +08:00
|
|
|
struct crypto_skcipher *tfm = ci->ci_enc_key.tfm;
|
fscrypt: add Adiantum support
Add support for the Adiantum encryption mode to fscrypt. Adiantum is a
tweakable, length-preserving encryption mode with security provably
reducible to that of XChaCha12 and AES-256, subject to a security bound.
It's also a true wide-block mode, unlike XTS. See the paper
"Adiantum: length-preserving encryption for entry-level processors"
(https://eprint.iacr.org/2018/720.pdf) for more details. Also see
commit 059c2a4d8e16 ("crypto: adiantum - add Adiantum support").
On sufficiently long messages, Adiantum's bottlenecks are XChaCha12 and
the NH hash function. These algorithms are fast even on processors
without dedicated crypto instructions. Adiantum makes it feasible to
enable storage encryption on low-end mobile devices that lack AES
instructions; currently such devices are unencrypted. On ARM Cortex-A7,
on 4096-byte messages Adiantum encryption is about 4 times faster than
AES-256-XTS encryption; decryption is about 5 times faster.
In fscrypt, Adiantum is suitable for encrypting both file contents and
names. With filenames, it fixes a known weakness: when two filenames in
a directory share a common prefix of >= 16 bytes, with CTS-CBC their
encrypted filenames share a common prefix too, leaking information.
Adiantum does not have this problem.
Since Adiantum also accepts long tweaks (IVs), it's also safe to use the
master key directly for Adiantum encryption rather than deriving
per-file keys, provided that the per-file nonce is included in the IVs
and the master key isn't used for any other encryption mode. This
configuration saves memory and improves performance. A new fscrypt
policy flag is added to allow users to opt-in to this configuration.
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2019-01-06 21:36:21 +08:00
|
|
|
union fscrypt_iv iv;
|
|
|
|
int res;
|
2015-04-26 15:12:50 +08:00
|
|
|
|
|
|
|
/* Allocate request */
|
2016-01-24 21:17:49 +08:00
|
|
|
req = skcipher_request_alloc(tfm, GFP_NOFS);
|
2018-05-01 06:51:38 +08:00
|
|
|
if (!req)
|
2015-04-26 15:12:50 +08:00
|
|
|
return -ENOMEM;
|
2016-01-24 21:17:49 +08:00
|
|
|
skcipher_request_set_callback(req,
|
2015-04-26 15:12:50 +08:00
|
|
|
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
|
2017-10-18 15:00:44 +08:00
|
|
|
crypto_req_done, &wait);
|
2015-04-26 15:12:50 +08:00
|
|
|
|
|
|
|
/* Initialize IV */
|
fscrypt: add Adiantum support
Add support for the Adiantum encryption mode to fscrypt. Adiantum is a
tweakable, length-preserving encryption mode with security provably
reducible to that of XChaCha12 and AES-256, subject to a security bound.
It's also a true wide-block mode, unlike XTS. See the paper
"Adiantum: length-preserving encryption for entry-level processors"
(https://eprint.iacr.org/2018/720.pdf) for more details. Also see
commit 059c2a4d8e16 ("crypto: adiantum - add Adiantum support").
On sufficiently long messages, Adiantum's bottlenecks are XChaCha12 and
the NH hash function. These algorithms are fast even on processors
without dedicated crypto instructions. Adiantum makes it feasible to
enable storage encryption on low-end mobile devices that lack AES
instructions; currently such devices are unencrypted. On ARM Cortex-A7,
on 4096-byte messages Adiantum encryption is about 4 times faster than
AES-256-XTS encryption; decryption is about 5 times faster.
In fscrypt, Adiantum is suitable for encrypting both file contents and
names. With filenames, it fixes a known weakness: when two filenames in
a directory share a common prefix of >= 16 bytes, with CTS-CBC their
encrypted filenames share a common prefix too, leaking information.
Adiantum does not have this problem.
Since Adiantum also accepts long tweaks (IVs), it's also safe to use the
master key directly for Adiantum encryption rather than deriving
per-file keys, provided that the per-file nonce is included in the IVs
and the master key isn't used for any other encryption mode. This
configuration saves memory and improves performance. A new fscrypt
policy flag is added to allow users to opt-in to this configuration.
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2019-01-06 21:36:21 +08:00
|
|
|
fscrypt_generate_iv(&iv, 0, ci);
|
2015-04-26 15:12:50 +08:00
|
|
|
|
|
|
|
/* Create decryption request */
|
|
|
|
sg_init_one(&src_sg, iname->name, iname->len);
|
|
|
|
sg_init_one(&dst_sg, oname->name, oname->len);
|
fscrypt: add Adiantum support
Add support for the Adiantum encryption mode to fscrypt. Adiantum is a
tweakable, length-preserving encryption mode with security provably
reducible to that of XChaCha12 and AES-256, subject to a security bound.
It's also a true wide-block mode, unlike XTS. See the paper
"Adiantum: length-preserving encryption for entry-level processors"
(https://eprint.iacr.org/2018/720.pdf) for more details. Also see
commit 059c2a4d8e16 ("crypto: adiantum - add Adiantum support").
On sufficiently long messages, Adiantum's bottlenecks are XChaCha12 and
the NH hash function. These algorithms are fast even on processors
without dedicated crypto instructions. Adiantum makes it feasible to
enable storage encryption on low-end mobile devices that lack AES
instructions; currently such devices are unencrypted. On ARM Cortex-A7,
on 4096-byte messages Adiantum encryption is about 4 times faster than
AES-256-XTS encryption; decryption is about 5 times faster.
In fscrypt, Adiantum is suitable for encrypting both file contents and
names. With filenames, it fixes a known weakness: when two filenames in
a directory share a common prefix of >= 16 bytes, with CTS-CBC their
encrypted filenames share a common prefix too, leaking information.
Adiantum does not have this problem.
Since Adiantum also accepts long tweaks (IVs), it's also safe to use the
master key directly for Adiantum encryption rather than deriving
per-file keys, provided that the per-file nonce is included in the IVs
and the master key isn't used for any other encryption mode. This
configuration saves memory and improves performance. A new fscrypt
policy flag is added to allow users to opt-in to this configuration.
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2019-01-06 21:36:21 +08:00
|
|
|
skcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, &iv);
|
2017-10-18 15:00:44 +08:00
|
|
|
res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait);
|
2016-01-24 21:17:49 +08:00
|
|
|
skcipher_request_free(req);
|
2015-04-26 15:12:50 +08:00
|
|
|
if (res < 0) {
|
2019-07-25 02:07:58 +08:00
|
|
|
fscrypt_err(inode, "Filename decryption failed: %d", res);
|
2015-04-26 15:12:50 +08:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
oname->len = strnlen(oname->name, iname->len);
|
2016-09-16 05:25:55 +08:00
|
|
|
return 0;
|
2015-04-26 15:12:50 +08:00
|
|
|
}
|
|
|
|
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
static const char base64url_table[65] =
|
|
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
2015-04-26 15:12:50 +08:00
|
|
|
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
#define FSCRYPT_BASE64URL_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3)
|
2017-04-25 01:00:10 +08:00
|
|
|
|
2015-04-26 15:12:50 +08:00
|
|
|
/**
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
* 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.
|
2015-04-26 15:12:50 +08:00
|
|
|
*
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
* 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.
|
2019-07-25 02:07:58 +08:00
|
|
|
*
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
* Return: the length of the resulting base64url-encoded string in bytes.
|
|
|
|
* This will be equal to FSCRYPT_BASE64URL_CHARS(srclen).
|
2015-04-26 15:12:50 +08:00
|
|
|
*/
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
static int fscrypt_base64url_encode(const u8 *src, int srclen, char *dst)
|
2015-04-26 15:12:50 +08:00
|
|
|
{
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
u32 ac = 0;
|
|
|
|
int bits = 0;
|
|
|
|
int i;
|
2015-04-26 15:12:50 +08:00
|
|
|
char *cp = dst;
|
|
|
|
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
for (i = 0; i < srclen; i++) {
|
|
|
|
ac = (ac << 8) | src[i];
|
2015-04-26 15:12:50 +08:00
|
|
|
bits += 8;
|
|
|
|
do {
|
|
|
|
bits -= 6;
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
*cp++ = base64url_table[(ac >> bits) & 0x3f];
|
2015-04-26 15:12:50 +08:00
|
|
|
} while (bits >= 6);
|
|
|
|
}
|
|
|
|
if (bits)
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
*cp++ = base64url_table[(ac << (6 - bits)) & 0x3f];
|
2015-04-26 15:12:50 +08:00
|
|
|
return cp - dst;
|
|
|
|
}
|
|
|
|
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
/**
|
|
|
|
* 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)
|
2015-04-26 15:12:50 +08:00
|
|
|
{
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
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]);
|
2015-04-26 15:12:50 +08:00
|
|
|
|
|
|
|
if (p == NULL || src[i] == 0)
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
return -1;
|
|
|
|
ac = (ac << 6) | (p - base64url_table);
|
2015-04-26 15:12:50 +08:00
|
|
|
bits += 6;
|
|
|
|
if (bits >= 8) {
|
|
|
|
bits -= 8;
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
*bp++ = (u8)(ac >> bits);
|
2015-04-26 15:12:50 +08:00
|
|
|
}
|
|
|
|
}
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
if (ac & ((1 << bits) - 1))
|
2015-04-26 15:12:50 +08:00
|
|
|
return -1;
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
return bp - dst;
|
2015-04-26 15:12:50 +08:00
|
|
|
}
|
|
|
|
|
fscrypt: handle test_dummy_encryption in more logical way
The behavior of the test_dummy_encryption mount option is that when a
new file (or directory or symlink) is created in an unencrypted
directory, it's automatically encrypted using a dummy encryption policy.
That's it; in particular, the encryption (or lack thereof) of existing
files (or directories or symlinks) doesn't change.
Unfortunately the implementation of test_dummy_encryption is a bit weird
and confusing. When test_dummy_encryption is enabled and a file is
being created in an unencrypted directory, we set up an encryption key
(->i_crypt_info) for the directory. This isn't actually used to do any
encryption, however, since the directory is still unencrypted! Instead,
->i_crypt_info is only used for inheriting the encryption policy.
One consequence of this is that the filesystem ends up providing a
"dummy context" (policy + nonce) instead of a "dummy policy". In
commit ed318a6cc0b6 ("fscrypt: support test_dummy_encryption=v2"), I
mistakenly thought this was required. However, actually the nonce only
ends up being used to derive a key that is never used.
Another consequence of this implementation is that it allows for
'inode->i_crypt_info != NULL && !IS_ENCRYPTED(inode)', which is an edge
case that can be forgotten about. For example, currently
FS_IOC_GET_ENCRYPTION_POLICY on an unencrypted directory may return the
dummy encryption policy when the filesystem is mounted with
test_dummy_encryption. That seems like the wrong thing to do, since
again, the directory itself is not actually encrypted.
Therefore, switch to a more logical and maintainable implementation
where the dummy encryption policy inheritance is done without setting up
keys for unencrypted directories. This involves:
- Adding a function fscrypt_policy_to_inherit() which returns the
encryption policy to inherit from a directory. This can be a real
policy, a dummy policy, or no policy.
- Replacing struct fscrypt_dummy_context, ->get_dummy_context(), etc.
with struct fscrypt_dummy_policy, ->get_dummy_policy(), etc.
- Making fscrypt_fname_encrypted_size() take an fscrypt_policy instead
of an inode.
Acked-by: Jaegeuk Kim <jaegeuk@kernel.org>
Acked-by: Jeff Layton <jlayton@kernel.org>
Link: https://lore.kernel.org/r/20200917041136.178600-13-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-09-17 12:11:35 +08:00
|
|
|
bool fscrypt_fname_encrypted_size(const union fscrypt_policy *policy,
|
|
|
|
u32 orig_len, u32 max_len,
|
|
|
|
u32 *encrypted_len_ret)
|
2015-04-26 15:12:50 +08:00
|
|
|
{
|
fscrypt: handle test_dummy_encryption in more logical way
The behavior of the test_dummy_encryption mount option is that when a
new file (or directory or symlink) is created in an unencrypted
directory, it's automatically encrypted using a dummy encryption policy.
That's it; in particular, the encryption (or lack thereof) of existing
files (or directories or symlinks) doesn't change.
Unfortunately the implementation of test_dummy_encryption is a bit weird
and confusing. When test_dummy_encryption is enabled and a file is
being created in an unencrypted directory, we set up an encryption key
(->i_crypt_info) for the directory. This isn't actually used to do any
encryption, however, since the directory is still unencrypted! Instead,
->i_crypt_info is only used for inheriting the encryption policy.
One consequence of this is that the filesystem ends up providing a
"dummy context" (policy + nonce) instead of a "dummy policy". In
commit ed318a6cc0b6 ("fscrypt: support test_dummy_encryption=v2"), I
mistakenly thought this was required. However, actually the nonce only
ends up being used to derive a key that is never used.
Another consequence of this implementation is that it allows for
'inode->i_crypt_info != NULL && !IS_ENCRYPTED(inode)', which is an edge
case that can be forgotten about. For example, currently
FS_IOC_GET_ENCRYPTION_POLICY on an unencrypted directory may return the
dummy encryption policy when the filesystem is mounted with
test_dummy_encryption. That seems like the wrong thing to do, since
again, the directory itself is not actually encrypted.
Therefore, switch to a more logical and maintainable implementation
where the dummy encryption policy inheritance is done without setting up
keys for unencrypted directories. This involves:
- Adding a function fscrypt_policy_to_inherit() which returns the
encryption policy to inherit from a directory. This can be a real
policy, a dummy policy, or no policy.
- Replacing struct fscrypt_dummy_context, ->get_dummy_context(), etc.
with struct fscrypt_dummy_policy, ->get_dummy_policy(), etc.
- Making fscrypt_fname_encrypted_size() take an fscrypt_policy instead
of an inode.
Acked-by: Jaegeuk Kim <jaegeuk@kernel.org>
Acked-by: Jeff Layton <jlayton@kernel.org>
Link: https://lore.kernel.org/r/20200917041136.178600-13-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-09-17 12:11:35 +08:00
|
|
|
int padding = 4 << (fscrypt_policy_flags(policy) &
|
2019-08-05 10:35:44 +08:00
|
|
|
FSCRYPT_POLICY_FLAGS_PAD_MASK);
|
2018-01-12 12:30:08 +08:00
|
|
|
u32 encrypted_len;
|
|
|
|
|
|
|
|
if (orig_len > max_len)
|
|
|
|
return false;
|
|
|
|
encrypted_len = max(orig_len, (u32)FS_CRYPTO_BLOCK_SIZE);
|
|
|
|
encrypted_len = round_up(encrypted_len, padding);
|
|
|
|
*encrypted_len_ret = min(encrypted_len, max_len);
|
|
|
|
return true;
|
2015-04-26 15:12:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-05-12 03:13:56 +08:00
|
|
|
* fscrypt_fname_alloc_buffer() - allocate a buffer for presented filenames
|
|
|
|
* @max_encrypted_len: maximum length of encrypted filenames the buffer will be
|
|
|
|
* used to present
|
|
|
|
* @crypto_str: (output) buffer to allocate
|
2015-04-26 15:12:50 +08:00
|
|
|
*
|
2018-01-12 12:30:08 +08:00
|
|
|
* Allocate a buffer that is large enough to hold any decrypted or encoded
|
|
|
|
* filename (null-terminated), for the given maximum encrypted filename length.
|
|
|
|
*
|
|
|
|
* Return: 0 on success, -errno on failure
|
2015-04-26 15:12:50 +08:00
|
|
|
*/
|
2020-08-10 22:21:39 +08:00
|
|
|
int fscrypt_fname_alloc_buffer(u32 max_encrypted_len,
|
2018-01-12 12:30:08 +08:00
|
|
|
struct fscrypt_str *crypto_str)
|
2015-04-26 15:12:50 +08:00
|
|
|
{
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
u32 max_presented_len = max_t(u32, FSCRYPT_NOKEY_NAME_MAX_ENCODED,
|
|
|
|
max_encrypted_len);
|
2017-04-25 01:00:10 +08:00
|
|
|
|
2018-01-12 12:30:08 +08:00
|
|
|
crypto_str->name = kmalloc(max_presented_len + 1, GFP_NOFS);
|
|
|
|
if (!crypto_str->name)
|
2015-04-26 15:12:50 +08:00
|
|
|
return -ENOMEM;
|
2018-01-12 12:30:08 +08:00
|
|
|
crypto_str->len = max_presented_len;
|
2015-04-26 15:12:50 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2015-05-16 07:26:10 +08:00
|
|
|
EXPORT_SYMBOL(fscrypt_fname_alloc_buffer);
|
2015-04-26 15:12:50 +08:00
|
|
|
|
|
|
|
/**
|
2020-05-12 03:13:56 +08:00
|
|
|
* fscrypt_fname_free_buffer() - free a buffer for presented filenames
|
|
|
|
* @crypto_str: the buffer to free
|
2015-04-26 15:12:50 +08:00
|
|
|
*
|
2020-05-12 03:13:56 +08:00
|
|
|
* Free a buffer that was allocated by fscrypt_fname_alloc_buffer().
|
2015-04-26 15:12:50 +08:00
|
|
|
*/
|
2015-05-16 07:26:10 +08:00
|
|
|
void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str)
|
2015-04-26 15:12:50 +08:00
|
|
|
{
|
|
|
|
if (!crypto_str)
|
|
|
|
return;
|
|
|
|
kfree(crypto_str->name);
|
|
|
|
crypto_str->name = NULL;
|
|
|
|
}
|
2015-05-16 07:26:10 +08:00
|
|
|
EXPORT_SYMBOL(fscrypt_fname_free_buffer);
|
2015-04-26 15:12:50 +08:00
|
|
|
|
|
|
|
/**
|
2020-05-12 03:13:56 +08:00
|
|
|
* fscrypt_fname_disk_to_usr() - convert an encrypted filename to
|
|
|
|
* user-presentable form
|
|
|
|
* @inode: inode of the parent directory (for regular filenames)
|
|
|
|
* or of the symlink (for symlink targets)
|
|
|
|
* @hash: first part of the name's dirhash, if applicable. This only needs to
|
|
|
|
* be provided if the filename is located in an indexed directory whose
|
|
|
|
* encryption key may be unavailable. Not needed for symlink targets.
|
|
|
|
* @minor_hash: second part of the name's dirhash, if applicable
|
|
|
|
* @iname: encrypted filename to convert. May also be "." or "..", which
|
|
|
|
* aren't actually encrypted.
|
|
|
|
* @oname: output buffer for the user-presentable filename. The caller must
|
|
|
|
* have allocated enough space for this, e.g. using
|
|
|
|
* fscrypt_fname_alloc_buffer().
|
2016-09-16 05:25:55 +08:00
|
|
|
*
|
fscrypt: improve format of no-key names
When an encrypted directory is listed without the key, the filesystem
must show "no-key names" that uniquely identify directory entries, are
at most 255 (NAME_MAX) bytes long, and don't contain '/' or '\0'.
Currently, for short names the no-key name is the base64 encoding of the
ciphertext filename, while for long names it's the base64 encoding of
the ciphertext filename's dirhash and second-to-last 16-byte block.
This format has the following problems:
- Since it doesn't always include the dirhash, it's incompatible with
directories that will use a secret-keyed dirhash over the plaintext
filenames. In this case, the dirhash won't be computable from the
ciphertext name without the key, so it instead must be retrieved from
the directory entry and always included in the no-key name.
Casefolded encrypted directories will use this type of dirhash.
- It's ambiguous: it's possible to craft two filenames that map to the
same no-key name, since the method used to abbreviate long filenames
doesn't use a proper cryptographic hash function.
Solve both these problems by switching to a new no-key name format that
is the base64 encoding of a variable-length structure that contains the
dirhash, up to 149 bytes of the ciphertext filename, and (if any bytes
remain) the SHA-256 of the remaining bytes of the ciphertext filename.
This ensures that each no-key name contains everything needed to find
the directory entry again, contains only legal characters, doesn't
exceed NAME_MAX, is unambiguous unless there's a SHA-256 collision, and
that we only take the performance hit of SHA-256 on very long filenames.
Note: this change does *not* address the existing issue where users can
modify the 'dirhash' part of a no-key name and the filesystem may still
accept the name.
Signed-off-by: Daniel Rosenberg <drosen@google.com>
[EB: improved comments and commit message, fixed checking return value
of base64_decode(), check for SHA-256 error, continue to set disk_name
for short names to keep matching simpler, and many other cleanups]
Link: https://lore.kernel.org/r/20200120223201.241390-7-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-01-21 06:32:01 +08:00
|
|
|
* If the key is available, we'll decrypt the disk name. Otherwise, we'll
|
|
|
|
* encode it for presentation in fscrypt_nokey_name format.
|
|
|
|
* See struct fscrypt_nokey_name for details.
|
2017-04-25 01:00:10 +08:00
|
|
|
*
|
2016-09-16 05:25:55 +08:00
|
|
|
* Return: 0 on success, -errno on failure
|
2015-04-26 15:12:50 +08:00
|
|
|
*/
|
2019-12-16 05:39:47 +08:00
|
|
|
int fscrypt_fname_disk_to_usr(const struct inode *inode,
|
|
|
|
u32 hash, u32 minor_hash,
|
|
|
|
const struct fscrypt_str *iname,
|
|
|
|
struct fscrypt_str *oname)
|
2015-04-26 15:12:50 +08:00
|
|
|
{
|
|
|
|
const struct qstr qname = FSTR_TO_QSTR(iname);
|
fscrypt: improve format of no-key names
When an encrypted directory is listed without the key, the filesystem
must show "no-key names" that uniquely identify directory entries, are
at most 255 (NAME_MAX) bytes long, and don't contain '/' or '\0'.
Currently, for short names the no-key name is the base64 encoding of the
ciphertext filename, while for long names it's the base64 encoding of
the ciphertext filename's dirhash and second-to-last 16-byte block.
This format has the following problems:
- Since it doesn't always include the dirhash, it's incompatible with
directories that will use a secret-keyed dirhash over the plaintext
filenames. In this case, the dirhash won't be computable from the
ciphertext name without the key, so it instead must be retrieved from
the directory entry and always included in the no-key name.
Casefolded encrypted directories will use this type of dirhash.
- It's ambiguous: it's possible to craft two filenames that map to the
same no-key name, since the method used to abbreviate long filenames
doesn't use a proper cryptographic hash function.
Solve both these problems by switching to a new no-key name format that
is the base64 encoding of a variable-length structure that contains the
dirhash, up to 149 bytes of the ciphertext filename, and (if any bytes
remain) the SHA-256 of the remaining bytes of the ciphertext filename.
This ensures that each no-key name contains everything needed to find
the directory entry again, contains only legal characters, doesn't
exceed NAME_MAX, is unambiguous unless there's a SHA-256 collision, and
that we only take the performance hit of SHA-256 on very long filenames.
Note: this change does *not* address the existing issue where users can
modify the 'dirhash' part of a no-key name and the filesystem may still
accept the name.
Signed-off-by: Daniel Rosenberg <drosen@google.com>
[EB: improved comments and commit message, fixed checking return value
of base64_decode(), check for SHA-256 error, continue to set disk_name
for short names to keep matching simpler, and many other cleanups]
Link: https://lore.kernel.org/r/20200120223201.241390-7-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-01-21 06:32:01 +08:00
|
|
|
struct fscrypt_nokey_name nokey_name;
|
|
|
|
u32 size; /* size of the unencoded no-key name */
|
2015-04-26 15:12:50 +08:00
|
|
|
|
2015-05-16 07:26:10 +08:00
|
|
|
if (fscrypt_is_dot_dotdot(&qname)) {
|
2015-04-26 15:12:50 +08:00
|
|
|
oname->name[0] = '.';
|
|
|
|
oname->name[iname->len - 1] = '.';
|
|
|
|
oname->len = iname->len;
|
2016-09-16 05:25:55 +08:00
|
|
|
return 0;
|
2015-04-26 15:12:50 +08:00
|
|
|
}
|
|
|
|
|
2015-05-16 07:26:10 +08:00
|
|
|
if (iname->len < FS_CRYPTO_BLOCK_SIZE)
|
2016-02-06 11:37:27 +08:00
|
|
|
return -EUCLEAN;
|
2015-04-26 15:12:50 +08:00
|
|
|
|
2019-04-12 05:32:15 +08:00
|
|
|
if (fscrypt_has_encryption_key(inode))
|
2015-05-16 07:26:10 +08:00
|
|
|
return fname_decrypt(inode, iname, oname);
|
|
|
|
|
fscrypt: improve format of no-key names
When an encrypted directory is listed without the key, the filesystem
must show "no-key names" that uniquely identify directory entries, are
at most 255 (NAME_MAX) bytes long, and don't contain '/' or '\0'.
Currently, for short names the no-key name is the base64 encoding of the
ciphertext filename, while for long names it's the base64 encoding of
the ciphertext filename's dirhash and second-to-last 16-byte block.
This format has the following problems:
- Since it doesn't always include the dirhash, it's incompatible with
directories that will use a secret-keyed dirhash over the plaintext
filenames. In this case, the dirhash won't be computable from the
ciphertext name without the key, so it instead must be retrieved from
the directory entry and always included in the no-key name.
Casefolded encrypted directories will use this type of dirhash.
- It's ambiguous: it's possible to craft two filenames that map to the
same no-key name, since the method used to abbreviate long filenames
doesn't use a proper cryptographic hash function.
Solve both these problems by switching to a new no-key name format that
is the base64 encoding of a variable-length structure that contains the
dirhash, up to 149 bytes of the ciphertext filename, and (if any bytes
remain) the SHA-256 of the remaining bytes of the ciphertext filename.
This ensures that each no-key name contains everything needed to find
the directory entry again, contains only legal characters, doesn't
exceed NAME_MAX, is unambiguous unless there's a SHA-256 collision, and
that we only take the performance hit of SHA-256 on very long filenames.
Note: this change does *not* address the existing issue where users can
modify the 'dirhash' part of a no-key name and the filesystem may still
accept the name.
Signed-off-by: Daniel Rosenberg <drosen@google.com>
[EB: improved comments and commit message, fixed checking return value
of base64_decode(), check for SHA-256 error, continue to set disk_name
for short names to keep matching simpler, and many other cleanups]
Link: https://lore.kernel.org/r/20200120223201.241390-7-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-01-21 06:32:01 +08:00
|
|
|
/*
|
|
|
|
* Sanity check that struct fscrypt_nokey_name doesn't have padding
|
|
|
|
* between fields and that its encoded size never exceeds NAME_MAX.
|
|
|
|
*/
|
|
|
|
BUILD_BUG_ON(offsetofend(struct fscrypt_nokey_name, dirhash) !=
|
|
|
|
offsetof(struct fscrypt_nokey_name, bytes));
|
|
|
|
BUILD_BUG_ON(offsetofend(struct fscrypt_nokey_name, bytes) !=
|
|
|
|
offsetof(struct fscrypt_nokey_name, sha256));
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
BUILD_BUG_ON(FSCRYPT_NOKEY_NAME_MAX_ENCODED > NAME_MAX);
|
fscrypt: improve format of no-key names
When an encrypted directory is listed without the key, the filesystem
must show "no-key names" that uniquely identify directory entries, are
at most 255 (NAME_MAX) bytes long, and don't contain '/' or '\0'.
Currently, for short names the no-key name is the base64 encoding of the
ciphertext filename, while for long names it's the base64 encoding of
the ciphertext filename's dirhash and second-to-last 16-byte block.
This format has the following problems:
- Since it doesn't always include the dirhash, it's incompatible with
directories that will use a secret-keyed dirhash over the plaintext
filenames. In this case, the dirhash won't be computable from the
ciphertext name without the key, so it instead must be retrieved from
the directory entry and always included in the no-key name.
Casefolded encrypted directories will use this type of dirhash.
- It's ambiguous: it's possible to craft two filenames that map to the
same no-key name, since the method used to abbreviate long filenames
doesn't use a proper cryptographic hash function.
Solve both these problems by switching to a new no-key name format that
is the base64 encoding of a variable-length structure that contains the
dirhash, up to 149 bytes of the ciphertext filename, and (if any bytes
remain) the SHA-256 of the remaining bytes of the ciphertext filename.
This ensures that each no-key name contains everything needed to find
the directory entry again, contains only legal characters, doesn't
exceed NAME_MAX, is unambiguous unless there's a SHA-256 collision, and
that we only take the performance hit of SHA-256 on very long filenames.
Note: this change does *not* address the existing issue where users can
modify the 'dirhash' part of a no-key name and the filesystem may still
accept the name.
Signed-off-by: Daniel Rosenberg <drosen@google.com>
[EB: improved comments and commit message, fixed checking return value
of base64_decode(), check for SHA-256 error, continue to set disk_name
for short names to keep matching simpler, and many other cleanups]
Link: https://lore.kernel.org/r/20200120223201.241390-7-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-01-21 06:32:01 +08:00
|
|
|
|
2021-05-28 07:52:36 +08:00
|
|
|
nokey_name.dirhash[0] = hash;
|
|
|
|
nokey_name.dirhash[1] = minor_hash;
|
|
|
|
|
fscrypt: improve format of no-key names
When an encrypted directory is listed without the key, the filesystem
must show "no-key names" that uniquely identify directory entries, are
at most 255 (NAME_MAX) bytes long, and don't contain '/' or '\0'.
Currently, for short names the no-key name is the base64 encoding of the
ciphertext filename, while for long names it's the base64 encoding of
the ciphertext filename's dirhash and second-to-last 16-byte block.
This format has the following problems:
- Since it doesn't always include the dirhash, it's incompatible with
directories that will use a secret-keyed dirhash over the plaintext
filenames. In this case, the dirhash won't be computable from the
ciphertext name without the key, so it instead must be retrieved from
the directory entry and always included in the no-key name.
Casefolded encrypted directories will use this type of dirhash.
- It's ambiguous: it's possible to craft two filenames that map to the
same no-key name, since the method used to abbreviate long filenames
doesn't use a proper cryptographic hash function.
Solve both these problems by switching to a new no-key name format that
is the base64 encoding of a variable-length structure that contains the
dirhash, up to 149 bytes of the ciphertext filename, and (if any bytes
remain) the SHA-256 of the remaining bytes of the ciphertext filename.
This ensures that each no-key name contains everything needed to find
the directory entry again, contains only legal characters, doesn't
exceed NAME_MAX, is unambiguous unless there's a SHA-256 collision, and
that we only take the performance hit of SHA-256 on very long filenames.
Note: this change does *not* address the existing issue where users can
modify the 'dirhash' part of a no-key name and the filesystem may still
accept the name.
Signed-off-by: Daniel Rosenberg <drosen@google.com>
[EB: improved comments and commit message, fixed checking return value
of base64_decode(), check for SHA-256 error, continue to set disk_name
for short names to keep matching simpler, and many other cleanups]
Link: https://lore.kernel.org/r/20200120223201.241390-7-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-01-21 06:32:01 +08:00
|
|
|
if (iname->len <= sizeof(nokey_name.bytes)) {
|
|
|
|
memcpy(nokey_name.bytes, iname->name, iname->len);
|
|
|
|
size = offsetof(struct fscrypt_nokey_name, bytes[iname->len]);
|
|
|
|
} else {
|
|
|
|
memcpy(nokey_name.bytes, iname->name, sizeof(nokey_name.bytes));
|
|
|
|
/* Compute strong hash of remaining part of name. */
|
2020-09-17 12:53:41 +08:00
|
|
|
sha256(&iname->name[sizeof(nokey_name.bytes)],
|
|
|
|
iname->len - sizeof(nokey_name.bytes),
|
|
|
|
nokey_name.sha256);
|
fscrypt: improve format of no-key names
When an encrypted directory is listed without the key, the filesystem
must show "no-key names" that uniquely identify directory entries, are
at most 255 (NAME_MAX) bytes long, and don't contain '/' or '\0'.
Currently, for short names the no-key name is the base64 encoding of the
ciphertext filename, while for long names it's the base64 encoding of
the ciphertext filename's dirhash and second-to-last 16-byte block.
This format has the following problems:
- Since it doesn't always include the dirhash, it's incompatible with
directories that will use a secret-keyed dirhash over the plaintext
filenames. In this case, the dirhash won't be computable from the
ciphertext name without the key, so it instead must be retrieved from
the directory entry and always included in the no-key name.
Casefolded encrypted directories will use this type of dirhash.
- It's ambiguous: it's possible to craft two filenames that map to the
same no-key name, since the method used to abbreviate long filenames
doesn't use a proper cryptographic hash function.
Solve both these problems by switching to a new no-key name format that
is the base64 encoding of a variable-length structure that contains the
dirhash, up to 149 bytes of the ciphertext filename, and (if any bytes
remain) the SHA-256 of the remaining bytes of the ciphertext filename.
This ensures that each no-key name contains everything needed to find
the directory entry again, contains only legal characters, doesn't
exceed NAME_MAX, is unambiguous unless there's a SHA-256 collision, and
that we only take the performance hit of SHA-256 on very long filenames.
Note: this change does *not* address the existing issue where users can
modify the 'dirhash' part of a no-key name and the filesystem may still
accept the name.
Signed-off-by: Daniel Rosenberg <drosen@google.com>
[EB: improved comments and commit message, fixed checking return value
of base64_decode(), check for SHA-256 error, continue to set disk_name
for short names to keep matching simpler, and many other cleanups]
Link: https://lore.kernel.org/r/20200120223201.241390-7-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-01-21 06:32:01 +08:00
|
|
|
size = FSCRYPT_NOKEY_NAME_MAX;
|
|
|
|
}
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
oname->len = fscrypt_base64url_encode((const u8 *)&nokey_name, size,
|
|
|
|
oname->name);
|
2016-09-16 05:25:55 +08:00
|
|
|
return 0;
|
2015-04-26 15:12:50 +08:00
|
|
|
}
|
2015-05-16 07:26:10 +08:00
|
|
|
EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
|
2015-04-26 15:12:50 +08:00
|
|
|
|
2017-04-25 01:00:10 +08:00
|
|
|
/**
|
|
|
|
* fscrypt_setup_filename() - prepare to search a possibly encrypted directory
|
|
|
|
* @dir: the directory that will be searched
|
|
|
|
* @iname: the user-provided filename being searched for
|
|
|
|
* @lookup: 1 if we're allowed to proceed without the key because it's
|
|
|
|
* ->lookup() or we're finding the dir_entry for deletion; 0 if we cannot
|
|
|
|
* proceed without the key because we're going to create the dir_entry.
|
|
|
|
* @fname: the filename information to be filled in
|
|
|
|
*
|
|
|
|
* Given a user-provided filename @iname, this function sets @fname->disk_name
|
|
|
|
* to the name that would be stored in the on-disk directory entry, if possible.
|
|
|
|
* If the directory is unencrypted this is simply @iname. Else, if we have the
|
|
|
|
* directory's encryption key, then @iname is the plaintext, so we encrypt it to
|
|
|
|
* get the disk_name.
|
|
|
|
*
|
2020-09-24 12:26:23 +08:00
|
|
|
* Else, for keyless @lookup operations, @iname should be a no-key name, so we
|
|
|
|
* decode it to get the struct fscrypt_nokey_name. Non-@lookup operations will
|
|
|
|
* be impossible in this case, so we fail them with ENOKEY.
|
2017-04-25 01:00:10 +08:00
|
|
|
*
|
|
|
|
* If successful, fscrypt_free_filename() must be called later to clean up.
|
|
|
|
*
|
|
|
|
* Return: 0 on success, -errno on failure
|
|
|
|
*/
|
2015-05-16 07:26:10 +08:00
|
|
|
int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
|
|
|
|
int lookup, struct fscrypt_name *fname)
|
2015-04-26 15:12:50 +08:00
|
|
|
{
|
fscrypt: improve format of no-key names
When an encrypted directory is listed without the key, the filesystem
must show "no-key names" that uniquely identify directory entries, are
at most 255 (NAME_MAX) bytes long, and don't contain '/' or '\0'.
Currently, for short names the no-key name is the base64 encoding of the
ciphertext filename, while for long names it's the base64 encoding of
the ciphertext filename's dirhash and second-to-last 16-byte block.
This format has the following problems:
- Since it doesn't always include the dirhash, it's incompatible with
directories that will use a secret-keyed dirhash over the plaintext
filenames. In this case, the dirhash won't be computable from the
ciphertext name without the key, so it instead must be retrieved from
the directory entry and always included in the no-key name.
Casefolded encrypted directories will use this type of dirhash.
- It's ambiguous: it's possible to craft two filenames that map to the
same no-key name, since the method used to abbreviate long filenames
doesn't use a proper cryptographic hash function.
Solve both these problems by switching to a new no-key name format that
is the base64 encoding of a variable-length structure that contains the
dirhash, up to 149 bytes of the ciphertext filename, and (if any bytes
remain) the SHA-256 of the remaining bytes of the ciphertext filename.
This ensures that each no-key name contains everything needed to find
the directory entry again, contains only legal characters, doesn't
exceed NAME_MAX, is unambiguous unless there's a SHA-256 collision, and
that we only take the performance hit of SHA-256 on very long filenames.
Note: this change does *not* address the existing issue where users can
modify the 'dirhash' part of a no-key name and the filesystem may still
accept the name.
Signed-off-by: Daniel Rosenberg <drosen@google.com>
[EB: improved comments and commit message, fixed checking return value
of base64_decode(), check for SHA-256 error, continue to set disk_name
for short names to keep matching simpler, and many other cleanups]
Link: https://lore.kernel.org/r/20200120223201.241390-7-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-01-21 06:32:01 +08:00
|
|
|
struct fscrypt_nokey_name *nokey_name;
|
2017-04-25 01:00:10 +08:00
|
|
|
int ret;
|
2015-04-26 15:12:50 +08:00
|
|
|
|
2015-05-16 07:26:10 +08:00
|
|
|
memset(fname, 0, sizeof(struct fscrypt_name));
|
2015-04-26 15:12:50 +08:00
|
|
|
fname->usr_fname = iname;
|
|
|
|
|
2017-10-10 03:15:36 +08:00
|
|
|
if (!IS_ENCRYPTED(dir) || fscrypt_is_dot_dotdot(iname)) {
|
2015-04-26 15:12:50 +08:00
|
|
|
fname->disk_name.name = (unsigned char *)iname->name;
|
|
|
|
fname->disk_name.len = iname->len;
|
2015-05-13 18:20:54 +08:00
|
|
|
return 0;
|
2015-04-26 15:12:50 +08:00
|
|
|
}
|
fscrypt: allow deleting files with unsupported encryption policy
Currently it's impossible to delete files that use an unsupported
encryption policy, as the kernel will just return an error when
performing any operation on the top-level encrypted directory, even just
a path lookup into the directory or opening the directory for readdir.
More specifically, this occurs in any of the following cases:
- The encryption context has an unrecognized version number. Current
kernels know about v1 and v2, but there could be more versions in the
future.
- The encryption context has unrecognized encryption modes
(FSCRYPT_MODE_*) or flags (FSCRYPT_POLICY_FLAG_*), an unrecognized
combination of modes, or reserved bits set.
- The encryption key has been added and the encryption modes are
recognized but aren't available in the crypto API -- for example, a
directory is encrypted with FSCRYPT_MODE_ADIANTUM but the kernel
doesn't have CONFIG_CRYPTO_ADIANTUM enabled.
It's desirable to return errors for most operations on files that use an
unsupported encryption policy, but the current behavior is too strict.
We need to allow enough to delete files, so that people can't be stuck
with undeletable files when downgrading kernel versions. That includes
allowing directories to be listed and allowing dentries to be looked up.
Fix this by modifying the key setup logic to treat an unsupported
encryption policy in the same way as "key unavailable" in the cases that
are required for a recursive delete to work: preparing for a readdir or
a dentry lookup, revalidating a dentry, or checking whether an inode has
the same encryption policy as its parent directory.
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
Link: https://lore.kernel.org/r/20201203022041.230976-10-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-12-03 10:20:41 +08:00
|
|
|
ret = fscrypt_get_encryption_info(dir, lookup);
|
2018-05-01 06:51:41 +08:00
|
|
|
if (ret)
|
2015-04-26 15:12:50 +08:00
|
|
|
return ret;
|
2015-05-16 07:26:10 +08:00
|
|
|
|
2019-04-12 05:32:15 +08:00
|
|
|
if (fscrypt_has_encryption_key(dir)) {
|
fscrypt: handle test_dummy_encryption in more logical way
The behavior of the test_dummy_encryption mount option is that when a
new file (or directory or symlink) is created in an unencrypted
directory, it's automatically encrypted using a dummy encryption policy.
That's it; in particular, the encryption (or lack thereof) of existing
files (or directories or symlinks) doesn't change.
Unfortunately the implementation of test_dummy_encryption is a bit weird
and confusing. When test_dummy_encryption is enabled and a file is
being created in an unencrypted directory, we set up an encryption key
(->i_crypt_info) for the directory. This isn't actually used to do any
encryption, however, since the directory is still unencrypted! Instead,
->i_crypt_info is only used for inheriting the encryption policy.
One consequence of this is that the filesystem ends up providing a
"dummy context" (policy + nonce) instead of a "dummy policy". In
commit ed318a6cc0b6 ("fscrypt: support test_dummy_encryption=v2"), I
mistakenly thought this was required. However, actually the nonce only
ends up being used to derive a key that is never used.
Another consequence of this implementation is that it allows for
'inode->i_crypt_info != NULL && !IS_ENCRYPTED(inode)', which is an edge
case that can be forgotten about. For example, currently
FS_IOC_GET_ENCRYPTION_POLICY on an unencrypted directory may return the
dummy encryption policy when the filesystem is mounted with
test_dummy_encryption. That seems like the wrong thing to do, since
again, the directory itself is not actually encrypted.
Therefore, switch to a more logical and maintainable implementation
where the dummy encryption policy inheritance is done without setting up
keys for unencrypted directories. This involves:
- Adding a function fscrypt_policy_to_inherit() which returns the
encryption policy to inherit from a directory. This can be a real
policy, a dummy policy, or no policy.
- Replacing struct fscrypt_dummy_context, ->get_dummy_context(), etc.
with struct fscrypt_dummy_policy, ->get_dummy_policy(), etc.
- Making fscrypt_fname_encrypted_size() take an fscrypt_policy instead
of an inode.
Acked-by: Jaegeuk Kim <jaegeuk@kernel.org>
Acked-by: Jeff Layton <jlayton@kernel.org>
Link: https://lore.kernel.org/r/20200917041136.178600-13-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-09-17 12:11:35 +08:00
|
|
|
if (!fscrypt_fname_encrypted_size(&dir->i_crypt_info->ci_policy,
|
2021-09-10 02:45:13 +08:00
|
|
|
iname->len, NAME_MAX,
|
2018-01-12 12:30:08 +08:00
|
|
|
&fname->crypto_buf.len))
|
2018-01-12 12:30:08 +08:00
|
|
|
return -ENAMETOOLONG;
|
|
|
|
fname->crypto_buf.name = kmalloc(fname->crypto_buf.len,
|
|
|
|
GFP_NOFS);
|
|
|
|
if (!fname->crypto_buf.name)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2020-01-20 15:17:36 +08:00
|
|
|
ret = fscrypt_fname_encrypt(dir, iname, fname->crypto_buf.name,
|
|
|
|
fname->crypto_buf.len);
|
2016-09-16 05:25:55 +08:00
|
|
|
if (ret)
|
2015-05-29 08:06:40 +08:00
|
|
|
goto errout;
|
2015-04-26 15:12:50 +08:00
|
|
|
fname->disk_name.name = fname->crypto_buf.name;
|
|
|
|
fname->disk_name.len = fname->crypto_buf.len;
|
2015-05-13 18:20:54 +08:00
|
|
|
return 0;
|
2015-04-26 15:12:50 +08:00
|
|
|
}
|
2015-05-29 08:06:40 +08:00
|
|
|
if (!lookup)
|
2016-12-06 03:12:44 +08:00
|
|
|
return -ENOKEY;
|
2020-09-24 12:26:23 +08:00
|
|
|
fname->is_nokey_name = true;
|
2015-04-26 15:12:50 +08:00
|
|
|
|
2015-05-16 07:26:10 +08:00
|
|
|
/*
|
|
|
|
* We don't have the key and we are doing a lookup; decode the
|
2015-04-26 15:12:50 +08:00
|
|
|
* user-supplied name
|
|
|
|
*/
|
2015-05-29 08:06:40 +08:00
|
|
|
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
if (iname->len > FSCRYPT_NOKEY_NAME_MAX_ENCODED)
|
fscrypt: improve format of no-key names
When an encrypted directory is listed without the key, the filesystem
must show "no-key names" that uniquely identify directory entries, are
at most 255 (NAME_MAX) bytes long, and don't contain '/' or '\0'.
Currently, for short names the no-key name is the base64 encoding of the
ciphertext filename, while for long names it's the base64 encoding of
the ciphertext filename's dirhash and second-to-last 16-byte block.
This format has the following problems:
- Since it doesn't always include the dirhash, it's incompatible with
directories that will use a secret-keyed dirhash over the plaintext
filenames. In this case, the dirhash won't be computable from the
ciphertext name without the key, so it instead must be retrieved from
the directory entry and always included in the no-key name.
Casefolded encrypted directories will use this type of dirhash.
- It's ambiguous: it's possible to craft two filenames that map to the
same no-key name, since the method used to abbreviate long filenames
doesn't use a proper cryptographic hash function.
Solve both these problems by switching to a new no-key name format that
is the base64 encoding of a variable-length structure that contains the
dirhash, up to 149 bytes of the ciphertext filename, and (if any bytes
remain) the SHA-256 of the remaining bytes of the ciphertext filename.
This ensures that each no-key name contains everything needed to find
the directory entry again, contains only legal characters, doesn't
exceed NAME_MAX, is unambiguous unless there's a SHA-256 collision, and
that we only take the performance hit of SHA-256 on very long filenames.
Note: this change does *not* address the existing issue where users can
modify the 'dirhash' part of a no-key name and the filesystem may still
accept the name.
Signed-off-by: Daniel Rosenberg <drosen@google.com>
[EB: improved comments and commit message, fixed checking return value
of base64_decode(), check for SHA-256 error, continue to set disk_name
for short names to keep matching simpler, and many other cleanups]
Link: https://lore.kernel.org/r/20200120223201.241390-7-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-01-21 06:32:01 +08:00
|
|
|
return -ENOENT;
|
|
|
|
|
|
|
|
fname->crypto_buf.name = kmalloc(FSCRYPT_NOKEY_NAME_MAX, GFP_KERNEL);
|
2015-05-29 08:06:40 +08:00
|
|
|
if (fname->crypto_buf.name == NULL)
|
|
|
|
return -ENOMEM;
|
2015-05-16 07:26:10 +08:00
|
|
|
|
fscrypt: align Base64 encoding with RFC 4648 base64url
fscrypt uses a Base64 encoding to encode no-key filenames (the filenames
that are presented to userspace when a directory is listed without its
encryption key). There are many variants of Base64, but the most common
ones are specified by RFC 4648. fscrypt can't use the regular RFC 4648
"base64" variant because "base64" uses the '/' character, which isn't
allowed in filenames. However, RFC 4648 also specifies a "base64url"
variant for use in URLs and filenames. "base64url" is less common than
"base64", but it's still implemented in many programming libraries.
Unfortunately, what fscrypt actually uses is a custom Base64 variant
that differs from "base64url" in several ways:
- The binary data is divided into 6-bit chunks differently.
- Values 62 and 63 are encoded with '+' and ',' instead of '-' and '_'.
- '='-padding isn't used. This isn't a problem per se, as the padding
isn't technically necessary, and RFC 4648 doesn't strictly require it.
But it needs to be properly documented.
There have been two attempts to copy the fscrypt Base64 code into lib/
(https://lkml.kernel.org/r/20200821182813.52570-6-jlayton@kernel.org and
https://lkml.kernel.org/r/20210716110428.9727-5-hare@suse.de), and both
have been caught up by the fscrypt Base64 variant being nonstandard and
not properly documented. Also, the planned use of the fscrypt Base64
code in the CephFS storage back-end will prevent it from being changed
later (whereas currently it can still be changed), so we need to choose
an encoding that we're happy with before it's too late.
Therefore, switch the fscrypt Base64 variant to base64url, in order to
align more closely with RFC 4648 and other implementations and uses of
Base64. However, I opted not to implement '='-padding, as '='-padding
adds complexity, is unnecessary, and isn't required by the RFC.
Link: https://lore.kernel.org/r/20210718000125.59701-1-ebiggers@kernel.org
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-07-18 08:01:25 +08:00
|
|
|
ret = fscrypt_base64url_decode(iname->name, iname->len,
|
|
|
|
fname->crypto_buf.name);
|
fscrypt: improve format of no-key names
When an encrypted directory is listed without the key, the filesystem
must show "no-key names" that uniquely identify directory entries, are
at most 255 (NAME_MAX) bytes long, and don't contain '/' or '\0'.
Currently, for short names the no-key name is the base64 encoding of the
ciphertext filename, while for long names it's the base64 encoding of
the ciphertext filename's dirhash and second-to-last 16-byte block.
This format has the following problems:
- Since it doesn't always include the dirhash, it's incompatible with
directories that will use a secret-keyed dirhash over the plaintext
filenames. In this case, the dirhash won't be computable from the
ciphertext name without the key, so it instead must be retrieved from
the directory entry and always included in the no-key name.
Casefolded encrypted directories will use this type of dirhash.
- It's ambiguous: it's possible to craft two filenames that map to the
same no-key name, since the method used to abbreviate long filenames
doesn't use a proper cryptographic hash function.
Solve both these problems by switching to a new no-key name format that
is the base64 encoding of a variable-length structure that contains the
dirhash, up to 149 bytes of the ciphertext filename, and (if any bytes
remain) the SHA-256 of the remaining bytes of the ciphertext filename.
This ensures that each no-key name contains everything needed to find
the directory entry again, contains only legal characters, doesn't
exceed NAME_MAX, is unambiguous unless there's a SHA-256 collision, and
that we only take the performance hit of SHA-256 on very long filenames.
Note: this change does *not* address the existing issue where users can
modify the 'dirhash' part of a no-key name and the filesystem may still
accept the name.
Signed-off-by: Daniel Rosenberg <drosen@google.com>
[EB: improved comments and commit message, fixed checking return value
of base64_decode(), check for SHA-256 error, continue to set disk_name
for short names to keep matching simpler, and many other cleanups]
Link: https://lore.kernel.org/r/20200120223201.241390-7-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-01-21 06:32:01 +08:00
|
|
|
if (ret < (int)offsetof(struct fscrypt_nokey_name, bytes[1]) ||
|
|
|
|
(ret > offsetof(struct fscrypt_nokey_name, sha256) &&
|
|
|
|
ret != FSCRYPT_NOKEY_NAME_MAX)) {
|
2015-04-26 15:12:50 +08:00
|
|
|
ret = -ENOENT;
|
2015-05-29 08:06:40 +08:00
|
|
|
goto errout;
|
2015-04-26 15:12:50 +08:00
|
|
|
}
|
|
|
|
fname->crypto_buf.len = ret;
|
fscrypt: improve format of no-key names
When an encrypted directory is listed without the key, the filesystem
must show "no-key names" that uniquely identify directory entries, are
at most 255 (NAME_MAX) bytes long, and don't contain '/' or '\0'.
Currently, for short names the no-key name is the base64 encoding of the
ciphertext filename, while for long names it's the base64 encoding of
the ciphertext filename's dirhash and second-to-last 16-byte block.
This format has the following problems:
- Since it doesn't always include the dirhash, it's incompatible with
directories that will use a secret-keyed dirhash over the plaintext
filenames. In this case, the dirhash won't be computable from the
ciphertext name without the key, so it instead must be retrieved from
the directory entry and always included in the no-key name.
Casefolded encrypted directories will use this type of dirhash.
- It's ambiguous: it's possible to craft two filenames that map to the
same no-key name, since the method used to abbreviate long filenames
doesn't use a proper cryptographic hash function.
Solve both these problems by switching to a new no-key name format that
is the base64 encoding of a variable-length structure that contains the
dirhash, up to 149 bytes of the ciphertext filename, and (if any bytes
remain) the SHA-256 of the remaining bytes of the ciphertext filename.
This ensures that each no-key name contains everything needed to find
the directory entry again, contains only legal characters, doesn't
exceed NAME_MAX, is unambiguous unless there's a SHA-256 collision, and
that we only take the performance hit of SHA-256 on very long filenames.
Note: this change does *not* address the existing issue where users can
modify the 'dirhash' part of a no-key name and the filesystem may still
accept the name.
Signed-off-by: Daniel Rosenberg <drosen@google.com>
[EB: improved comments and commit message, fixed checking return value
of base64_decode(), check for SHA-256 error, continue to set disk_name
for short names to keep matching simpler, and many other cleanups]
Link: https://lore.kernel.org/r/20200120223201.241390-7-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-01-21 06:32:01 +08:00
|
|
|
|
|
|
|
nokey_name = (void *)fname->crypto_buf.name;
|
|
|
|
fname->hash = nokey_name->dirhash[0];
|
|
|
|
fname->minor_hash = nokey_name->dirhash[1];
|
|
|
|
if (ret != FSCRYPT_NOKEY_NAME_MAX) {
|
|
|
|
/* The full ciphertext filename is available. */
|
|
|
|
fname->disk_name.name = nokey_name->bytes;
|
|
|
|
fname->disk_name.len =
|
|
|
|
ret - offsetof(struct fscrypt_nokey_name, bytes);
|
2015-04-26 15:12:50 +08:00
|
|
|
}
|
2015-05-13 18:20:54 +08:00
|
|
|
return 0;
|
2015-05-16 07:26:10 +08:00
|
|
|
|
2015-05-29 08:06:40 +08:00
|
|
|
errout:
|
2018-01-12 12:30:08 +08:00
|
|
|
kfree(fname->crypto_buf.name);
|
2015-04-26 15:12:50 +08:00
|
|
|
return ret;
|
|
|
|
}
|
2015-05-16 07:26:10 +08:00
|
|
|
EXPORT_SYMBOL(fscrypt_setup_filename);
|
2019-12-10 04:43:59 +08:00
|
|
|
|
fscrypt: improve format of no-key names
When an encrypted directory is listed without the key, the filesystem
must show "no-key names" that uniquely identify directory entries, are
at most 255 (NAME_MAX) bytes long, and don't contain '/' or '\0'.
Currently, for short names the no-key name is the base64 encoding of the
ciphertext filename, while for long names it's the base64 encoding of
the ciphertext filename's dirhash and second-to-last 16-byte block.
This format has the following problems:
- Since it doesn't always include the dirhash, it's incompatible with
directories that will use a secret-keyed dirhash over the plaintext
filenames. In this case, the dirhash won't be computable from the
ciphertext name without the key, so it instead must be retrieved from
the directory entry and always included in the no-key name.
Casefolded encrypted directories will use this type of dirhash.
- It's ambiguous: it's possible to craft two filenames that map to the
same no-key name, since the method used to abbreviate long filenames
doesn't use a proper cryptographic hash function.
Solve both these problems by switching to a new no-key name format that
is the base64 encoding of a variable-length structure that contains the
dirhash, up to 149 bytes of the ciphertext filename, and (if any bytes
remain) the SHA-256 of the remaining bytes of the ciphertext filename.
This ensures that each no-key name contains everything needed to find
the directory entry again, contains only legal characters, doesn't
exceed NAME_MAX, is unambiguous unless there's a SHA-256 collision, and
that we only take the performance hit of SHA-256 on very long filenames.
Note: this change does *not* address the existing issue where users can
modify the 'dirhash' part of a no-key name and the filesystem may still
accept the name.
Signed-off-by: Daniel Rosenberg <drosen@google.com>
[EB: improved comments and commit message, fixed checking return value
of base64_decode(), check for SHA-256 error, continue to set disk_name
for short names to keep matching simpler, and many other cleanups]
Link: https://lore.kernel.org/r/20200120223201.241390-7-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-01-21 06:32:01 +08:00
|
|
|
/**
|
|
|
|
* fscrypt_match_name() - test whether the given name matches a directory entry
|
|
|
|
* @fname: the name being searched for
|
|
|
|
* @de_name: the name from the directory entry
|
|
|
|
* @de_name_len: the length of @de_name in bytes
|
|
|
|
*
|
|
|
|
* Normally @fname->disk_name will be set, and in that case we simply compare
|
|
|
|
* that to the name stored in the directory entry. The only exception is that
|
|
|
|
* if we don't have the key for an encrypted directory and the name we're
|
|
|
|
* looking for is very long, then we won't have the full disk_name and instead
|
|
|
|
* we'll need to match against a fscrypt_nokey_name that includes a strong hash.
|
|
|
|
*
|
|
|
|
* Return: %true if the name matches, otherwise %false.
|
|
|
|
*/
|
|
|
|
bool fscrypt_match_name(const struct fscrypt_name *fname,
|
|
|
|
const u8 *de_name, u32 de_name_len)
|
|
|
|
{
|
|
|
|
const struct fscrypt_nokey_name *nokey_name =
|
|
|
|
(const void *)fname->crypto_buf.name;
|
2020-09-17 12:53:41 +08:00
|
|
|
u8 digest[SHA256_DIGEST_SIZE];
|
fscrypt: improve format of no-key names
When an encrypted directory is listed without the key, the filesystem
must show "no-key names" that uniquely identify directory entries, are
at most 255 (NAME_MAX) bytes long, and don't contain '/' or '\0'.
Currently, for short names the no-key name is the base64 encoding of the
ciphertext filename, while for long names it's the base64 encoding of
the ciphertext filename's dirhash and second-to-last 16-byte block.
This format has the following problems:
- Since it doesn't always include the dirhash, it's incompatible with
directories that will use a secret-keyed dirhash over the plaintext
filenames. In this case, the dirhash won't be computable from the
ciphertext name without the key, so it instead must be retrieved from
the directory entry and always included in the no-key name.
Casefolded encrypted directories will use this type of dirhash.
- It's ambiguous: it's possible to craft two filenames that map to the
same no-key name, since the method used to abbreviate long filenames
doesn't use a proper cryptographic hash function.
Solve both these problems by switching to a new no-key name format that
is the base64 encoding of a variable-length structure that contains the
dirhash, up to 149 bytes of the ciphertext filename, and (if any bytes
remain) the SHA-256 of the remaining bytes of the ciphertext filename.
This ensures that each no-key name contains everything needed to find
the directory entry again, contains only legal characters, doesn't
exceed NAME_MAX, is unambiguous unless there's a SHA-256 collision, and
that we only take the performance hit of SHA-256 on very long filenames.
Note: this change does *not* address the existing issue where users can
modify the 'dirhash' part of a no-key name and the filesystem may still
accept the name.
Signed-off-by: Daniel Rosenberg <drosen@google.com>
[EB: improved comments and commit message, fixed checking return value
of base64_decode(), check for SHA-256 error, continue to set disk_name
for short names to keep matching simpler, and many other cleanups]
Link: https://lore.kernel.org/r/20200120223201.241390-7-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-01-21 06:32:01 +08:00
|
|
|
|
|
|
|
if (likely(fname->disk_name.name)) {
|
|
|
|
if (de_name_len != fname->disk_name.len)
|
|
|
|
return false;
|
|
|
|
return !memcmp(de_name, fname->disk_name.name, de_name_len);
|
|
|
|
}
|
|
|
|
if (de_name_len <= sizeof(nokey_name->bytes))
|
|
|
|
return false;
|
|
|
|
if (memcmp(de_name, nokey_name->bytes, sizeof(nokey_name->bytes)))
|
|
|
|
return false;
|
2020-09-17 12:53:41 +08:00
|
|
|
sha256(&de_name[sizeof(nokey_name->bytes)],
|
|
|
|
de_name_len - sizeof(nokey_name->bytes), digest);
|
|
|
|
return !memcmp(digest, nokey_name->sha256, sizeof(digest));
|
fscrypt: improve format of no-key names
When an encrypted directory is listed without the key, the filesystem
must show "no-key names" that uniquely identify directory entries, are
at most 255 (NAME_MAX) bytes long, and don't contain '/' or '\0'.
Currently, for short names the no-key name is the base64 encoding of the
ciphertext filename, while for long names it's the base64 encoding of
the ciphertext filename's dirhash and second-to-last 16-byte block.
This format has the following problems:
- Since it doesn't always include the dirhash, it's incompatible with
directories that will use a secret-keyed dirhash over the plaintext
filenames. In this case, the dirhash won't be computable from the
ciphertext name without the key, so it instead must be retrieved from
the directory entry and always included in the no-key name.
Casefolded encrypted directories will use this type of dirhash.
- It's ambiguous: it's possible to craft two filenames that map to the
same no-key name, since the method used to abbreviate long filenames
doesn't use a proper cryptographic hash function.
Solve both these problems by switching to a new no-key name format that
is the base64 encoding of a variable-length structure that contains the
dirhash, up to 149 bytes of the ciphertext filename, and (if any bytes
remain) the SHA-256 of the remaining bytes of the ciphertext filename.
This ensures that each no-key name contains everything needed to find
the directory entry again, contains only legal characters, doesn't
exceed NAME_MAX, is unambiguous unless there's a SHA-256 collision, and
that we only take the performance hit of SHA-256 on very long filenames.
Note: this change does *not* address the existing issue where users can
modify the 'dirhash' part of a no-key name and the filesystem may still
accept the name.
Signed-off-by: Daniel Rosenberg <drosen@google.com>
[EB: improved comments and commit message, fixed checking return value
of base64_decode(), check for SHA-256 error, continue to set disk_name
for short names to keep matching simpler, and many other cleanups]
Link: https://lore.kernel.org/r/20200120223201.241390-7-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-01-21 06:32:01 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(fscrypt_match_name);
|
|
|
|
|
fscrypt: derive dirhash key for casefolded directories
When we allow indexed directories to use both encryption and
casefolding, for the dirhash we can't just hash the ciphertext filenames
that are stored on-disk (as is done currently) because the dirhash must
be case insensitive, but the stored names are case-preserving. Nor can
we hash the plaintext names with an unkeyed hash (or a hash keyed with a
value stored on-disk like ext4's s_hash_seed), since that would leak
information about the names that encryption is meant to protect.
Instead, if we can accept a dirhash that's only computable when the
fscrypt key is available, we can hash the plaintext names with a keyed
hash using a secret key derived from the directory's fscrypt master key.
We'll use SipHash-2-4 for this purpose.
Prepare for this by deriving a SipHash key for each casefolded encrypted
directory. Make sure to handle deriving the key not only when setting
up the directory's fscrypt_info, but also in the case where the casefold
flag is enabled after the fscrypt_info was already set up. (We could
just always derive the key regardless of casefolding, but that would
introduce unnecessary overhead for people not using casefolding.)
Signed-off-by: Daniel Rosenberg <drosen@google.com>
[EB: improved commit message, updated fscrypt.rst, squashed with change
that avoids unnecessarily deriving the key, and many other cleanups]
Link: https://lore.kernel.org/r/20200120223201.241390-3-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-01-21 06:31:57 +08:00
|
|
|
/**
|
|
|
|
* fscrypt_fname_siphash() - calculate the SipHash of a filename
|
|
|
|
* @dir: the parent directory
|
|
|
|
* @name: the filename to calculate the SipHash of
|
|
|
|
*
|
|
|
|
* Given a plaintext filename @name and a directory @dir which uses SipHash as
|
|
|
|
* its dirhash method and has had its fscrypt key set up, this function
|
|
|
|
* calculates the SipHash of that name using the directory's secret dirhash key.
|
|
|
|
*
|
|
|
|
* Return: the SipHash of @name using the hash key of @dir
|
|
|
|
*/
|
|
|
|
u64 fscrypt_fname_siphash(const struct inode *dir, const struct qstr *name)
|
|
|
|
{
|
|
|
|
const struct fscrypt_info *ci = dir->i_crypt_info;
|
|
|
|
|
|
|
|
WARN_ON(!ci->ci_dirhash_key_initialized);
|
|
|
|
|
|
|
|
return siphash(name->name, name->len, &ci->ci_dirhash_key);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(fscrypt_fname_siphash);
|
|
|
|
|
2019-12-10 04:43:59 +08:00
|
|
|
/*
|
|
|
|
* Validate dentries in encrypted directories to make sure we aren't potentially
|
|
|
|
* caching stale dentries after a key has been added.
|
|
|
|
*/
|
2020-09-24 13:47:21 +08:00
|
|
|
int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
|
2019-12-10 04:43:59 +08:00
|
|
|
{
|
|
|
|
struct dentry *dir;
|
|
|
|
int err;
|
|
|
|
int valid;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Plaintext names are always valid, since fscrypt doesn't support
|
2020-09-24 12:26:23 +08:00
|
|
|
* reverting to no-key names without evicting the directory's inode
|
2019-12-10 04:43:59 +08:00
|
|
|
* -- which implies eviction of the dentries in the directory.
|
|
|
|
*/
|
2020-09-24 12:26:24 +08:00
|
|
|
if (!(dentry->d_flags & DCACHE_NOKEY_NAME))
|
2019-12-10 04:43:59 +08:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
/*
|
2020-09-24 12:26:23 +08:00
|
|
|
* No-key name; valid if the directory's key is still unavailable.
|
2019-12-10 04:43:59 +08:00
|
|
|
*
|
2020-09-24 12:26:23 +08:00
|
|
|
* Although fscrypt forbids rename() on no-key names, we still must use
|
|
|
|
* dget_parent() here rather than use ->d_parent directly. That's
|
2019-12-10 04:43:59 +08:00
|
|
|
* because a corrupted fs image may contain directory hard links, which
|
|
|
|
* the VFS handles by moving the directory's dentry tree in the dcache
|
|
|
|
* each time ->lookup() finds the directory and it already has a dentry
|
|
|
|
* elsewhere. Thus ->d_parent can be changing, and we must safely grab
|
|
|
|
* a reference to some ->d_parent to prevent it from being freed.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (flags & LOOKUP_RCU)
|
|
|
|
return -ECHILD;
|
|
|
|
|
|
|
|
dir = dget_parent(dentry);
|
fscrypt: allow deleting files with unsupported encryption policy
Currently it's impossible to delete files that use an unsupported
encryption policy, as the kernel will just return an error when
performing any operation on the top-level encrypted directory, even just
a path lookup into the directory or opening the directory for readdir.
More specifically, this occurs in any of the following cases:
- The encryption context has an unrecognized version number. Current
kernels know about v1 and v2, but there could be more versions in the
future.
- The encryption context has unrecognized encryption modes
(FSCRYPT_MODE_*) or flags (FSCRYPT_POLICY_FLAG_*), an unrecognized
combination of modes, or reserved bits set.
- The encryption key has been added and the encryption modes are
recognized but aren't available in the crypto API -- for example, a
directory is encrypted with FSCRYPT_MODE_ADIANTUM but the kernel
doesn't have CONFIG_CRYPTO_ADIANTUM enabled.
It's desirable to return errors for most operations on files that use an
unsupported encryption policy, but the current behavior is too strict.
We need to allow enough to delete files, so that people can't be stuck
with undeletable files when downgrading kernel versions. That includes
allowing directories to be listed and allowing dentries to be looked up.
Fix this by modifying the key setup logic to treat an unsupported
encryption policy in the same way as "key unavailable" in the cases that
are required for a recursive delete to work: preparing for a readdir or
a dentry lookup, revalidating a dentry, or checking whether an inode has
the same encryption policy as its parent directory.
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
Link: https://lore.kernel.org/r/20201203022041.230976-10-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
2020-12-03 10:20:41 +08:00
|
|
|
/*
|
|
|
|
* Pass allow_unsupported=true, so that files with an unsupported
|
|
|
|
* encryption policy can be deleted.
|
|
|
|
*/
|
|
|
|
err = fscrypt_get_encryption_info(d_inode(dir), true);
|
2019-12-10 04:43:59 +08:00
|
|
|
valid = !fscrypt_has_encryption_key(d_inode(dir));
|
|
|
|
dput(dir);
|
|
|
|
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
return valid;
|
|
|
|
}
|
2020-09-24 13:47:21 +08:00
|
|
|
EXPORT_SYMBOL_GPL(fscrypt_d_revalidate);
|