Pedro Tammela says: ==================== net/sched: fix action bind logic Some actions are not handling the case where an action can be created and bound to a filter independently. These actions are checking for parameters only passed in the netlink message for create/change/replace, which then errors out for valid uses like: tc filter ... action pedit index 1 In the iproute2 side, we saw a couple of actions with their parsers broken when passing "index 1" as the only action argument, while the kernel side accepted it correctly. We fixed those as well. ====================
Unified · Split
| @@ -190,40 +190,67 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla, · 189 unmodified lines | ||
| 190 | 190 | parm = nla_data(tb[TCA_MPLS_PARMS]); |
| 191 | 191 | index = parm->index; |
| 192 | 192 | |
| 193 | + err = tcf_idr_check_alloc(tn, &index, a, bind); | |
| 194 | + if (err < 0) | |
| 195 | + return err; | |
| 196 | + exists = err; | |
| 197 | + if (exists && bind) | |
| 198 | + return 0; | |
| 199 | + | |
| 200 | + if (!exists) { | |
| 201 | + ret = tcf_idr_create(tn, index, est, a, &act_mpls_ops, bind, | |
| 202 | + true, flags); | |
| 203 | + if (ret) { | |
| 204 | + tcf_idr_cleanup(tn, index); | |
| 205 | + return ret; | |
| 206 | + } | |
| 207 | + | |
| 208 | + ret = ACT_P_CREATED; | |
| 209 | + } else if (!(flags & TCA_ACT_FLAGS_REPLACE)) { | |
| 210 | + tcf_idr_release(*a, bind); | |
| 211 | + return -EEXIST; | |
| 212 | + } | |
| 213 | + | |
| 193 | 214 | /* Verify parameters against action type. */ |
| 194 | 215 | switch (parm->m_action) { |
| 195 | 216 | case TCA_MPLS_ACT_POP: |
| 196 | 217 | if (!tb[TCA_MPLS_PROTO]) { |
| 197 | 218 | NL_SET_ERR_MSG_MOD(extack, "Protocol must be set for MPLS pop"); |
| 198 | − return -EINVAL; | |
| 219 | + err = -EINVAL; | |
| 220 | + goto release_idr; | |
| 199 | 221 | } |
| 200 | 222 | if (!eth_proto_is_802_3(nla_get_be16(tb[TCA_MPLS_PROTO]))) { |
| 201 | 223 | NL_SET_ERR_MSG_MOD(extack, "Invalid protocol type for MPLS pop"); |
| 202 | − return -EINVAL; | |
| 224 | + err = -EINVAL; | |
| 225 | + goto release_idr; | |
| 203 | 226 | } |
| 204 | 227 | if (tb[TCA_MPLS_LABEL] || tb[TCA_MPLS_TTL] || tb[TCA_MPLS_TC] || |
| 205 | 228 | tb[TCA_MPLS_BOS]) { |
| 206 | 229 | NL_SET_ERR_MSG_MOD(extack, "Label, TTL, TC or BOS cannot be used with MPLS pop"); |
| 207 | − return -EINVAL; | |
| 230 | + err = -EINVAL; | |
| 231 | + goto release_idr; | |
| 208 | 232 | } |
| 209 | 233 | break; |
| 210 | 234 | case TCA_MPLS_ACT_DEC_TTL: |
| 211 | 235 | if (tb[TCA_MPLS_PROTO] || tb[TCA_MPLS_LABEL] || |
| 212 | 236 | tb[TCA_MPLS_TTL] || tb[TCA_MPLS_TC] || tb[TCA_MPLS_BOS]) { |
| 213 | 237 | NL_SET_ERR_MSG_MOD(extack, "Label, TTL, TC, BOS or protocol cannot be used with MPLS dec_ttl"); |
| 214 | − return -EINVAL; | |
| 238 | + err = -EINVAL; | |
| 239 | + goto release_idr; | |
| 215 | 240 | } |
| 216 | 241 | break; |
| 217 | 242 | case TCA_MPLS_ACT_PUSH: |
| 218 | 243 | case TCA_MPLS_ACT_MAC_PUSH: |
| 219 | 244 | if (!tb[TCA_MPLS_LABEL]) { |
| 220 | 245 | NL_SET_ERR_MSG_MOD(extack, "Label is required for MPLS push"); |
| 221 | − return -EINVAL; | |
| 246 | + err = -EINVAL; | |
| 247 | + goto release_idr; | |
| 222 | 248 | } |
| 223 | 249 | if (tb[TCA_MPLS_PROTO] && |
| 224 | 250 | !eth_p_mpls(nla_get_be16(tb[TCA_MPLS_PROTO]))) { |
| 225 | 251 | NL_SET_ERR_MSG_MOD(extack, "Protocol must be an MPLS type for MPLS push"); |
| 226 | − return -EPROTONOSUPPORT; | |
| 252 | + err = -EPROTONOSUPPORT; | |
| 253 | + goto release_idr; | |
| 227 | 254 | } |
| 228 | 255 | /* Push needs a TTL - if not specified, set a default value. */ |
| 229 | 256 | if (!tb[TCA_MPLS_TTL]) { |
| @@ -238,33 +265,14 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla, · 8 unmodified lines | ||
| 238 | 265 | case TCA_MPLS_ACT_MODIFY: |
| 239 | 266 | if (tb[TCA_MPLS_PROTO]) { |
| 240 | 267 | NL_SET_ERR_MSG_MOD(extack, "Protocol cannot be used with MPLS modify"); |
| 241 | − return -EINVAL; | |
| 268 | + err = -EINVAL; | |
| 269 | + goto release_idr; | |
| 242 | 270 | } |
| 243 | 271 | break; |
| 244 | 272 | default: |
| 245 | 273 | NL_SET_ERR_MSG_MOD(extack, "Unknown MPLS action"); |
| 246 | − return -EINVAL; | |
| 247 | − } | |
| 248 | − | |
| 249 | − err = tcf_idr_check_alloc(tn, &index, a, bind); | |
| 250 | − if (err < 0) | |
| 251 | − return err; | |
| 252 | − exists = err; | |
| 253 | − if (exists && bind) | |
| 254 | − return 0; | |
| 255 | − | |
| 256 | − if (!exists) { | |
| 257 | − ret = tcf_idr_create(tn, index, est, a, | |
| 258 | − &act_mpls_ops, bind, true, flags); | |
| 259 | − if (ret) { | |
| 260 | − tcf_idr_cleanup(tn, index); | |
| 261 | − return ret; | |
| 262 | − } | |
| 263 | − | |
| 264 | − ret = ACT_P_CREATED; | |
| 265 | − } else if (!(flags & TCA_ACT_FLAGS_REPLACE)) { | |
| 266 | − tcf_idr_release(*a, bind); | |
| 267 | − return -EEXIST; | |
| 274 | + err = -EINVAL; | |
| 275 | + goto release_idr; | |
| 268 | 276 | } |
| 269 | 277 | |
| 270 | 278 | err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); |
| @@ -181,26 +181,6 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, · 180 unmodified lines | ||
| 181 | 181 | } |
| 182 | 182 | |
| 183 | 183 | parm = nla_data(pattr); |
| 184 | − if (!parm->nkeys) { | |
| 185 | − NL_SET_ERR_MSG_MOD(extack, "Pedit requires keys to be passed"); | |
| 186 | − return -EINVAL; | |
| 187 | − } | |
| 188 | − ksize = parm->nkeys * sizeof(struct tc_pedit_key); | |
| 189 | − if (nla_len(pattr) < sizeof(*parm) + ksize) { | |
| 190 | − NL_SET_ERR_MSG_ATTR(extack, pattr, "Length of TCA_PEDIT_PARMS or TCA_PEDIT_PARMS_EX pedit attribute is invalid"); | |
| 191 | − return -EINVAL; | |
| 192 | − } | |
| 193 | − | |
| 194 | − nparms = kzalloc(sizeof(*nparms), GFP_KERNEL); | |
| 195 | − if (!nparms) | |
| 196 | − return -ENOMEM; | |
| 197 | − | |
| 198 | − nparms->tcfp_keys_ex = | |
| 199 | − tcf_pedit_keys_ex_parse(tb[TCA_PEDIT_KEYS_EX], parm->nkeys); | |
| 200 | − if (IS_ERR(nparms->tcfp_keys_ex)) { | |
| 201 | − ret = PTR_ERR(nparms->tcfp_keys_ex); | |
| 202 | − goto out_free; | |
| 203 | − } | |
| 204 | 184 | |
| 205 | 185 | index = parm->index; |
| 206 | 186 | err = tcf_idr_check_alloc(tn, &index, a, bind); |
| @@ -209,25 +189,49 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, · 2 unmodified lines | ||
| 209 | 189 | &act_pedit_ops, bind, flags); |
| 210 | 190 | if (ret) { |
| 211 | 191 | tcf_idr_cleanup(tn, index); |
| 212 | − goto out_free_ex; | |
| 192 | + return ret; | |
| 213 | 193 | } |
| 214 | 194 | ret = ACT_P_CREATED; |
| 215 | 195 | } else if (err > 0) { |
| 216 | 196 | if (bind) |
| 217 | − goto out_free; | |
| 197 | + return 0; | |
| 218 | 198 | if (!(flags & TCA_ACT_FLAGS_REPLACE)) { |
| 219 | 199 | ret = -EEXIST; |
| 220 | 200 | goto out_release; |
| 221 | 201 | } |
| 222 | 202 | } else { |
| 223 | − ret = err; | |
| 224 | − goto out_free_ex; | |
| 203 | + return err; | |
| 204 | + } | |
| 205 | + | |
| 206 | + if (!parm->nkeys) { | |
| 207 | + NL_SET_ERR_MSG_MOD(extack, "Pedit requires keys to be passed"); | |
| 208 | + ret = -EINVAL; | |
| 209 | + goto out_release; | |
| 210 | + } | |
| 211 | + ksize = parm->nkeys * sizeof(struct tc_pedit_key); | |
| 212 | + if (nla_len(pattr) < sizeof(*parm) + ksize) { | |
| 213 | + NL_SET_ERR_MSG_ATTR(extack, pattr, "Length of TCA_PEDIT_PARMS or TCA_PEDIT_PARMS_EX pedit attribute is invalid"); | |
| 214 | + ret = -EINVAL; | |
| 215 | + goto out_release; | |
| 216 | + } | |
| 217 | + | |
| 218 | + nparms = kzalloc(sizeof(*nparms), GFP_KERNEL); | |
| 219 | + if (!nparms) { | |
| 220 | + ret = -ENOMEM; | |
| 221 | + goto out_release; | |
| 222 | + } | |
| 223 | + | |
| 224 | + nparms->tcfp_keys_ex = | |
| 225 | + tcf_pedit_keys_ex_parse(tb[TCA_PEDIT_KEYS_EX], parm->nkeys); | |
| 226 | + if (IS_ERR(nparms->tcfp_keys_ex)) { | |
| 227 | + ret = PTR_ERR(nparms->tcfp_keys_ex); | |
| 228 | + goto out_free; | |
| 225 | 229 | } |
| 226 | 230 | |
| 227 | 231 | err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); |
| 228 | 232 | if (err < 0) { |
| 229 | 233 | ret = err; |
| 230 | − goto out_release; | |
| 234 | + goto out_free_ex; | |
| 231 | 235 | } |
| 232 | 236 | |
| 233 | 237 | nparms->tcfp_off_max_hint = 0; |
| @@ -278,12 +282,12 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, · 44 unmodified lines | ||
| 278 | 282 | put_chain: |
| 279 | 283 | if (goto_ch) |
| 280 | 284 | tcf_chain_put_by_act(goto_ch); |
| 281 | −out_release: | |
| 282 | − tcf_idr_release(*a, bind); | |
| 283 | 285 | out_free_ex: |
| 284 | 286 | kfree(nparms->tcfp_keys_ex); |
| 285 | 287 | out_free: |
| 286 | 288 | kfree(nparms); |
| 289 | +out_release: | |
| 290 | + tcf_idr_release(*a, bind); | |
| 287 | 291 | return ret; |
| 288 | 292 | } |
| 289 | 293 | |
| @@ -55,8 +55,8 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla, · 54 unmodified lines | ||
| 55 | 55 | sample_policy, NULL); |
| 56 | 56 | if (ret < 0) |
| 57 | 57 | return ret; |
| 58 | − if (!tb[TCA_SAMPLE_PARMS] || !tb[TCA_SAMPLE_RATE] || | |
| 59 | − !tb[TCA_SAMPLE_PSAMPLE_GROUP]) | |
| 58 | + | |
| 59 | + if (!tb[TCA_SAMPLE_PARMS]) | |
| 60 | 60 | return -EINVAL; |
| 61 | 61 | |
| 62 | 62 | parm = nla_data(tb[TCA_SAMPLE_PARMS]); |
| @@ -80,6 +80,13 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla, · 17 unmodified lines | ||
| 80 | 80 | tcf_idr_release(*a, bind); |
| 81 | 81 | return -EEXIST; |
| 82 | 82 | } |
| 83 | + | |
| 84 | + if (!tb[TCA_SAMPLE_RATE] || !tb[TCA_SAMPLE_PSAMPLE_GROUP]) { | |
| 85 | + NL_SET_ERR_MSG(extack, "sample rate and group are required"); | |
| 86 | + err = -EINVAL; | |
| 87 | + goto release_idr; | |
| 88 | + } | |
| 89 | + | |
| 83 | 90 | err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); |
| 84 | 91 | if (err < 0) |
| 85 | 92 | goto release_idr; |