Thread (37 messages) 37 messages, 3 authors, 2018-08-14

Re: [PATCH net-next v6 11/11] net: sched: change action API to use array of pointers to actions

From: Vlad Buslov <hidden>
Date: 2018-08-09 09:26:48

On Wed 08 Aug 2018 at 18:29, Cong Wang [off-list ref] wrote:
On Wed, Aug 8, 2018 at 4:41 AM Vlad Buslov [off-list ref] wrote:
quoted

On Tue 07 Aug 2018 at 23:26, Cong Wang [off-list ref] wrote:
quoted
On Thu, Jul 5, 2018 at 7:24 AM Vlad Buslov [off-list ref] wrote:
quoted
        attr_size = tcf_action_full_attrs_size(attr_size);

        if (event == RTM_GETACTION)
-               ret = tcf_get_notify(net, portid, n, &actions, event, extack);
+               ret = tcf_get_notify(net, portid, n, actions, event, extack);
        else { /* delete */
-               ret = tcf_del_notify(net, n, &actions, portid, attr_size, extack);
+               ret = tcf_del_notify(net, n, actions, &acts_deleted, portid,
+                                    attr_size, extack);
                if (ret)
                        goto err;
                return ret;
        }
 err:
-       tcf_action_put_lst(&actions);
+       tcf_action_put_many(&actions[acts_deleted]);
        return ret;
How does this even work?

You save an index in 'acts_deleted', but you pass &actions[acts_deleted]
to tcf_action_put_many(), which seems you want to start from
where it fails, but inside tcf_action_put_many() it starts from 0
to TCA_ACT_MAX_PRIO, out-of-bound access at least?
Actions array is declared to be TCA_ACT_MAX_PRIO+1 in size, and

Declaration doesn't matter at all, functions see it as a pure pointer
once you pass it as an argument.

quoted
initialized to NULL pointers. In loop inside tcf_action_put_many() there
are two checks: One is that index is less than TCA_ACT_MAX_PRIO and
another one that pointer is not NULL. In this case I rely on extra NULL
pointer at the end of actions array to prevent out-of-bound access.
True, but you pass &actions[acts_deleted] as the start of the array,
so inside it would be:

&actions[acts_deleted][0]...&actions[acts_deleted][MAX_PRIO]

So, the overall of the result is:

actions[acts_deleted]...actions[acts_deleted + MAX_PRIO]

You have out-of-bound access when acts_deleted > 1.

And if acts_deleted == MAX_PRIO-1, then you don't have any
NULL pointer to rely on.
Lets look at the loop inside tcf_action_put_many():

	for (i = 0; i < TCA_ACT_MAX_PRIO && actions[i]; i++) {
		struct tc_action *a = actions[i];
		const struct tc_action_ops *ops = a->ops;

		if (tcf_action_put(a))
			module_put(ops->owner);
	}

In the case you highlighted I rely on second conditional - pointer to
action in array is not NULL. As I already explained in my previous
email, by making initial array TCA_ACT_MAX_PRIO+1 in size I ensure that
there is always a NULL pointer at the end of sequence of actions pointed
by 'actions' pointer/array.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help