child-sa: Handle refcount overflow for unique mark/if_id allocation gracefully
The refcount_t for allocating unique marks and interface IDs may overflow or hit the special value for unique marks/if_ids, in the worst case not setting it on CHILD_SAs that should have one. As (potentially two) marks/if_ids are allocated only for newly created CHILD_SAs, but not for rekeying, this not very likely. Still, if a setup uses aggressive re-authentication and or re-creates CHILD_SAs every minute, a gateway with 100'000 tunnels may hit the overflow within a month uptime.
This commit is contained in:
committed by
Tobias Brunner
parent
dde40bcb9e
commit
1a740bf3f3
@@ -150,30 +150,44 @@ bool mark_from_string(const char *value, mark_op_t ops, mark_t *mark)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate a unique mark that is non-zero and not one of the special values.
|
||||||
|
*/
|
||||||
|
static uint32_t allocate_unique_mark()
|
||||||
|
{
|
||||||
|
static refcount_t unique_mark = 0;
|
||||||
|
uint32_t m;
|
||||||
|
|
||||||
|
m = ref_get_nonzero(&unique_mark);
|
||||||
|
while (MARK_IS_UNIQUE(m))
|
||||||
|
{
|
||||||
|
m = ref_get_nonzero(&unique_mark);
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Described in header
|
* Described in header
|
||||||
*/
|
*/
|
||||||
void allocate_unique_marks(uint32_t *in, uint32_t *out)
|
void allocate_unique_marks(uint32_t *in, uint32_t *out)
|
||||||
{
|
{
|
||||||
static refcount_t unique_mark = 0;
|
|
||||||
|
|
||||||
if (MARK_IS_UNIQUE(*in) || MARK_IS_UNIQUE(*out))
|
if (MARK_IS_UNIQUE(*in) || MARK_IS_UNIQUE(*out))
|
||||||
{
|
{
|
||||||
refcount_t mark = 0;
|
uint32_t mark = 0;
|
||||||
bool unique_dir = *in == MARK_UNIQUE_DIR ||
|
bool unique_dir = *in == MARK_UNIQUE_DIR ||
|
||||||
*out == MARK_UNIQUE_DIR;
|
*out == MARK_UNIQUE_DIR;
|
||||||
|
|
||||||
if (!unique_dir)
|
if (!unique_dir)
|
||||||
{
|
{
|
||||||
mark = ref_get(&unique_mark);
|
mark = allocate_unique_mark();
|
||||||
}
|
}
|
||||||
if (MARK_IS_UNIQUE(*in))
|
if (MARK_IS_UNIQUE(*in))
|
||||||
{
|
{
|
||||||
*in = unique_dir ? ref_get(&unique_mark) : mark;
|
*in = unique_dir ? allocate_unique_mark() : mark;
|
||||||
}
|
}
|
||||||
if (MARK_IS_UNIQUE(*out))
|
if (MARK_IS_UNIQUE(*out))
|
||||||
{
|
{
|
||||||
*out = unique_dir ? ref_get(&unique_mark) : mark;
|
*out = unique_dir ? allocate_unique_mark() : mark;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -219,30 +233,46 @@ bool if_id_from_string(const char *value, uint32_t *if_id)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate a unique interface ID that is non-zero and not one of the special
|
||||||
|
* values.
|
||||||
|
*/
|
||||||
|
static uint32_t allocate_unique_if_id()
|
||||||
|
{
|
||||||
|
static refcount_t unique_if_id = 0;
|
||||||
|
uint32_t if_id;
|
||||||
|
|
||||||
|
if_id = ref_get_nonzero(&unique_if_id);
|
||||||
|
while (IF_ID_IS_UNIQUE(if_id))
|
||||||
|
{
|
||||||
|
if_id = ref_get_nonzero(&unique_if_id);
|
||||||
|
}
|
||||||
|
return if_id;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Described in header
|
* Described in header
|
||||||
*/
|
*/
|
||||||
void allocate_unique_if_ids(uint32_t *in, uint32_t *out)
|
void allocate_unique_if_ids(uint32_t *in, uint32_t *out)
|
||||||
{
|
{
|
||||||
static refcount_t unique_if_id = 0;
|
|
||||||
|
|
||||||
if (IF_ID_IS_UNIQUE(*in) || IF_ID_IS_UNIQUE(*out))
|
if (IF_ID_IS_UNIQUE(*in) || IF_ID_IS_UNIQUE(*out))
|
||||||
{
|
{
|
||||||
refcount_t if_id = 0;
|
uint32_t if_id = 0;
|
||||||
bool unique_dir = *in == IF_ID_UNIQUE_DIR ||
|
bool unique_dir = *in == IF_ID_UNIQUE_DIR ||
|
||||||
*out == IF_ID_UNIQUE_DIR;
|
*out == IF_ID_UNIQUE_DIR;
|
||||||
|
|
||||||
if (!unique_dir)
|
if (!unique_dir)
|
||||||
{
|
{
|
||||||
if_id = ref_get(&unique_if_id);
|
if_id = allocate_unique_if_id();
|
||||||
}
|
}
|
||||||
if (IF_ID_IS_UNIQUE(*in))
|
if (IF_ID_IS_UNIQUE(*in))
|
||||||
{
|
{
|
||||||
*in = unique_dir ? ref_get(&unique_if_id) : if_id;
|
*in = unique_dir ? allocate_unique_if_id() : if_id;
|
||||||
}
|
}
|
||||||
if (IF_ID_IS_UNIQUE(*out))
|
if (IF_ID_IS_UNIQUE(*out))
|
||||||
{
|
{
|
||||||
*out = unique_dir ? ref_get(&unique_if_id) : if_id;
|
*out = unique_dir ? allocate_unique_if_id() : if_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user