lkml.org 
[lkml]   [2024]   [Jan]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH AUTOSEL 6.6 25/31] ceph: fix invalid pointer access if get_quota_realm return ERR_PTR
    Date
    From: Wenchao Hao <haowenchao2@huawei.com>

    [ Upstream commit 0f4cf64eabc6e16cfc2704f1960e82dc79d91c8d ]

    This issue is reported by smatch that get_quota_realm() might return
    ERR_PTR but we did not handle it. It's not a immediate bug, while we
    still should address it to avoid potential bugs if get_quota_realm()
    is changed to return other ERR_PTR in future.

    Set ceph_snap_realm's pointer in get_quota_realm()'s to address this
    issue, the pointer would be set to NULL if get_quota_realm() failed
    to get struct ceph_snap_realm, so no ERR_PTR would happen any more.

    [ xiubli: minor code style clean up ]

    Signed-off-by: Wenchao Hao <haowenchao2@huawei.com>
    Reviewed-by: Xiubo Li <xiubli@redhat.com>
    Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    fs/ceph/quota.c | 39 ++++++++++++++++++++++-----------------
    1 file changed, 22 insertions(+), 17 deletions(-)

    diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c
    index f7fcf7f08ec6..ca4932e6f71b 100644
    --- a/fs/ceph/quota.c
    +++ b/fs/ceph/quota.c
    @@ -194,10 +194,10 @@ void ceph_cleanup_quotarealms_inodes(struct ceph_mds_client *mdsc)
    }

    /*
    - * This function walks through the snaprealm for an inode and returns the
    - * ceph_snap_realm for the first snaprealm that has quotas set (max_files,
    + * This function walks through the snaprealm for an inode and set the
    + * realmp with the first snaprealm that has quotas set (max_files,
    * max_bytes, or any, depending on the 'which_quota' argument). If the root is
    - * reached, return the root ceph_snap_realm instead.
    + * reached, set the realmp with the root ceph_snap_realm instead.
    *
    * Note that the caller is responsible for calling ceph_put_snap_realm() on the
    * returned realm.
    @@ -208,18 +208,19 @@ void ceph_cleanup_quotarealms_inodes(struct ceph_mds_client *mdsc)
    * this function will return -EAGAIN; otherwise, the snaprealms walk-through
    * will be restarted.
    */
    -static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc,
    - struct inode *inode,
    - enum quota_get_realm which_quota,
    - bool retry)
    +static int get_quota_realm(struct ceph_mds_client *mdsc, struct inode *inode,
    + enum quota_get_realm which_quota,
    + struct ceph_snap_realm **realmp, bool retry)
    {
    struct ceph_inode_info *ci = NULL;
    struct ceph_snap_realm *realm, *next;
    struct inode *in;
    bool has_quota;

    + if (realmp)
    + *realmp = NULL;
    if (ceph_snap(inode) != CEPH_NOSNAP)
    - return NULL;
    + return 0;

    restart:
    realm = ceph_inode(inode)->i_snap_realm;
    @@ -245,7 +246,7 @@ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc,
    break;
    ceph_put_snap_realm(mdsc, realm);
    if (!retry)
    - return ERR_PTR(-EAGAIN);
    + return -EAGAIN;
    goto restart;
    }

    @@ -254,8 +255,11 @@ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc,
    iput(in);

    next = realm->parent;
    - if (has_quota || !next)
    - return realm;
    + if (has_quota || !next) {
    + if (realmp)
    + *realmp = realm;
    + return 0;
    + }

    ceph_get_snap_realm(mdsc, next);
    ceph_put_snap_realm(mdsc, realm);
    @@ -264,7 +268,7 @@ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc,
    if (realm)
    ceph_put_snap_realm(mdsc, realm);

    - return NULL;
    + return 0;
    }

    bool ceph_quota_is_same_realm(struct inode *old, struct inode *new)
    @@ -272,6 +276,7 @@ bool ceph_quota_is_same_realm(struct inode *old, struct inode *new)
    struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(old->i_sb);
    struct ceph_snap_realm *old_realm, *new_realm;
    bool is_same;
    + int ret;

    restart:
    /*
    @@ -281,9 +286,9 @@ bool ceph_quota_is_same_realm(struct inode *old, struct inode *new)
    * dropped and we can then restart the whole operation.
    */
    down_read(&mdsc->snap_rwsem);
    - old_realm = get_quota_realm(mdsc, old, QUOTA_GET_ANY, true);
    - new_realm = get_quota_realm(mdsc, new, QUOTA_GET_ANY, false);
    - if (PTR_ERR(new_realm) == -EAGAIN) {
    + get_quota_realm(mdsc, old, QUOTA_GET_ANY, &old_realm, true);
    + ret = get_quota_realm(mdsc, new, QUOTA_GET_ANY, &new_realm, false);
    + if (ret == -EAGAIN) {
    up_read(&mdsc->snap_rwsem);
    if (old_realm)
    ceph_put_snap_realm(mdsc, old_realm);
    @@ -485,8 +490,8 @@ bool ceph_quota_update_statfs(struct ceph_fs_client *fsc, struct kstatfs *buf)
    bool is_updated = false;

    down_read(&mdsc->snap_rwsem);
    - realm = get_quota_realm(mdsc, d_inode(fsc->sb->s_root),
    - QUOTA_GET_MAX_BYTES, true);
    + get_quota_realm(mdsc, d_inode(fsc->sb->s_root), QUOTA_GET_MAX_BYTES,
    + &realm, true);
    up_read(&mdsc->snap_rwsem);
    if (!realm)
    return false;
    --
    2.43.0

    \
     
     \ /
      Last update: 2024-05-27 14:37    [W:2.138 / U:0.064 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site