On 14/06/16(Tue) 20:10, Florian Obser wrote:
> On Tue, Jun 14, 2016 at 06:26:00PM +0200, Martin Pieuchot wrote:
> > On 14/06/16(Tue) 15:18, Florian Obser wrote:
> > > Hi,
> > > I'm seeing this panic on my v6 gateway running in a vm (don't ask):
> > > It has a v6 tunnel via HE on gif0.
> > >
> > > I hope I copied all relevant information, if not, my appologies, I'm
> > > in a hurry currently, please just ask for more.
> > >
> > > I will probably investigate more when I'm home :)
> > >
> > > panic: trap type 6, code=0, pc=ffffffff812fe70f
> > > Starting stack trace...
> > > panic() at panic+0x10b
> > > trap() at trap+0x7b8
> > > --- trap (number 6) ---
> > > ip6_output_ipsec_lookup() at ip6_output_ipsec_lookup+0x6f
> > > ip6_output() at ip6_output+0x21c
> > > esp_output_cb() at esp_output_cb+0x135
> > > taskq_thread() at taskq_thread+0x6c
> > > end trace frame: 0x0, count: 251
> > > End of stack trace.
> > > syncing disks... done
> >
> > This seems to be an invalid `'tdbi'' dereference in
> > ip6_output_ipsec_lookup():
> >
> > 2890: tdbi = (struct tdb_ident *)(mtag + 1);
> > 2891: HERE -> if (tdbi->spi == tdb->tdb_spi &&
> > 2892: tdbi->proto == tdb->tdb_sproto &&
> > ...
> >
> > Markus, Mike any idea how this could happen?
>
> I tracked it down to ref 1.89 of ip6_forward.c / ref 1.205 ip6_output.c:
> "factor out ipsec into ip6_output_ipsec_{lookup,send}(); ok mpi@, naddy@"
>
> The problem is that we are not exiting the "loop detection" for loop
> when tdb is set to NULL. We enter again and dereference tdb -> boom.
>
> The following diff makes ip6_output_ipsec_lookup() similar to
> ip_output_ipsec_lookup().
> It's easier to see what the diff is doing by applying and doing diff -b.
> OK?
ok mpi@
> p.s. I also note that the v4 and v6 version are really similiar, we
> can probably merge them. Wonder if it's worth it or if it's best to
> keep v4 and v6 seperate...
For the moment we're trying to reduce the size of "#ifdef IPSEC" chunks
inside the IP paths. But reducing differences between v4 and v6 by
reusing code is a good thing.
> diff --git ip6_output.c ip6_output.c
> index 64eea86..3adaa7d 100644
> --- ip6_output.c
> +++ ip6_output.c
> @@ -2882,21 +2882,21 @@ ip6_output_ipsec_lookup(struct mbuf *m, int *error,
> struct inpcb *inp)
> tdb = ipsp_spd_lookup(m, AF_INET6, sizeof(struct ip6_hdr),
> error, IPSP_DIRECTION_OUT, NULL, inp, 0);
>
> - if (tdb != NULL) {
> - /* Loop detection */
> - for (mtag = m_tag_first(m); mtag != NULL;
> - mtag = m_tag_next(m, mtag)) {
> - if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE)
> - continue;
> - tdbi = (struct tdb_ident *)(mtag + 1);
> - if (tdbi->spi == tdb->tdb_spi &&
> - tdbi->proto == tdb->tdb_sproto &&
> - tdbi->rdomain == tdb->tdb_rdomain &&
> - !bcmp(&tdbi->dst, &tdb->tdb_dst,
> - sizeof(union sockaddr_union)))
> - tdb = NULL;
> + if (tdb == NULL)
> + return NULL;
> + /* Loop detection */
> + for (mtag = m_tag_first(m); mtag != NULL; mtag = m_tag_next(m, mtag)) {
> + if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE)
> + continue;
> + tdbi = (struct tdb_ident *)(mtag + 1);
> + if (tdbi->spi == tdb->tdb_spi &&
> + tdbi->proto == tdb->tdb_sproto &&
> + tdbi->rdomain == tdb->tdb_rdomain &&
> + !memcmp(&tdbi->dst, &tdb->tdb_dst,
> + sizeof(union sockaddr_union))) {
> + /* no IPsec needed */
> + return NULL;
> }
> - /* We need to do IPsec */
> }
> return tdb;
> }
>
>
> --
> I'm not entirely sure you are real.
>