lkml.org 
[lkml]   [2018]   [Sep]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.18 099/145] nfsd: fix leaked file lock with nfs exported overlayfs
    Date
    4.18-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Amir Goldstein <amir73il@gmail.com>

    commit 64bed6cbe38bc95689fb9399872d9ce250192f90 upstream.

    nfsd and lockd call vfs_lock_file() to lock/unlock the inode
    returned by locks_inode(file).

    Many places in nfsd/lockd code use the inode returned by
    file_inode(file) for lock manipulation. With Overlayfs, file_inode()
    (the underlying inode) is not the same object as locks_inode() (the
    overlay inode). This can result in "Leaked POSIX lock" messages
    and eventually to a kernel crash as reported by Eddie Horng:
    https://marc.info/?l=linux-unionfs&m=153086643202072&w=2

    Fix all the call sites in nfsd/lockd that should use locks_inode().
    This is a correctness bug that manifested when overlayfs gained
    NFS export support in v4.16.

    Reported-by: Eddie Horng <eddiehorng.tw@gmail.com>
    Tested-by: Eddie Horng <eddiehorng.tw@gmail.com>
    Cc: Jeff Layton <jlayton@kernel.org>
    Fixes: 8383f1748829 ("ovl: wire up NFS export operations")
    Cc: stable@vger.kernel.org
    Signed-off-by: Amir Goldstein <amir73il@gmail.com>
    Signed-off-by: J. Bruce Fields <bfields@redhat.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    fs/lockd/clntlock.c | 2 +-
    fs/lockd/clntproc.c | 2 +-
    fs/lockd/svclock.c | 16 ++++++++--------
    fs/lockd/svcsubs.c | 4 ++--
    fs/nfsd/nfs4state.c | 2 +-
    include/linux/lockd/lockd.h | 4 ++--
    6 files changed, 15 insertions(+), 15 deletions(-)

    --- a/fs/lockd/clntlock.c
    +++ b/fs/lockd/clntlock.c
    @@ -187,7 +187,7 @@ __be32 nlmclnt_grant(const struct sockad
    continue;
    if (!rpc_cmp_addr(nlm_addr(block->b_host), addr))
    continue;
    - if (nfs_compare_fh(NFS_FH(file_inode(fl_blocked->fl_file)) ,fh) != 0)
    + if (nfs_compare_fh(NFS_FH(locks_inode(fl_blocked->fl_file)), fh) != 0)
    continue;
    /* Alright, we found a lock. Set the return status
    * and wake up the caller
    --- a/fs/lockd/clntproc.c
    +++ b/fs/lockd/clntproc.c
    @@ -128,7 +128,7 @@ static void nlmclnt_setlockargs(struct n
    char *nodename = req->a_host->h_rpcclnt->cl_nodename;

    nlmclnt_next_cookie(&argp->cookie);
    - memcpy(&lock->fh, NFS_FH(file_inode(fl->fl_file)), sizeof(struct nfs_fh));
    + memcpy(&lock->fh, NFS_FH(locks_inode(fl->fl_file)), sizeof(struct nfs_fh));
    lock->caller = nodename;
    lock->oh.data = req->a_owner;
    lock->oh.len = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s",
    --- a/fs/lockd/svclock.c
    +++ b/fs/lockd/svclock.c
    @@ -405,8 +405,8 @@ nlmsvc_lock(struct svc_rqst *rqstp, stru
    __be32 ret;

    dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
    - file_inode(file->f_file)->i_sb->s_id,
    - file_inode(file->f_file)->i_ino,
    + locks_inode(file->f_file)->i_sb->s_id,
    + locks_inode(file->f_file)->i_ino,
    lock->fl.fl_type, lock->fl.fl_pid,
    (long long)lock->fl.fl_start,
    (long long)lock->fl.fl_end,
    @@ -511,8 +511,8 @@ nlmsvc_testlock(struct svc_rqst *rqstp,
    __be32 ret;

    dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n",
    - file_inode(file->f_file)->i_sb->s_id,
    - file_inode(file->f_file)->i_ino,
    + locks_inode(file->f_file)->i_sb->s_id,
    + locks_inode(file->f_file)->i_ino,
    lock->fl.fl_type,
    (long long)lock->fl.fl_start,
    (long long)lock->fl.fl_end);
    @@ -566,8 +566,8 @@ nlmsvc_unlock(struct net *net, struct nl
    int error;

    dprintk("lockd: nlmsvc_unlock(%s/%ld, pi=%d, %Ld-%Ld)\n",
    - file_inode(file->f_file)->i_sb->s_id,
    - file_inode(file->f_file)->i_ino,
    + locks_inode(file->f_file)->i_sb->s_id,
    + locks_inode(file->f_file)->i_ino,
    lock->fl.fl_pid,
    (long long)lock->fl.fl_start,
    (long long)lock->fl.fl_end);
    @@ -595,8 +595,8 @@ nlmsvc_cancel_blocked(struct net *net, s
    int status = 0;

    dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n",
    - file_inode(file->f_file)->i_sb->s_id,
    - file_inode(file->f_file)->i_ino,
    + locks_inode(file->f_file)->i_sb->s_id,
    + locks_inode(file->f_file)->i_ino,
    lock->fl.fl_pid,
    (long long)lock->fl.fl_start,
    (long long)lock->fl.fl_end);
    --- a/fs/lockd/svcsubs.c
    +++ b/fs/lockd/svcsubs.c
    @@ -44,7 +44,7 @@ static inline void nlm_debug_print_fh(ch

    static inline void nlm_debug_print_file(char *msg, struct nlm_file *file)
    {
    - struct inode *inode = file_inode(file->f_file);
    + struct inode *inode = locks_inode(file->f_file);

    dprintk("lockd: %s %s/%ld\n",
    msg, inode->i_sb->s_id, inode->i_ino);
    @@ -414,7 +414,7 @@ nlmsvc_match_sb(void *datap, struct nlm_
    {
    struct super_block *sb = datap;

    - return sb == file_inode(file->f_file)->i_sb;
    + return sb == locks_inode(file->f_file)->i_sb;
    }

    /**
    --- a/fs/nfsd/nfs4state.c
    +++ b/fs/nfsd/nfs4state.c
    @@ -6293,7 +6293,7 @@ check_for_locks(struct nfs4_file *fp, st
    return status;
    }

    - inode = file_inode(filp);
    + inode = locks_inode(filp);
    flctx = inode->i_flctx;

    if (flctx && !list_empty_careful(&flctx->flc_posix)) {
    --- a/include/linux/lockd/lockd.h
    +++ b/include/linux/lockd/lockd.h
    @@ -299,7 +299,7 @@ int nlmsvc_unlock_all_by_ip(st

    static inline struct inode *nlmsvc_file_inode(struct nlm_file *file)
    {
    - return file_inode(file->f_file);
    + return locks_inode(file->f_file);
    }

    static inline int __nlm_privileged_request4(const struct sockaddr *sap)
    @@ -359,7 +359,7 @@ static inline int nlm_privileged_request
    static inline int nlm_compare_locks(const struct file_lock *fl1,
    const struct file_lock *fl2)
    {
    - return file_inode(fl1->fl_file) == file_inode(fl2->fl_file)
    + return locks_inode(fl1->fl_file) == locks_inode(fl2->fl_file)
    && fl1->fl_pid == fl2->fl_pid
    && fl1->fl_owner == fl2->fl_owner
    && fl1->fl_start == fl2->fl_start

    \
     
     \ /
      Last update: 2018-09-07 23:24    [W:4.168 / U:0.004 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site