• Christian Brauner's avatar
    file: reclaim 24 bytes from f_owner · 1934b212
    Christian Brauner authored
    We do embedd struct fown_struct into struct file letting it take up 32
    bytes in total. We could tweak struct fown_struct to be more compact but
    really it shouldn't even be embedded in struct file in the first place.
    
    Instead, actual users of struct fown_struct should allocate the struct
    on demand. This frees up 24 bytes in struct file.
    
    That will have some potentially user-visible changes for the ownership
    fcntl()s. Some of them can now fail due to allocation failures.
    Practically, that probably will almost never happen as the allocations
    are small and they only happen once per file.
    
    The fown_struct is used during kill_fasync() which is used by e.g.,
    pipes to generate a SIGIO signal. Sending of such signals is conditional
    on userspace having set an owner for the file using one of the F_OWNER
    fcntl()s. Such users will be unaffected if struct fown_struct is
    allocated during the fcntl() call.
    
    There are a few subsystems that call __f_setown() expecting
    file->f_owner to be allocated:
    
    (1) tun devices
        file->f_op->fasync::tun_chr_fasync()
        -> __f_setown()
    
        There are no callers of tun_chr_fasync().
    
    (2) tty devices
    
        file->f_op->fasync::tty_fasync()
        -> __tty_fasync()
           -> __f_setown()
    
        tty_fasync() has no additional callers but __tty_fasync() has. Note
        that __tty_fasync() only calls __f_setown() if the @on argument is
        true. It's called from:
    
        file->f_op->release::tty_release()
        -> tty_release()
           -> __tty_fasync()
              -> __f_setown()
    
        tty_release() calls __tty_fasync() with @on false
        => __f_setown() is never called from tty_release().
           => All callers of tty_release() are safe as well.
    
        file->f_op->release::tty_open()
        -> tty_release()
           -> __tty_fasync()
              -> __f_setown()
    
        __tty_hangup() calls __tty_fasync() with @on false
        => __f_setown() is never called from tty_release().
           => All callers of __tty_hangup() are safe as well.
    
    From the callchains it's obvious that (1) and (2) end up getting called
    via file->f_op->fasync(). That can happen either through the F_SETFL
    fcntl() with the FASYNC flag raised or via the FIOASYNC ioctl(). If
    FASYNC is requested and the file isn't already FASYNC then
    file->f_op->fasync() is called with @on true which ends up causing both
    (1) and (2) to call __f_setown().
    
    (1) and (2) are the only subsystems that call __f_setown() from the
    file->f_op->fasync() handler. So both (1) and (2) have been updated to
    allocate a struct fown_struct prior to calling fasync_helper() to
    register with the fasync infrastructure. That's safe as they both call
    fasync_helper() which also does allocations if @on is true.
    
    The other interesting case are file leases:
    
    (3) file leases
        lease_manager_ops->lm_setup::lease_setup()
        -> __f_setown()
    
        Which in turn is called from:
    
        generic_add_lease()
        -> lease_manager_ops->lm_setup::lease_setup()
           -> __f_setown()
    
    So here again we can simply make generic_add_lease() allocate struct
    fown_struct prior to the lease_manager_ops->lm_setup::lease_setup()
    which happens under a spinlock.
    
    With that the two remaining subsystems that call __f_setown() are:
    
    (4) dnotify
    (5) sockets
    
    Both have their own custom ioctls to set struct fown_struct and both
    have been converted to allocate a struct fown_struct on demand from
    their respective ioctls.
    
    Interactions with O_PATH are fine as well e.g., when opening a /dev/tty
    as O_PATH then no file->f_op->open() happens thus no file->f_owner is
    allocated. That's fine as no file operation will be set for those and
    the device has never been opened. fcntl()s called on such things will
    just allocate a ->f_owner on demand. Although I have zero idea why'd you
    care about f_owner on an O_PATH fd.
    
    Link: https://lore.kernel.org/r/20240813-work-f_owner-v2-1-4e9343a79f9f@kernel.orgReviewed-by: default avatarJeff Layton <jlayton@kernel.org>
    Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
    1934b212
dnotify.c 11.1 KB