• Jann Horn's avatar
    fuse: use unsigned type for getxattr/listxattr size truncation · b1891524
    Jann Horn authored
    The existing code uses min_t(ssize_t, outarg.size, XATTR_LIST_MAX) when
    parsing the FUSE daemon's response to a zero-length getxattr/listxattr
    request.
    On 32-bit kernels, where ssize_t and outarg.size are the same size, this is
    wrong: The min_t() will pass through any size values that are negative when
    interpreted as signed.
    fuse_listxattr() will then return this userspace-supplied negative value,
    which callers will treat as an error value.
    
    This kind of bug pattern can lead to fairly bad security bugs because of
    how error codes are used in the Linux kernel. If a caller were to convert
    the numeric error into an error pointer, like so:
    
        struct foo *func(...) {
          int len = fuse_getxattr(..., NULL, 0);
          if (len < 0)
            return ERR_PTR(len);
          ...
        }
    
    then it would end up returning this userspace-supplied negative value cast
    to a pointer - but the caller of this function wouldn't recognize it as an
    error pointer (IS_ERR_VALUE() only detects values in the narrow range in
    which legitimate errno values are), and so it would just be treated as a
    kernel pointer.
    
    I think there is at least one theoretical codepath where this could happen,
    but that path would involve virtio-fs with submounts plus some weird
    SELinux configuration, so I think it's probably not a concern in practice.
    
    Cc: stable@vger.kernel.org # v4.9
    Fixes: 63401ccd ("fuse: limit xattr returned size")
    Signed-off-by: default avatarJann Horn <jannh@google.com>
    Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
    b1891524
xattr.c 4.96 KB