Re: [PATCH 3/5] ksmbd: fix kernel oops from idr_remove()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



2022년 7월 22일 (금) 오후 12:04, Namjae Jeon <linkinjeon@xxxxxxxxxx>님이 작성:
>
> There is a report that kernel oops happen from idr_remove().
>
> kernel: BUG: kernel NULL pointer dereference, address: 0000000000000010
> kernel: RIP: 0010:idr_remove+0x1/0x20
> kernel:  __ksmbd_close_fd+0xb2/0x2d0 [ksmbd]
> kernel:  ksmbd_vfs_read+0x91/0x190 [ksmbd]
> kernel:  ksmbd_fd_put+0x29/0x40 [ksmbd]
> kernel:  smb2_read+0x210/0x390 [ksmbd]
> kernel:  __process_request+0xa4/0x180 [ksmbd]
> kernel:  __handle_ksmbd_work+0xf0/0x290 [ksmbd]
> kernel:  handle_ksmbd_work+0x2d/0x50 [ksmbd]
> kernel:  process_one_work+0x21d/0x3f0
> kernel:  worker_thread+0x50/0x3d0
> kernel:  rescuer_thread+0x390/0x390
> kernel:  kthread+0xee/0x120
> kthread_complete_and_exit+0x20/0x20
> kernel:  ret_from_fork+0x22/0x30
>
> While accessing files, If connection is disconnected, windows send
> session setup request included previous session destroy. But while still
> processing requests on previous session, this request destroy file
> table, which mean file table idr will be freed and set to NULL.
> So kernel oops happen from ft->idr in __ksmbd_close_fd().
> This patch don't directly destroy session in destroy_previous_session().
> It just set to KSMBD_SESS_EXITING so that connection will be
> terminated after finishing the rest of requests.
>
> Signed-off-by: Namjae Jeon <linkinjeon@xxxxxxxxxx>

Looks good to me.
Reviewed-by: Hyunchul Lee <hyc.lee@xxxxxxxxx>

> ---
>  fs/ksmbd/mgmt/user_session.c | 2 ++
>  fs/ksmbd/smb2pdu.c           | 8 ++++++--
>  2 files changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/fs/ksmbd/mgmt/user_session.c b/fs/ksmbd/mgmt/user_session.c
> index 25e9ba3b7550..b9acb6770b03 100644
> --- a/fs/ksmbd/mgmt/user_session.c
> +++ b/fs/ksmbd/mgmt/user_session.c
> @@ -239,6 +239,8 @@ struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
>         sess = ksmbd_session_lookup(conn, id);
>         if (!sess && conn->binding)
>                 sess = ksmbd_session_lookup_slowpath(id);
> +       if (sess && sess->state != SMB2_SESSION_VALID)
> +               sess = NULL;
>         return sess;
>  }
>
> diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c
> index 5a0328a070dc..ae5677a66cb2 100644
> --- a/fs/ksmbd/smb2pdu.c
> +++ b/fs/ksmbd/smb2pdu.c
> @@ -593,6 +593,7 @@ static void destroy_previous_session(struct ksmbd_conn *conn,
>  {
>         struct ksmbd_session *prev_sess = ksmbd_session_lookup_slowpath(id);
>         struct ksmbd_user *prev_user;
> +       struct channel *chann;
>
>         if (!prev_sess)
>                 return;
> @@ -608,8 +609,11 @@ static void destroy_previous_session(struct ksmbd_conn *conn,
>         }
>
>         put_session(prev_sess);
> -       xa_erase(&conn->sessions, prev_sess->id);
> -       ksmbd_session_destroy(prev_sess);
> +       prev_sess->state = SMB2_SESSION_EXPIRED;
> +       write_lock(&prev_sess->chann_lock);
> +       list_for_each_entry(chann, &prev_sess->ksmbd_chann_list, chann_list)
> +               chann->conn->status = KSMBD_SESS_EXITING;
> +       write_unlock(&prev_sess->chann_lock);
>  }
>
>  /**
> --
> 2.25.1
>


-- 
Thanks,
Hyunchul




[Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux