lkml.org 
[lkml]   [2018]   [Sep]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.9 14/78] act_ife: fix a potential deadlock
    Date
    4.9-stable review patch.  If anyone has any objections, please let me know.

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

    From: Cong Wang <xiyou.wangcong@gmail.com>

    [ Upstream commit 5ffe57da29b3802baeddaa40909682bbb4cb4d48 ]

    use_all_metadata() acquires read_lock(&ife_mod_lock), then calls
    add_metainfo() which calls find_ife_oplist() which acquires the same
    lock again. Deadlock!

    Introduce __add_metainfo() which accepts struct tcf_meta_ops *ops
    as an additional parameter and let its callers to decide how
    to find it. For use_all_metadata(), it already has ops, no
    need to find it again, just call __add_metainfo() directly.

    And, as ife_mod_lock is only needed for find_ife_oplist(),
    this means we can make non-atomic allocation for populate_metalist()
    now.

    Fixes: 817e9f2c5c26 ("act_ife: acquire ife_mod_lock before reading ifeoplist")
    Cc: Jamal Hadi Salim <jhs@mojatatu.com>
    Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    net/sched/act_ife.c | 34 +++++++++++++++++++++-------------
    1 file changed, 21 insertions(+), 13 deletions(-)

    --- a/net/sched/act_ife.c
    +++ b/net/sched/act_ife.c
    @@ -296,22 +296,16 @@ static int load_metaops_and_vet(u32 meta

    /* called when adding new meta information
    */
    -static int add_metainfo(struct tcf_ife_info *ife, u32 metaid, void *metaval,
    - int len, bool atomic, bool exists)
    +static int __add_metainfo(const struct tcf_meta_ops *ops,
    + struct tcf_ife_info *ife, u32 metaid, void *metaval,
    + int len, bool atomic, bool exists)
    {
    struct tcf_meta_info *mi = NULL;
    - struct tcf_meta_ops *ops = find_ife_oplist(metaid);
    int ret = 0;

    - if (!ops)
    - return -ENOENT;
    -
    mi = kzalloc(sizeof(*mi), atomic ? GFP_ATOMIC : GFP_KERNEL);
    - if (!mi) {
    - /*put back what find_ife_oplist took */
    - module_put(ops->owner);
    + if (!mi)
    return -ENOMEM;
    - }

    mi->metaid = metaid;
    mi->ops = ops;
    @@ -319,7 +313,6 @@ static int add_metainfo(struct tcf_ife_i
    ret = ops->alloc(mi, metaval, atomic ? GFP_ATOMIC : GFP_KERNEL);
    if (ret != 0) {
    kfree(mi);
    - module_put(ops->owner);
    return ret;
    }
    }
    @@ -333,6 +326,21 @@ static int add_metainfo(struct tcf_ife_i
    return ret;
    }

    +static int add_metainfo(struct tcf_ife_info *ife, u32 metaid, void *metaval,
    + int len, bool exists)
    +{
    + const struct tcf_meta_ops *ops = find_ife_oplist(metaid);
    + int ret;
    +
    + if (!ops)
    + return -ENOENT;
    + ret = __add_metainfo(ops, ife, metaid, metaval, len, false, exists);
    + if (ret)
    + /*put back what find_ife_oplist took */
    + module_put(ops->owner);
    + return ret;
    +}
    +
    static int use_all_metadata(struct tcf_ife_info *ife, bool exists)
    {
    struct tcf_meta_ops *o;
    @@ -341,7 +349,7 @@ static int use_all_metadata(struct tcf_i

    read_lock(&ife_mod_lock);
    list_for_each_entry(o, &ifeoplist, list) {
    - rc = add_metainfo(ife, o->metaid, NULL, 0, true, exists);
    + rc = __add_metainfo(o, ife, o->metaid, NULL, 0, true, exists);
    if (rc == 0)
    installed += 1;
    }
    @@ -430,7 +438,7 @@ static int populate_metalist(struct tcf_
    if (rc != 0)
    return rc;

    - rc = add_metainfo(ife, i, val, len, false, exists);
    + rc = add_metainfo(ife, i, val, len, exists);
    if (rc)
    return rc;
    }

    \
     
     \ /
      Last update: 2018-09-13 16:19    [W:4.050 / U:0.124 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site