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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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))
|
||||
{
|
||||
refcount_t mark = 0;
|
||||
uint32_t mark = 0;
|
||||
bool unique_dir = *in == MARK_UNIQUE_DIR ||
|
||||
*out == MARK_UNIQUE_DIR;
|
||||
|
||||
if (!unique_dir)
|
||||
{
|
||||
mark = ref_get(&unique_mark);
|
||||
mark = allocate_unique_mark();
|
||||
}
|
||||
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))
|
||||
{
|
||||
*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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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))
|
||||
{
|
||||
refcount_t if_id = 0;
|
||||
uint32_t if_id = 0;
|
||||
bool unique_dir = *in == IF_ID_UNIQUE_DIR ||
|
||||
*out == IF_ID_UNIQUE_DIR;
|
||||
|
||||
if (!unique_dir)
|
||||
{
|
||||
if_id = ref_get(&unique_if_id);
|
||||
if_id = allocate_unique_if_id();
|
||||
}
|
||||
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))
|
||||
{
|
||||
*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