netdev
[Top] [All Lists]

[PATCH PKT_SCHED 15/22]: police action: fix multiple bugs in init path

To: jamal <hadi@xxxxxxxxxx>
Subject: [PATCH PKT_SCHED 15/22]: police action: fix multiple bugs in init path
From: Patrick McHardy <kaber@xxxxxxxxx>
Date: Mon, 10 Jan 2005 20:38:08 +0100
Cc: Maillist netdev <netdev@xxxxxxxxxxx>
Sender: netdev-bounce@xxxxxxxxxxx
User-agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.3) Gecko/20041008 Debian/1.7.3-5

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2005/01/10 02:43:13+01:00 kaber@xxxxxxxxxxxx 
#   [PKT_SCHED]: police action: fix multiple bugs in init path
#   
#   - Return proper error codes
#   - Some attribute sizes are not checked
#   - rta may by NULL
#   - multiple leaks
#   - possible unbalanced unlock
#   - used action is freed after if an error happens while trying to replace
#   - estimator can't be replaced
#   
#   This patch makes replacement atomic, so the old action is either
#   replaced entirely or not touched at all.
#   
#   Signed-off-by: Patrick McHardy <kaber@xxxxxxxxx>
# 
# net/sched/police.c
#   2005/01/10 02:43:06+01:00 kaber@xxxxxxxxxxxx +49 -37
#   [PKT_SCHED]: police action: fix multiple bugs in init path
#   
#   - Return proper error codes
#   - Some attribute sizes are not checked
#   - rta may by NULL
#   - multiple leaks
#   - possible unbalanced unlock
#   - used action is freed after if an error happens while trying to replace
#   - estimator can't be replaced
#   
#   This patch makes replacement atomic, so the old action is either
#   replaced entirely or not touched at all.
#   
#   Signed-off-by: Patrick McHardy <kaber@xxxxxxxxx>
# 
diff -Nru a/net/sched/police.c b/net/sched/police.c
--- a/net/sched/police.c        2005-01-10 06:22:48 +01:00
+++ b/net/sched/police.c        2005-01-10 06:22:48 +01:00
@@ -165,20 +165,28 @@
                                  struct tc_action *a, int ovr, int bind)
 {
        unsigned h;
-       int ret = 0;
+       int ret = 0, err;
        struct rtattr *tb[TCA_POLICE_MAX];
        struct tc_police *parm;
        struct tcf_police *p;
+       struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL;
 
-       if (rtattr_parse(tb, TCA_POLICE_MAX, RTA_DATA(rta),
-                        RTA_PAYLOAD(rta)) < 0)
-               return -1;
+       if (rta == NULL || rtattr_parse(tb, TCA_POLICE_MAX, RTA_DATA(rta),
+                                       RTA_PAYLOAD(rta)) < 0)
+               return -EINVAL;
 
        if (tb[TCA_POLICE_TBF-1] == NULL ||
            RTA_PAYLOAD(tb[TCA_POLICE_TBF-1]) != sizeof(*parm))
-               return -1;
-
+               return -EINVAL;
        parm = RTA_DATA(tb[TCA_POLICE_TBF-1]);
+
+       if (tb[TCA_POLICE_RESULT-1] != NULL &&
+           RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32))
+               return -EINVAL;
+       if (tb[TCA_POLICE_RESULT-1] != NULL &&
+           RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32))
+               return -EINVAL;
+
        if (parm->index && (p = tcf_police_lookup(parm->index)) != NULL) {
                a->priv = p;
                spin_lock(&p->lock);
@@ -186,18 +194,18 @@
                        p->bindcnt += 1;
                        p->refcnt += 1;
                }
+               spin_unlock(&p->lock);
                if (ovr)
                        goto override;
-               spin_unlock(&p->lock);
                return ret;
        }
 
        p = kmalloc(sizeof(*p), GFP_KERNEL);
        if (p == NULL)
-               return -1;
+               return -ENOMEM;
        memset(p, 0, sizeof(*p));
 
-       ret = 1;
+       ret = ACT_P_CREATED;
        p->refcnt = 1;
        spin_lock_init(&p->lock);
        p->stats_lock = &p->lock;
@@ -205,28 +213,32 @@
                p->bindcnt = 1;
 override:
        if (parm->rate.rate) {
-               p->R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1]);
-               if (p->R_tab == NULL)
+               err = -ENOMEM;
+               R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1]);
+               if (R_tab == NULL)
                        goto failure;
                if (parm->peakrate.rate) {
-                       p->P_tab = qdisc_get_rtab(&parm->peakrate,
-                                                 tb[TCA_POLICE_PEAKRATE-1]);
-                       if (p->P_tab == NULL)
+                       P_tab = qdisc_get_rtab(&parm->peakrate,
+                                              tb[TCA_POLICE_PEAKRATE-1]);
+                       if (p->P_tab == NULL) {
+                               qdisc_put_rtab(R_tab);
                                goto failure;
+                       }
                }
        }
-       if (tb[TCA_POLICE_RESULT-1]) {
-               if (RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32))
-                       goto failure;
-               p->result = *(u32*)RTA_DATA(tb[TCA_POLICE_RESULT-1]);
+       /* No failure allowed after this point */
+       spin_lock(&p->lock);
+       if (R_tab != NULL) {
+               qdisc_put_rtab(p->R_tab);
+               p->R_tab = R_tab;
        }
-#ifdef CONFIG_NET_ESTIMATOR
-       if (tb[TCA_POLICE_AVRATE-1]) {
-               if (RTA_PAYLOAD(tb[TCA_POLICE_AVRATE-1]) != sizeof(u32))
-                       goto failure;
-               p->ewma_rate = *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]);
+       if (P_tab != NULL) {
+               qdisc_put_rtab(p->P_tab);
+               p->P_tab = P_tab;
        }
-#endif
+
+       if (tb[TCA_POLICE_RESULT-1])
+               p->result = *(u32*)RTA_DATA(tb[TCA_POLICE_RESULT-1]);
        p->toks = p->burst = parm->burst;
        p->mtu = parm->mtu;
        if (p->mtu == 0) {
@@ -238,16 +250,19 @@
                p->ptoks = L2T_P(p, p->mtu);
        p->action = parm->action;
 
-       if (ovr) {
-               spin_unlock(&p->lock);
-               return ret;
-       }
-       PSCHED_GET_TIME(p->t_c);
-       p->index = parm->index ? : tcf_police_new_index();
 #ifdef CONFIG_NET_ESTIMATOR
+       if (tb[TCA_POLICE_AVRATE-1])
+               p->ewma_rate = *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]);
        if (est)
-               gen_new_estimator(&p->bstats, &p->rate_est, p->stats_lock, est);
+               gen_replace_estimator(&p->bstats, &p->rate_est, p->stats_lock, 
est);
 #endif
+
+       spin_unlock(&p->lock);
+       if (ret != ACT_P_CREATED)
+               return ret;
+
+       PSCHED_GET_TIME(p->t_c);
+       p->index = parm->index ? : tcf_police_new_index();
        h = tcf_police_hash(p->index);
        write_lock_bh(&police_lock);
        p->next = tcf_police_ht[h];
@@ -258,12 +273,9 @@
        return ret;
 
 failure:
-       if (p->R_tab)
-               qdisc_put_rtab(p->R_tab);
-       if (ovr)
-               spin_unlock(&p->lock);
-       kfree(p);
-       return -1;
+       if (ret == ACT_P_CREATED)
+               kfree(p);
+       return err;
 }
 
 static int tcf_act_police_cleanup(struct tc_action *a, int bind)
<Prev in Thread] Current Thread [Next in Thread>
  • [PATCH PKT_SCHED 15/22]: police action: fix multiple bugs in init path, Patrick McHardy <=