When using flowtable llentrys can outlive the interface with which they're associated
at which the lle_tbl pointer points to freed memory and the llt_free pointer is no longer valid. Move the free pointer in to the llentry itself and update the initalization sites. MFC after: 2 weeks
This commit is contained in:
parent
ffbbf1cb2c
commit
a99e9d281d
@ -106,7 +106,6 @@ struct llentry {
|
||||
("negative refcnt %d", (lle)->lle_refcnt)); \
|
||||
(lle)->lle_refcnt++; \
|
||||
} while (0)
|
||||
|
||||
#define LLE_REMREF(lle) do { \
|
||||
LLE_WLOCK_ASSERT(lle); \
|
||||
KASSERT((lle)->lle_refcnt > 1, \
|
||||
@ -116,7 +115,7 @@ struct llentry {
|
||||
|
||||
#define LLE_FREE_LOCKED(lle) do { \
|
||||
if ((lle)->lle_refcnt <= 1) \
|
||||
(lle)->lle_tbl->llt_free((lle)->lle_tbl, (lle));\
|
||||
(lle)->lle_free((lle)->lle_tbl, (lle));\
|
||||
else { \
|
||||
(lle)->lle_refcnt--; \
|
||||
LLE_WUNLOCK(lle); \
|
||||
@ -152,7 +151,6 @@ struct lltable {
|
||||
int llt_af;
|
||||
struct ifnet *llt_ifp;
|
||||
|
||||
void (*llt_free)(struct lltable *, struct llentry *);
|
||||
void (*llt_prefix_free)(struct lltable *,
|
||||
const struct sockaddr *prefix,
|
||||
const struct sockaddr *mask,
|
||||
|
@ -1260,6 +1260,20 @@ struct in_llentry {
|
||||
struct sockaddr_in l3_addr4;
|
||||
};
|
||||
|
||||
/*
|
||||
* Deletes an address from the address table.
|
||||
* This function is called by the timer functions
|
||||
* such as arptimer() and nd6_llinfo_timer(), and
|
||||
* the caller does the locking.
|
||||
*/
|
||||
static void
|
||||
in_lltable_free(struct lltable *llt, struct llentry *lle)
|
||||
{
|
||||
LLE_WUNLOCK(lle);
|
||||
LLE_LOCK_DESTROY(lle);
|
||||
free(lle, M_LLTABLE);
|
||||
}
|
||||
|
||||
static struct llentry *
|
||||
in_lltable_new(const struct sockaddr *l3addr, u_int flags)
|
||||
{
|
||||
@ -1277,25 +1291,11 @@ in_lltable_new(const struct sockaddr *l3addr, u_int flags)
|
||||
lle->base.la_expire = time_uptime; /* mark expired */
|
||||
lle->l3_addr4 = *(const struct sockaddr_in *)l3addr;
|
||||
lle->base.lle_refcnt = 1;
|
||||
lle->base.lle_free = in_lltable_free;
|
||||
LLE_LOCK_INIT(&lle->base);
|
||||
return &lle->base;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deletes an address from the address table.
|
||||
* This function is called by the timer functions
|
||||
* such as arptimer() and nd6_llinfo_timer(), and
|
||||
* the caller does the locking.
|
||||
*/
|
||||
static void
|
||||
in_lltable_free(struct lltable *llt, struct llentry *lle)
|
||||
{
|
||||
LLE_WUNLOCK(lle);
|
||||
LLE_LOCK_DESTROY(lle);
|
||||
free(lle, M_LLTABLE);
|
||||
}
|
||||
|
||||
|
||||
#define IN_ARE_MASKED_ADDR_EQUAL(d, a, m) ( \
|
||||
(((ntohl((d)->sin_addr.s_addr) ^ (a)->sin_addr.s_addr) & (m)->sin_addr.s_addr)) == 0 )
|
||||
|
||||
@ -1577,7 +1577,6 @@ in_domifattach(struct ifnet *ifp)
|
||||
|
||||
llt = lltable_init(ifp, AF_INET);
|
||||
if (llt != NULL) {
|
||||
llt->llt_free = in_lltable_free;
|
||||
llt->llt_prefix_free = in_lltable_prefix_free;
|
||||
llt->llt_lookup = in_lltable_lookup;
|
||||
llt->llt_dump = in_lltable_dump;
|
||||
|
@ -2439,25 +2439,6 @@ struct in6_llentry {
|
||||
struct sockaddr_in6 l3_addr6;
|
||||
};
|
||||
|
||||
static struct llentry *
|
||||
in6_lltable_new(const struct sockaddr *l3addr, u_int flags)
|
||||
{
|
||||
struct in6_llentry *lle;
|
||||
|
||||
lle = malloc(sizeof(struct in6_llentry), M_LLTABLE,
|
||||
M_DONTWAIT | M_ZERO);
|
||||
if (lle == NULL) /* NB: caller generates msg */
|
||||
return NULL;
|
||||
|
||||
lle->l3_addr6 = *(const struct sockaddr_in6 *)l3addr;
|
||||
lle->base.lle_refcnt = 1;
|
||||
LLE_LOCK_INIT(&lle->base);
|
||||
callout_init_rw(&lle->base.ln_timer_ch, &lle->base.lle_lock,
|
||||
CALLOUT_RETURNUNLOCKED);
|
||||
|
||||
return &lle->base;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deletes an address from the address table.
|
||||
* This function is called by the timer functions
|
||||
@ -2472,6 +2453,26 @@ in6_lltable_free(struct lltable *llt, struct llentry *lle)
|
||||
free(lle, M_LLTABLE);
|
||||
}
|
||||
|
||||
static struct llentry *
|
||||
in6_lltable_new(const struct sockaddr *l3addr, u_int flags)
|
||||
{
|
||||
struct in6_llentry *lle;
|
||||
|
||||
lle = malloc(sizeof(struct in6_llentry), M_LLTABLE,
|
||||
M_DONTWAIT | M_ZERO);
|
||||
if (lle == NULL) /* NB: caller generates msg */
|
||||
return NULL;
|
||||
|
||||
lle->l3_addr6 = *(const struct sockaddr_in6 *)l3addr;
|
||||
lle->base.lle_refcnt = 1;
|
||||
lle->base.lle_free = in6_lltable_free;
|
||||
LLE_LOCK_INIT(&lle->base);
|
||||
callout_init_rw(&lle->base.ln_timer_ch, &lle->base.lle_lock,
|
||||
CALLOUT_RETURNUNLOCKED);
|
||||
|
||||
return &lle->base;
|
||||
}
|
||||
|
||||
static void
|
||||
in6_lltable_prefix_free(struct lltable *llt,
|
||||
const struct sockaddr *prefix,
|
||||
@ -2713,7 +2714,6 @@ in6_domifattach(struct ifnet *ifp)
|
||||
ext->scope6_id = scope6_ifattach(ifp);
|
||||
ext->lltable = lltable_init(ifp, AF_INET6);
|
||||
if (ext->lltable != NULL) {
|
||||
ext->lltable->llt_free = in6_lltable_free;
|
||||
ext->lltable->llt_prefix_free = in6_lltable_prefix_free;
|
||||
ext->lltable->llt_lookup = in6_lltable_lookup;
|
||||
ext->lltable->llt_dump = in6_lltable_dump;
|
||||
|
Loading…
Reference in New Issue
Block a user