1. 07 11月, 2019 1 次提交
    • E
      fscrypt: add support for IV_INO_LBLK_64 policies · b103fb76
      Eric Biggers 提交于
      Inline encryption hardware compliant with the UFS v2.1 standard or with
      the upcoming version of the eMMC standard has the following properties:
      
      (1) Per I/O request, the encryption key is specified by a previously
          loaded keyslot.  There might be only a small number of keyslots.
      
      (2) Per I/O request, the starting IV is specified by a 64-bit "data unit
          number" (DUN).  IV bits 64-127 are assumed to be 0.  The hardware
          automatically increments the DUN for each "data unit" of
          configurable size in the request, e.g. for each filesystem block.
      
      Property (1) makes it inefficient to use the traditional fscrypt
      per-file keys.  Property (2) precludes the use of the existing
      DIRECT_KEY fscrypt policy flag, which needs at least 192 IV bits.
      
      Therefore, add a new fscrypt policy flag IV_INO_LBLK_64 which causes the
      encryption to modified as follows:
      
      - The encryption keys are derived from the master key, encryption mode
        number, and filesystem UUID.
      
      - The IVs are chosen as (inode_number << 32) | file_logical_block_num.
        For filenames encryption, file_logical_block_num is 0.
      
      Since the file nonces aren't used in the key derivation, many files may
      share the same encryption key.  This is much more efficient on the
      target hardware.  Including the inode number in the IVs and mixing the
      filesystem UUID into the keys ensures that data in different files is
      nevertheless still encrypted differently.
      
      Additionally, limiting the inode and block numbers to 32 bits and
      placing the block number in the low bits maintains compatibility with
      the 64-bit DUN convention (property (2) above).
      
      Since this scheme assumes that inode numbers are stable (which may
      preclude filesystem shrinking) and that inode and file logical block
      numbers are at most 32-bit, IV_INO_LBLK_64 will only be allowed on
      filesystems that meet these constraints.  These are acceptable
      limitations for the cases where this format would actually be used.
      
      Note that IV_INO_LBLK_64 is an on-disk format, not an implementation.
      This patch just adds support for it using the existing filesystem layer
      encryption.  A later patch will add support for inline encryption.
      Reviewed-by: NPaul Crowley <paulcrowley@google.com>
      Co-developed-by: NSatya Tangirala <satyat@google.com>
      Signed-off-by: NSatya Tangirala <satyat@google.com>
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      b103fb76
  2. 22 10月, 2019 1 次提交
    • E
      fscrypt: remove struct fscrypt_ctx · 1565bdad
      Eric Biggers 提交于
      Now that ext4 and f2fs implement their own post-read workflow that
      supports both fscrypt and fsverity, the fscrypt-only workflow based
      around struct fscrypt_ctx is no longer used.  So remove the unused code.
      
      This is based on a patch from Chandan Rajendra's "Consolidate FS read
      I/O callbacks code" patchset, but rebased onto the latest kernel, folded
      __fscrypt_decrypt_bio() into fscrypt_decrypt_bio(), cleaned up
      fscrypt_initialize(), and updated the commit message.
      
      Originally-from: Chandan Rajendra <chandan@linux.ibm.com>
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      1565bdad
  3. 13 8月, 2019 7 次提交
    • E
      fscrypt: add FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS ioctl · 78a1b96b
      Eric Biggers 提交于
      Add a root-only variant of the FS_IOC_REMOVE_ENCRYPTION_KEY ioctl which
      removes all users' claims of the key, not just the current user's claim.
      I.e., it always removes the key itself, no matter how many users have
      added it.
      
      This is useful for forcing a directory to be locked, without having to
      figure out which user ID(s) the key was added under.  This is planned to
      be used by a command like 'sudo fscrypt lock DIR --all-users' in the
      fscrypt userspace tool (http://github.com/google/fscrypt).
      Reviewed-by: NTheodore Ts'o <tytso@mit.edu>
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      78a1b96b
    • E
      fscrypt: v2 encryption policy support · 5dae460c
      Eric Biggers 提交于
      Add a new fscrypt policy version, "v2".  It has the following changes
      from the original policy version, which we call "v1" (*):
      
      - Master keys (the user-provided encryption keys) are only ever used as
        input to HKDF-SHA512.  This is more flexible and less error-prone, and
        it avoids the quirks and limitations of the AES-128-ECB based KDF.
        Three classes of cryptographically isolated subkeys are defined:
      
          - Per-file keys, like used in v1 policies except for the new KDF.
      
          - Per-mode keys.  These implement the semantics of the DIRECT_KEY
            flag, which for v1 policies made the master key be used directly.
            These are also planned to be used for inline encryption when
            support for it is added.
      
          - Key identifiers (see below).
      
      - Each master key is identified by a 16-byte master_key_identifier,
        which is derived from the key itself using HKDF-SHA512.  This prevents
        users from associating the wrong key with an encrypted file or
        directory.  This was easily possible with v1 policies, which
        identified the key by an arbitrary 8-byte master_key_descriptor.
      
      - The key must be provided in the filesystem-level keyring, not in a
        process-subscribed keyring.
      
      The following UAPI additions are made:
      
      - The existing ioctl FS_IOC_SET_ENCRYPTION_POLICY can now be passed a
        fscrypt_policy_v2 to set a v2 encryption policy.  It's disambiguated
        from fscrypt_policy/fscrypt_policy_v1 by the version code prefix.
      
      - A new ioctl FS_IOC_GET_ENCRYPTION_POLICY_EX is added.  It allows
        getting the v1 or v2 encryption policy of an encrypted file or
        directory.  The existing FS_IOC_GET_ENCRYPTION_POLICY ioctl could not
        be used because it did not have a way for userspace to indicate which
        policy structure is expected.  The new ioctl includes a size field, so
        it is extensible to future fscrypt policy versions.
      
      - The ioctls FS_IOC_ADD_ENCRYPTION_KEY, FS_IOC_REMOVE_ENCRYPTION_KEY,
        and FS_IOC_GET_ENCRYPTION_KEY_STATUS now support managing keys for v2
        encryption policies.  Such keys are kept logically separate from keys
        for v1 encryption policies, and are identified by 'identifier' rather
        than by 'descriptor'.  The 'identifier' need not be provided when
        adding a key, since the kernel will calculate it anyway.
      
      This patch temporarily keeps adding/removing v2 policy keys behind the
      same permission check done for adding/removing v1 policy keys:
      capable(CAP_SYS_ADMIN).  However, the next patch will carefully take
      advantage of the cryptographically secure master_key_identifier to allow
      non-root users to add/remove v2 policy keys, thus providing a full
      replacement for v1 policies.
      
      (*) Actually, in the API fscrypt_policy::version is 0 while on-disk
          fscrypt_context::format is 1.  But I believe it makes the most sense
          to advance both to '2' to have them be in sync, and to consider the
          numbering to start at 1 except for the API quirk.
      Reviewed-by: NPaul Crowley <paulcrowley@google.com>
      Reviewed-by: NTheodore Ts'o <tytso@mit.edu>
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      5dae460c
    • E
      fscrypt: add FS_IOC_GET_ENCRYPTION_KEY_STATUS ioctl · 5a7e2992
      Eric Biggers 提交于
      Add a new fscrypt ioctl, FS_IOC_GET_ENCRYPTION_KEY_STATUS.  Given a key
      specified by 'struct fscrypt_key_specifier' (the same way a key is
      specified for the other fscrypt key management ioctls), it returns
      status information in a 'struct fscrypt_get_key_status_arg'.
      
      The main motivation for this is that applications need to be able to
      check whether an encrypted directory is "unlocked" or not, so that they
      can add the key if it is not, and avoid adding the key (which may
      involve prompting the user for a passphrase) if it already is.
      
      It's possible to use some workarounds such as checking whether opening a
      regular file fails with ENOKEY, or checking whether the filenames "look
      like gibberish" or not.  However, no workaround is usable in all cases.
      
      Like the other key management ioctls, the keyrings syscalls may seem at
      first to be a good fit for this.  Unfortunately, they are not.  Even if
      we exposed the keyring ID of the ->s_master_keys keyring and gave
      everyone Search permission on it (note: currently the keyrings
      permission system would also allow everyone to "invalidate" the keyring
      too), the fscrypt keys have an additional state that doesn't map cleanly
      to the keyrings API: the secret can be removed, but we can be still
      tracking the files that were using the key, and the removal can be
      re-attempted or the secret added again.
      
      After later patches, some applications will also need a way to determine
      whether a key was added by the current user vs. by some other user.
      Reserved fields are included in fscrypt_get_key_status_arg for this and
      other future extensions.
      Reviewed-by: NTheodore Ts'o <tytso@mit.edu>
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      5a7e2992
    • E
      fscrypt: add FS_IOC_REMOVE_ENCRYPTION_KEY ioctl · b1c0ec35
      Eric Biggers 提交于
      Add a new fscrypt ioctl, FS_IOC_REMOVE_ENCRYPTION_KEY.  This ioctl
      removes an encryption key that was added by FS_IOC_ADD_ENCRYPTION_KEY.
      It wipes the secret key itself, then "locks" the encrypted files and
      directories that had been unlocked using that key -- implemented by
      evicting the relevant dentries and inodes from the VFS caches.
      
      The problem this solves is that many fscrypt users want the ability to
      remove encryption keys, causing the corresponding encrypted directories
      to appear "locked" (presented in ciphertext form) again.  Moreover,
      users want removing an encryption key to *really* remove it, in the
      sense that the removed keys cannot be recovered even if kernel memory is
      compromised, e.g. by the exploit of a kernel security vulnerability or
      by a physical attack.  This is desirable after a user logs out of the
      system, for example.  In many cases users even already assume this to be
      the case and are surprised to hear when it's not.
      
      It is not sufficient to simply unlink the master key from the keyring
      (or to revoke or invalidate it), since the actual encryption transform
      objects are still pinned in memory by their inodes.  Therefore, to
      really remove a key we must also evict the relevant inodes.
      
      Currently one workaround is to run 'sync && echo 2 >
      /proc/sys/vm/drop_caches'.  But, that evicts all unused inodes in the
      system rather than just the inodes associated with the key being
      removed, causing severe performance problems.  Moreover, it requires
      root privileges, so regular users can't "lock" their encrypted files.
      
      Another workaround, used in Chromium OS kernels, is to add a new
      VFS-level ioctl FS_IOC_DROP_CACHE which is a more restricted version of
      drop_caches that operates on a single super_block.  It does:
      
              shrink_dcache_sb(sb);
              invalidate_inodes(sb, false);
      
      But it's still a hack.  Yet, the major users of filesystem encryption
      want this feature badly enough that they are actually using these hacks.
      
      To properly solve the problem, start maintaining a list of the inodes
      which have been "unlocked" using each master key.  Originally this
      wasn't possible because the kernel didn't keep track of in-use master
      keys at all.  But, with the ->s_master_keys keyring it is now possible.
      
      Then, add an ioctl FS_IOC_REMOVE_ENCRYPTION_KEY.  It finds the specified
      master key in ->s_master_keys, then wipes the secret key itself, which
      prevents any additional inodes from being unlocked with the key.  Then,
      it syncs the filesystem and evicts the inodes in the key's list.  The
      normal inode eviction code will free and wipe the per-file keys (in
      ->i_crypt_info).  Note that freeing ->i_crypt_info without evicting the
      inodes was also considered, but would have been racy.
      
      Some inodes may still be in use when a master key is removed, and we
      can't simply revoke random file descriptors, mmap's, etc.  Thus, the
      ioctl simply skips in-use inodes, and returns -EBUSY to indicate that
      some inodes weren't evicted.  The master key *secret* is still removed,
      but the fscrypt_master_key struct remains to keep track of the remaining
      inodes.  Userspace can then retry the ioctl to evict the remaining
      inodes.  Alternatively, if userspace adds the key again, the refreshed
      secret will be associated with the existing list of inodes so they
      remain correctly tracked for future key removals.
      
      The ioctl doesn't wipe pagecache pages.  Thus, we tolerate that after a
      kernel compromise some portions of plaintext file contents may still be
      recoverable from memory.  This can be solved by enabling page poisoning
      system-wide, which security conscious users may choose to do.  But it's
      very difficult to solve otherwise, e.g. note that plaintext file
      contents may have been read in other places than pagecache pages.
      
      Like FS_IOC_ADD_ENCRYPTION_KEY, FS_IOC_REMOVE_ENCRYPTION_KEY is
      initially restricted to privileged users only.  This is sufficient for
      some use cases, but not all.  A later patch will relax this restriction,
      but it will require introducing key hashes, among other changes.
      Reviewed-by: NTheodore Ts'o <tytso@mit.edu>
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      b1c0ec35
    • E
      fscrypt: add FS_IOC_ADD_ENCRYPTION_KEY ioctl · 22d94f49
      Eric Biggers 提交于
      Add a new fscrypt ioctl, FS_IOC_ADD_ENCRYPTION_KEY.  This ioctl adds an
      encryption key to the filesystem's fscrypt keyring ->s_master_keys,
      making any files encrypted with that key appear "unlocked".
      
      Why we need this
      ~~~~~~~~~~~~~~~~
      
      The main problem is that the "locked/unlocked" (ciphertext/plaintext)
      status of encrypted files is global, but the fscrypt keys are not.
      fscrypt only looks for keys in the keyring(s) the process accessing the
      filesystem is subscribed to: the thread keyring, process keyring, and
      session keyring, where the session keyring may contain the user keyring.
      
      Therefore, userspace has to put fscrypt keys in the keyrings for
      individual users or sessions.  But this means that when a process with a
      different keyring tries to access encrypted files, whether they appear
      "unlocked" or not is nondeterministic.  This is because it depends on
      whether the files are currently present in the inode cache.
      
      Fixing this by consistently providing each process its own view of the
      filesystem depending on whether it has the key or not isn't feasible due
      to how the VFS caches work.  Furthermore, while sometimes users expect
      this behavior, it is misguided for two reasons.  First, it would be an
      OS-level access control mechanism largely redundant with existing access
      control mechanisms such as UNIX file permissions, ACLs, LSMs, etc.
      Encryption is actually for protecting the data at rest.
      
      Second, almost all users of fscrypt actually do need the keys to be
      global.  The largest users of fscrypt, Android and Chromium OS, achieve
      this by having PID 1 create a "session keyring" that is inherited by
      every process.  This works, but it isn't scalable because it prevents
      session keyrings from being used for any other purpose.
      
      On general-purpose Linux distros, the 'fscrypt' userspace tool [1] can't
      similarly abuse the session keyring, so to make 'sudo' work on all
      systems it has to link all the user keyrings into root's user keyring
      [2].  This is ugly and raises security concerns.  Moreover it can't make
      the keys available to system services, such as sshd trying to access the
      user's '~/.ssh' directory (see [3], [4]) or NetworkManager trying to
      read certificates from the user's home directory (see [5]); or to Docker
      containers (see [6], [7]).
      
      By having an API to add a key to the *filesystem* we'll be able to fix
      the above bugs, remove userspace workarounds, and clearly express the
      intended semantics: the locked/unlocked status of an encrypted directory
      is global, and encryption is orthogonal to OS-level access control.
      
      Why not use the add_key() syscall
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      
      We use an ioctl for this API rather than the existing add_key() system
      call because the ioctl gives us the flexibility needed to implement
      fscrypt-specific semantics that will be introduced in later patches:
      
      - Supporting key removal with the semantics such that the secret is
        removed immediately and any unused inodes using the key are evicted;
        also, the eviction of any in-use inodes can be retried.
      
      - Calculating a key-dependent cryptographic identifier and returning it
        to userspace.
      
      - Allowing keys to be added and removed by non-root users, but only keys
        for v2 encryption policies; and to prevent denial-of-service attacks,
        users can only remove keys they themselves have added, and a key is
        only really removed after all users who added it have removed it.
      
      Trying to shoehorn these semantics into the keyrings syscalls would be
      very difficult, whereas the ioctls make things much easier.
      
      However, to reuse code the implementation still uses the keyrings
      service internally.  Thus we get lockless RCU-mode key lookups without
      having to re-implement it, and the keys automatically show up in
      /proc/keys for debugging purposes.
      
      References:
      
          [1] https://github.com/google/fscrypt
          [2] https://goo.gl/55cCrI#heading=h.vf09isp98isb
          [3] https://github.com/google/fscrypt/issues/111#issuecomment-444347939
          [4] https://github.com/google/fscrypt/issues/116
          [5] https://bugs.launchpad.net/ubuntu/+source/fscrypt/+bug/1770715
          [6] https://github.com/google/fscrypt/issues/128
          [7] https://askubuntu.com/questions/1130306/cannot-run-docker-on-an-encrypted-filesystemReviewed-by: NTheodore Ts'o <tytso@mit.edu>
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      22d94f49
    • E
      fscrypt: rename keyinfo.c to keysetup.c · feed8258
      Eric Biggers 提交于
      Rename keyinfo.c to keysetup.c since this better describes what the file
      does (sets up the key), and it matches the new file keysetup_v1.c.
      Reviewed-by: NTheodore Ts'o <tytso@mit.edu>
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      feed8258
    • E
      fs, fscrypt: move uapi definitions to new header <linux/fscrypt.h> · 7af0ab0d
      Eric Biggers 提交于
      More fscrypt definitions are being added, and we shouldn't use a
      disproportionate amount of space in <linux/fs.h> for fscrypt stuff.
      So move the fscrypt definitions to a new header <linux/fscrypt.h>.
      
      For source compatibility with existing userspace programs, <linux/fs.h>
      still includes the new header.
      Reviewed-by: NTheodore Ts'o <tytso@mit.edu>
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      7af0ab0d
  4. 29 5月, 2019 6 次提交
    • E
      fscrypt: support decrypting multiple filesystem blocks per page · aa8bc1ac
      Eric Biggers 提交于
      Rename fscrypt_decrypt_page() to fscrypt_decrypt_pagecache_blocks() and
      redefine its behavior to decrypt all filesystem blocks in the given
      region of the given page, rather than assuming that the region consists
      of just one filesystem block.  Also remove the 'inode' and 'lblk_num'
      parameters, since they can be retrieved from the page as it's already
      assumed to be a pagecache page.
      
      This is in preparation for allowing encryption on ext4 filesystems with
      blocksize != PAGE_SIZE.
      
      This is based on work by Chandan Rajendra.
      Reviewed-by: NChandan Rajendra <chandan@linux.ibm.com>
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      aa8bc1ac
    • E
      fscrypt: introduce fscrypt_decrypt_block_inplace() · 41adbcb7
      Eric Biggers 提交于
      Currently fscrypt_decrypt_page() does one of two logically distinct
      things depending on whether FS_CFLG_OWN_PAGES is set in the filesystem's
      fscrypt_operations: decrypt a pagecache page in-place, or decrypt a
      filesystem block in-place in any page.  Currently these happen to share
      the same implementation, but this conflates the notion of blocks and
      pages.  It also makes it so that all callers have to provide inode and
      lblk_num, when fscrypt could determine these itself for pagecache pages.
      
      Therefore, move the FS_CFLG_OWN_PAGES behavior into a new function
      fscrypt_decrypt_block_inplace().  This mirrors
      fscrypt_encrypt_block_inplace().
      
      This is in preparation for allowing encryption on ext4 filesystems with
      blocksize != PAGE_SIZE.
      Reviewed-by: NChandan Rajendra <chandan@linux.ibm.com>
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      41adbcb7
    • E
      fscrypt: support encrypting multiple filesystem blocks per page · 53bc1d85
      Eric Biggers 提交于
      Rename fscrypt_encrypt_page() to fscrypt_encrypt_pagecache_blocks() and
      redefine its behavior to encrypt all filesystem blocks from the given
      region of the given page, rather than assuming that the region consists
      of just one filesystem block.  Also remove the 'inode' and 'lblk_num'
      parameters, since they can be retrieved from the page as it's already
      assumed to be a pagecache page.
      
      This is in preparation for allowing encryption on ext4 filesystems with
      blocksize != PAGE_SIZE.
      
      This is based on work by Chandan Rajendra.
      Reviewed-by: NChandan Rajendra <chandan@linux.ibm.com>
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      53bc1d85
    • E
      fscrypt: introduce fscrypt_encrypt_block_inplace() · 03569f2f
      Eric Biggers 提交于
      fscrypt_encrypt_page() behaves very differently depending on whether the
      filesystem set FS_CFLG_OWN_PAGES in its fscrypt_operations.  This makes
      the function difficult to understand and document.  It also makes it so
      that all callers have to provide inode and lblk_num, when fscrypt could
      determine these itself for pagecache pages.
      
      Therefore, move the FS_CFLG_OWN_PAGES behavior into a new function
      fscrypt_encrypt_block_inplace().
      
      This is in preparation for allowing encryption on ext4 filesystems with
      blocksize != PAGE_SIZE.
      Reviewed-by: NChandan Rajendra <chandan@linux.ibm.com>
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      03569f2f
    • E
      fscrypt: remove the "write" part of struct fscrypt_ctx · 2a415a02
      Eric Biggers 提交于
      Now that fscrypt_ctx is not used for writes, remove the 'w' fields.
      Reviewed-by: NChandan Rajendra <chandan@linux.ibm.com>
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      2a415a02
    • E
      fscrypt: simplify bounce page handling · d2d0727b
      Eric Biggers 提交于
      Currently, bounce page handling for writes to encrypted files is
      unnecessarily complicated.  A fscrypt_ctx is allocated along with each
      bounce page, page_private(bounce_page) points to this fscrypt_ctx, and
      fscrypt_ctx::w::control_page points to the original pagecache page.
      
      However, because writes don't use the fscrypt_ctx for anything else,
      there's no reason why page_private(bounce_page) can't just point to the
      original pagecache page directly.
      
      Therefore, this patch makes this change.  In the process, it also cleans
      up the API exposed to filesystems that allows testing whether a page is
      a bounce page, getting the pagecache page from a bounce page, and
      freeing a bounce page.
      Reviewed-by: NChandan Rajendra <chandan@linux.ibm.com>
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      d2d0727b
  5. 08 5月, 2019 1 次提交
  6. 18 4月, 2019 1 次提交
    • E
      fscrypt: cache decrypted symlink target in ->i_link · 2c58d548
      Eric Biggers 提交于
      Path lookups that traverse encrypted symlink(s) are very slow because
      each encrypted symlink needs to be decrypted each time it's followed.
      This also involves dropping out of rcu-walk mode.
      
      Make encrypted symlinks faster by caching the decrypted symlink target
      in ->i_link.  The first call to fscrypt_get_symlink() sets it.  Then,
      the existing VFS path lookup code uses the non-NULL ->i_link to take the
      fast path where ->get_link() isn't called, and lookups in rcu-walk mode
      remain in rcu-walk mode.
      
      Also set ->i_link immediately when a new encrypted symlink is created.
      
      To safely free the symlink target after an RCU grace period has elapsed,
      introduce a new function fscrypt_free_inode(), and make the relevant
      filesystems call it just before actually freeing the inode.
      
      Cc: Al Viro <viro@zeniv.linux.org.uk>
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      Signed-off-by: NTheodore Ts'o <tytso@mit.edu>
      2c58d548
  7. 17 4月, 2019 6 次提交
    • E
      fscrypt: fix race where ->lookup() marks plaintext dentry as ciphertext · b01531db
      Eric Biggers 提交于
      ->lookup() in an encrypted directory begins as follows:
      
      1. fscrypt_prepare_lookup():
          a. Try to load the directory's encryption key.
          b. If the key is unavailable, mark the dentry as a ciphertext name
             via d_flags.
      2. fscrypt_setup_filename():
          a. Try to load the directory's encryption key.
          b. If the key is available, encrypt the name (treated as a plaintext
             name) to get the on-disk name.  Otherwise decode the name
             (treated as a ciphertext name) to get the on-disk name.
      
      But if the key is concurrently added, it may be found at (2a) but not at
      (1a).  In this case, the dentry will be wrongly marked as a ciphertext
      name even though it was actually treated as plaintext.
      
      This will cause the dentry to be wrongly invalidated on the next lookup,
      potentially causing problems.  For example, if the racy ->lookup() was
      part of sys_mount(), then the new mount will be detached when anything
      tries to access it.  This is despite the mountpoint having a plaintext
      path, which should remain valid now that the key was added.
      
      Of course, this is only possible if there's a userspace race.  Still,
      the additional kernel-side race is confusing and unexpected.
      
      Close the kernel-side race by changing fscrypt_prepare_lookup() to also
      set the on-disk filename (step 2b), consistent with the d_flags update.
      
      Fixes: 28b4c263 ("ext4 crypto: revalidate dentry after adding or removing the key")
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      Signed-off-by: NTheodore Ts'o <tytso@mit.edu>
      b01531db
    • E
      fs, fscrypt: clear DCACHE_ENCRYPTED_NAME when unaliasing directory · 0bf3d5c1
      Eric Biggers 提交于
      Make __d_move() clear DCACHE_ENCRYPTED_NAME on the source dentry.  This
      is needed for when d_splice_alias() moves a directory's encrypted alias
      to its decrypted alias as a result of the encryption key being added.
      
      Otherwise, the decrypted alias will incorrectly be invalidated on the
      next lookup, causing problems such as unmounting a mount the user just
      mount()ed there.
      
      Note that we don't have to support arbitrary moves of this flag because
      fscrypt doesn't allow dentries with DCACHE_ENCRYPTED_NAME to be the
      source or target of a rename().
      
      Fixes: 28b4c263 ("ext4 crypto: revalidate dentry after adding or removing the key")
      Reported-by: NSarthak Kukreti <sarthakkukreti@chromium.org>
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      Signed-off-by: NTheodore Ts'o <tytso@mit.edu>
      0bf3d5c1
    • E
      fscrypt: fix race allowing rename() and link() of ciphertext dentries · 968dd6d0
      Eric Biggers 提交于
      Close some race conditions where fscrypt allowed rename() and link() on
      ciphertext dentries that had been looked up just prior to the key being
      concurrently added.  It's better to return -ENOKEY in this case.
      
      This avoids doing the nonsensical thing of encrypting the names a second
      time when searching for the actual on-disk dir entries.  It also
      guarantees that DCACHE_ENCRYPTED_NAME dentries are never rename()d, so
      the dcache won't have support all possible combinations of moving
      DCACHE_ENCRYPTED_NAME around during __d_move().
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      Signed-off-by: NTheodore Ts'o <tytso@mit.edu>
      968dd6d0
    • E
      fscrypt: clean up and improve dentry revalidation · 6cc24868
      Eric Biggers 提交于
      Make various improvements to fscrypt dentry revalidation:
      
      - Don't try to handle the case where the per-directory key is removed,
        as this can't happen without the inode (and dentries) being evicted.
      
      - Flag ciphertext dentries rather than plaintext dentries, since it's
        ciphertext dentries that need the special handling.
      
      - Avoid doing unnecessary work for non-ciphertext dentries.
      
      - When revalidating ciphertext dentries, try to set up the directory's
        i_crypt_info to make sure the key is really still absent, rather than
        invalidating all negative dentries as the previous code did.  An old
        comment suggested we can't do this for locking reasons, but AFAICT
        this comment was outdated and it actually works fine.
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      Signed-off-by: NTheodore Ts'o <tytso@mit.edu>
      6cc24868
    • E
      fscrypt: use READ_ONCE() to access ->i_crypt_info · e37a784d
      Eric Biggers 提交于
      ->i_crypt_info starts out NULL and may later be locklessly set to a
      non-NULL value by the cmpxchg() in fscrypt_get_encryption_info().
      
      But ->i_crypt_info is used directly, which technically is incorrect.
      It's a data race, and it doesn't include the data dependency barrier
      needed to safely dereference the pointer on at least one architecture.
      
      Fix this by using READ_ONCE() instead.  Note: we don't need to use
      smp_load_acquire(), since dereferencing the pointer only requires a data
      dependency barrier, which is already included in READ_ONCE().  We also
      don't need READ_ONCE() in places where ->i_crypt_info is unconditionally
      dereferenced, since it must have already been checked.
      
      Also downgrade the cmpxchg() to cmpxchg_release(), since RELEASE
      semantics are sufficient on the write side.
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      Signed-off-by: NTheodore Ts'o <tytso@mit.edu>
      e37a784d
    • E
      fscrypt: drop inode argument from fscrypt_get_ctx() · cd0265fc
      Eric Biggers 提交于
      The only reason the inode is being passed to fscrypt_get_ctx() is to
      verify that the encryption key is available.  However, all callers
      already ensure this because if we get as far as trying to do I/O to an
      encrypted file without the key, there's already a bug.
      
      Therefore, remove this unnecessary argument.
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      Signed-off-by: NTheodore Ts'o <tytso@mit.edu>
      cd0265fc
  8. 24 1月, 2019 2 次提交
    • E
      fscrypt: return -EXDEV for incompatible rename or link into encrypted dir · f5e55e77
      Eric Biggers 提交于
      Currently, trying to rename or link a regular file, directory, or
      symlink into an encrypted directory fails with EPERM when the source
      file is unencrypted or is encrypted with a different encryption policy,
      and is on the same mountpoint.  It is correct for the operation to fail,
      but the choice of EPERM breaks tools like 'mv' that know to copy rather
      than rename if they see EXDEV, but don't know what to do with EPERM.
      
      Our original motivation for EPERM was to encourage users to securely
      handle their data.  Encrypting files by "moving" them into an encrypted
      directory can be insecure because the unencrypted data may remain in
      free space on disk, where it can later be recovered by an attacker.
      It's much better to encrypt the data from the start, or at least try to
      securely delete the source data e.g. using the 'shred' program.
      
      However, the current behavior hasn't been effective at achieving its
      goal because users tend to be confused, hack around it, and complain;
      see e.g. https://github.com/google/fscrypt/issues/76.  And in some cases
      it's actually inconsistent or unnecessary.  For example, 'mv'-ing files
      between differently encrypted directories doesn't work even in cases
      where it can be secure, such as when in userspace the same passphrase
      protects both directories.  Yet, you *can* already 'mv' unencrypted
      files into an encrypted directory if the source files are on a different
      mountpoint, even though doing so is often insecure.
      
      There are probably better ways to teach users to securely handle their
      files.  For example, the 'fscrypt' userspace tool could provide a
      command that migrates unencrypted files into an encrypted directory,
      acting like 'shred' on the source files and providing appropriate
      warnings depending on the type of the source filesystem and disk.
      
      Receiving errors on unimportant files might also force some users to
      disable encryption, thus making the behavior counterproductive.  It's
      desirable to make encryption as unobtrusive as possible.
      
      Therefore, change the error code from EPERM to EXDEV so that tools
      looking for EXDEV will fall back to a copy.
      
      This, of course, doesn't prevent users from still doing the right things
      to securely manage their files.  Note that this also matches the
      behavior when a file is renamed between two project quota hierarchies;
      so there's precedent for using EXDEV for things other than mountpoints.
      
      xfstests generic/398 will require an update with this change.
      
      [Rewritten from an earlier patch series by Michael Halcrow.]
      
      Cc: Michael Halcrow <mhalcrow@google.com>
      Cc: Joe Richey <joerichey@google.com>
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      f5e55e77
    • C
      fscrypt: remove filesystem specific build config option · 643fa961
      Chandan Rajendra 提交于
      In order to have a common code base for fscrypt "post read" processing
      for all filesystems which support encryption, this commit removes
      filesystem specific build config option (e.g. CONFIG_EXT4_FS_ENCRYPTION)
      and replaces it with a build option (i.e. CONFIG_FS_ENCRYPTION) whose
      value affects all the filesystems making use of fscrypt.
      Reviewed-by: NEric Biggers <ebiggers@google.com>
      Signed-off-by: NChandan Rajendra <chandan@linux.vnet.ibm.com>
      Signed-off-by: NEric Biggers <ebiggers@google.com>
      643fa961
  9. 12 1月, 2018 10 次提交
  10. 19 10月, 2017 5 次提交