Skip to content
  • Eric Biggers's avatar
    fscrypt: add fscrypt_symlink_getattr() for computing st_size · 38342724
    Eric Biggers authored
    commit d1876056 upstream.
    
    Add a helper function fscrypt_symlink_getattr() which will be called
    from the various filesystems' ->getattr() methods to read and decrypt
    the target of encrypted symlinks in order to report the correct st_size.
    
    Detailed explanation:
    
    As required by POSIX and as documented in various man pages, st_size for
    a symlink is supposed to be the length of the symlink target.
    Unfortunately, st_size has always been wrong for encrypted symlinks
    because st_size is populated from i_size from disk, which intentionally
    contains the length of the encrypted symlink target.  That's slightly
    greater than the length of the decrypted symlink target (which is the
    symlink target that userspace usually sees), and usually won't match the
    length of the no-key encoded symlink target either.
    
    This hadn't been fixed yet because reporting the correct st_size would
    require reading the symlink target from disk and decrypting or encoding
    it, which historically has been considered too heavyweight to do in
    ->getattr().  Also historically, the wrong st_size had only broken a
    test (LTP lstat03) and there were no known complaints from real users.
    (This is probably because the st_size of symlinks isn't used too often,
    and when it is, typically it's for a hint for what buffer size to pass
    to readlink() -- which a slightly-too-large size still works for.)
    
    However, a couple things have changed now.  First, there have recently
    been complaints about the current behavior from real users:
    
    - Breakage in rpmbuild:
      https://github.com/rpm-software-management/rpm/issues/1682
      https://github.com/google/fscrypt/issues/305
    
    - Breakage in toybox cpio:
      https://www.mail-archive.com/toybox@lists.landley.net/msg07193.html
    
    - Breakage in libgit2: https://issuetracker.google.com/issues/189629152
      (on Android public issue tracker, requires login)
    
    Second, we now cache decrypted symlink targets in ->i_link.  Therefore,
    taking the performance hit of reading and decrypting the symlink target
    in ->getattr() wouldn't be as big a deal as it used to be, since usually
    it will just save having to do the same thing later.
    
    Also note that eCryptfs ended up having to read and decrypt symlink
    targets in ->getattr() as well, to fix this same issue; see
    commit 3a60a168 ("eCryptfs: Decrypt symlink target for stat size").
    
    So, let's just bite the bullet, and read and decrypt the symlink target
    in ->getattr() in order to report the correct st_size.  Add a function
    fscrypt_symlink_getattr() which the filesystems will call to do this.
    
    (Alternatively, we could store the decrypted size of symlinks on-disk.
    But there isn't a great place to do so, and encryption is meant to hide
    the original size to some extent; that property would be lost.)
    
    Cc: stable@vger.kernel.org
    Link: https://lore.kernel.org/r/20210702065350.209646-2-ebiggers@kernel.org
    
    
    Signed-off-by: default avatarEric Biggers <ebiggers@google.com>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    38342724