On Thu, Jun 20, 2019 at 5:52 AM Davide Caratti <dcara...@redhat.com> wrote: > > hello Cong, thanks for reading. > > On Wed, 2019-06-19 at 15:04 -0700, Cong Wang wrote: > > On Wed, Jun 19, 2019 at 2:10 PM Davide Caratti <dcara...@redhat.com> wrote: > > > on some CPUs (e.g. i686), tcf_walker.cookie has the same size as the IDR. > > > In this situation, the following script: > > > > > > # tc filter add dev eth0 ingress handle 0xffffffff flower action ok > > > # tc filter show dev eth0 ingress > > > > > > results in an infinite loop. It happened also on other CPUs (e.g x86_64), > > > before commit 061775583e35 ("net: sched: flower: introduce reference > > > counting for filters"), because 'handle' + 1 made the u32 overflow before > > > it was assigned to 'cookie'; but that commit replaced the assignment with > > > a self-increment of 'cookie', so the problem was indirectly fixed. > > > > Interesting... Is this really specific to cls_flower? To me it looks like > > a bug of idr_*_ul() API's, especially for idr_for_each_entry_ul(). > > good question, I have to investigate this better (idr_for_each_entry_ul() > expands in a iteration of idr_get_next_ul()). It surely got in cls_flower > when it was converted to use IDRs, but it's true that there might be other > points in TC where IDR are used and the same pattern is present (see > below).
Yeah, this means we probably want to fix it in idr_get_next_ul() or its callers like idr_for_each_entry_ul(). > > > Can you test if the following command has the same problem on i386? > > > > tc actions add action ok index 4294967295 > > the action is added, but then reading it back results in an infinite loop. > And again, the infinite loop happens on i686 and not on x86_64. I will try > to see where's the problem also here. Right, this is what I expect, thanks for confirming it. I am not sure it is better to handle this overflow inside idr_get_next_ul() or just let its callers to handle it. According to the comments above idr_get_next_ul() it sounds like it is not expected to overflow, so... diff --git a/lib/idr.c b/lib/idr.c index c34e256d2f01..a38f5e391cec 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -267,6 +267,9 @@ void *idr_get_next_ul(struct idr *idr, unsigned long *nextid) if (!slot) return NULL; + /* overflow */ + if (iter.index < id) + return NULL; *nextid = iter.index + base; return rcu_dereference_raw(*slot); }