Commit 24b2c435 authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller

[PKT_SCHED]: gact action: fix multiple bugs in init path

- rta can be NULL
- Attribute sizes are not checked
- No locking when replacing an action
- The action is inserted into the hash before its parameters are set

Also return proper error codes.
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b2a6ba1a
...@@ -218,10 +218,10 @@ tcf_hash_search(struct tc_action *a, u32 index) ...@@ -218,10 +218,10 @@ tcf_hash_search(struct tc_action *a, u32 index)
#ifdef CONFIG_NET_ACT_INIT #ifdef CONFIG_NET_ACT_INIT
static inline struct tcf_st * static inline struct tcf_st *
tcf_hash_check(struct tc_st *parm, struct tc_action *a, int ovr, int bind) tcf_hash_check(u32 index, struct tc_action *a, int ovr, int bind)
{ {
struct tcf_st *p = NULL; struct tcf_st *p = NULL;
if (parm->index && (p = tcf_hash_lookup(parm->index)) != NULL) { if (index && (p = tcf_hash_lookup(index)) != NULL) {
spin_lock(&p->lock); spin_lock(&p->lock);
if (bind) { if (bind) {
p->bindcnt++; p->bindcnt++;
...@@ -234,9 +234,8 @@ tcf_hash_check(struct tc_st *parm, struct tc_action *a, int ovr, int bind) ...@@ -234,9 +234,8 @@ tcf_hash_check(struct tc_st *parm, struct tc_action *a, int ovr, int bind)
} }
static inline struct tcf_st * static inline struct tcf_st *
tcf_hash_create(struct tc_st *parm, struct rtattr *est, struct tc_action *a, int size, int ovr, int bind) tcf_hash_create(u32 index, struct rtattr *est, struct tc_action *a, int size, int ovr, int bind)
{ {
unsigned h;
struct tcf_st *p = NULL; struct tcf_st *p = NULL;
p = kmalloc(size, GFP_KERNEL); p = kmalloc(size, GFP_KERNEL);
...@@ -252,31 +251,25 @@ tcf_hash_create(struct tc_st *parm, struct rtattr *est, struct tc_action *a, int ...@@ -252,31 +251,25 @@ tcf_hash_create(struct tc_st *parm, struct rtattr *est, struct tc_action *a, int
spin_lock_init(&p->lock); spin_lock_init(&p->lock);
p->stats_lock = &p->lock; p->stats_lock = &p->lock;
p->index = parm->index ? : tcf_hash_new_index(); p->index = index ? : tcf_hash_new_index();
p->tm.install = jiffies; p->tm.install = jiffies;
p->tm.lastuse = jiffies; p->tm.lastuse = jiffies;
#ifdef CONFIG_NET_ESTIMATOR #ifdef CONFIG_NET_ESTIMATOR
if (est) if (est)
gen_new_estimator(&p->bstats, &p->rate_est, p->stats_lock, est); gen_new_estimator(&p->bstats, &p->rate_est, p->stats_lock, est);
#endif #endif
h = tcf_hash(p->index);
write_lock_bh(&tcf_t_lock);
p->next = tcf_ht[h];
tcf_ht[h] = p;
write_unlock_bh(&tcf_t_lock);
a->priv = (void *) p; a->priv = (void *) p;
return p; return p;
} }
static inline struct tcf_st * static inline void tcf_hash_insert(struct tcf_st *p)
tcf_hash_init(struct tc_st *parm, struct rtattr *est, struct tc_action *a, int size, int ovr, int bind)
{ {
struct tcf_st *p = tcf_hash_check (parm,a,ovr,bind); unsigned h = tcf_hash(p->index);
if (!p) write_lock_bh(&tcf_t_lock);
p = tcf_hash_create(parm, est, a, size, ovr, bind); p->next = tcf_ht[h];
return p; tcf_ht[h] = p;
write_unlock_bh(&tcf_t_lock);
} }
#endif #endif
......
...@@ -75,51 +75,53 @@ static int tcf_gact_init(struct rtattr *rta, struct rtattr *est, ...@@ -75,51 +75,53 @@ static int tcf_gact_init(struct rtattr *rta, struct rtattr *est,
struct tc_action *a, int ovr, int bind) struct tc_action *a, int ovr, int bind)
{ {
struct rtattr *tb[TCA_GACT_MAX]; struct rtattr *tb[TCA_GACT_MAX];
struct tc_gact *parm = NULL; struct tc_gact *parm;
#ifdef CONFIG_GACT_PROB struct tcf_gact *p;
struct tc_gact_p *p_parm = NULL;
#endif
struct tcf_gact *p = NULL;
int ret = 0; int ret = 0;
if (rtattr_parse(tb, TCA_GACT_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta)) < 0) if (rta == NULL ||
return -1; rtattr_parse(tb, TCA_GACT_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta)) < 0)
return -EINVAL;
if (tb[TCA_GACT_PARMS - 1] == NULL) {
printk("BUG: tcf_gact_init called with NULL params\n");
return -1;
}
if (tb[TCA_GACT_PARMS - 1] == NULL ||
RTA_PAYLOAD(tb[TCA_GACT_PARMS - 1]) < sizeof(*parm))
return -EINVAL;
parm = RTA_DATA(tb[TCA_GACT_PARMS - 1]); parm = RTA_DATA(tb[TCA_GACT_PARMS - 1]);
if (tb[TCA_GACT_PROB-1] != NULL)
#ifdef CONFIG_GACT_PROB #ifdef CONFIG_GACT_PROB
if (tb[TCA_GACT_PROB - 1] != NULL) if (RTA_PAYLOAD(tb[TCA_GACT_PROB-1]) < sizeof(struct tc_gact_p))
p_parm = RTA_DATA(tb[TCA_GACT_PROB - 1]); return -EINVAL;
#else
return -EOPNOTSUPP;
#endif #endif
p = tcf_hash_check(parm, a, ovr, bind);
p = tcf_hash_check(parm->index, a, ovr, bind);
if (p == NULL) { if (p == NULL) {
p = tcf_hash_create(parm, est, a, sizeof(*p), ovr, bind); p = tcf_hash_create(parm->index, est, a, sizeof(*p), ovr, bind);
if (p == NULL) if (p == NULL)
return -1; return -ENOMEM;
else { ret = ACT_P_CREATED;
p->refcnt = 1; } else {
ret = 1; if (!ovr) {
goto override; tcf_hash_release(p, bind);
return -EEXIST;
} }
} }
if (ovr) { spin_lock_bh(&p->lock);
override: p->action = parm->action;
p->action = parm->action;
#ifdef CONFIG_GACT_PROB #ifdef CONFIG_GACT_PROB
if (p_parm != NULL) { if (tb[TCA_GACT_PROB-1] != NULL) {
p->paction = p_parm->paction; struct tc_gact_p *p_parm = RTA_DATA(tb[TCA_GACT_PROB-1]);
p->pval = p_parm->pval; p->paction = p_parm->paction;
p->ptype = p_parm->ptype; p->pval = p_parm->pval;
} else { p->ptype = p_parm->ptype;
p->paction = p->pval = p->ptype = 0;
}
#endif
} }
#endif
spin_unlock_bh(&p->lock);
if (ret == ACT_P_CREATED)
tcf_hash_insert(p);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment