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

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

- Return proper error codes
- Attribute sizes are not checked
- rta may by NULL
- The action is inserted into the hash before its parameters are set
- replacement happens without locking
- no reallocation on replacement for possibly changed numbers of keys
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cab1d7bb
...@@ -8,7 +8,7 @@ struct tcf_pedit ...@@ -8,7 +8,7 @@ struct tcf_pedit
tca_gen(pedit); tca_gen(pedit);
unsigned char nkeys; unsigned char nkeys;
unsigned char flags; unsigned char flags;
struct tc_pedit_key keys[0]; struct tc_pedit_key *keys;
}; };
#endif #endif
...@@ -58,40 +58,60 @@ tcf_pedit_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, ...@@ -58,40 +58,60 @@ tcf_pedit_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a,
{ {
struct rtattr *tb[TCA_PEDIT_MAX]; struct rtattr *tb[TCA_PEDIT_MAX];
struct tc_pedit *parm; struct tc_pedit *parm;
int size = 0;
int ret = 0; int ret = 0;
struct tcf_pedit *p; struct tcf_pedit *p;
struct tc_pedit_key *keys = NULL;
if (rtattr_parse(tb, TCA_PEDIT_MAX, RTA_DATA(rta), int ksize;
RTA_PAYLOAD(rta)) < 0)
return -1; if (rta == NULL || rtattr_parse(tb, TCA_PEDIT_MAX, RTA_DATA(rta),
if (tb[TCA_PEDIT_PARMS - 1] == NULL) { RTA_PAYLOAD(rta)) < 0)
printk("BUG: tcf_pedit_init called with NULL params\n"); return -EINVAL;
return -1;
} if (tb[TCA_PEDIT_PARMS - 1] == NULL ||
RTA_PAYLOAD(tb[TCA_PEDIT_PARMS-1]) < sizeof(*parm))
parm = RTA_DATA(tb[TCA_PEDIT_PARMS - 1]); return -EINVAL;
p = tcf_hash_check(parm, a, ovr, bind); parm = RTA_DATA(tb[TCA_PEDIT_PARMS-1]);
if (p == NULL) { /* new */ ksize = parm->nkeys * sizeof(struct tc_pedit_key);
if (RTA_PAYLOAD(tb[TCA_PEDIT_PARMS-1]) < sizeof(*parm) + ksize)
return -EINVAL;
p = tcf_hash_check(parm->index, a, ovr, bind);
if (p == NULL) {
if (!parm->nkeys) if (!parm->nkeys)
return -1; return -EINVAL;
size = sizeof(*p) + parm->nkeys * sizeof(struct tc_pedit_key); p = tcf_hash_create(parm->index, est, a, sizeof(*p), ovr, bind);
p = tcf_hash_create(parm, est, a, size, ovr, bind);
if (p == NULL) if (p == NULL)
return -1; return -ENOMEM;
ret = 1; keys = kmalloc(ksize, GFP_KERNEL);
goto override; if (keys == NULL) {
} kfree(p);
return -ENOMEM;
if (ovr) { }
override: ret = ACT_P_CREATED;
p->flags = parm->flags; } else {
p->nkeys = parm->nkeys; if (!ovr) {
p->action = parm->action; tcf_hash_release(p, bind);
memcpy(p->keys, parm->keys, return -EEXIST;
parm->nkeys * sizeof(struct tc_pedit_key)); }
if (p->nkeys && p->nkeys != parm->nkeys) {
keys = kmalloc(ksize, GFP_KERNEL);
if (keys == NULL)
return -ENOMEM;
}
} }
spin_lock_bh(&p->lock);
p->flags = parm->flags;
p->action = parm->action;
if (keys) {
kfree(p->keys);
p->keys = keys;
p->nkeys = parm->nkeys;
}
memcpy(p->keys, parm->keys, ksize);
spin_unlock_bh(&p->lock);
if (ret == ACT_P_CREATED)
tcf_hash_insert(p);
return ret; return ret;
} }
...@@ -100,8 +120,13 @@ tcf_pedit_cleanup(struct tc_action *a, int bind) ...@@ -100,8 +120,13 @@ tcf_pedit_cleanup(struct tc_action *a, int bind)
{ {
struct tcf_pedit *p = PRIV(a, pedit); struct tcf_pedit *p = PRIV(a, pedit);
if (NULL != p) if (p != NULL) {
return tcf_hash_release(p, bind); struct tc_pedit_key *keys = p->keys;
if (tcf_hash_release(p, bind)) {
kfree(keys);
return 1;
}
}
return 0; return 0;
} }
......
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