diff options
author | Maria Matejka <mq@ucw.cz> | 2023-04-21 15:26:06 +0200 |
---|---|---|
committer | Maria Matejka <mq@ucw.cz> | 2023-04-24 10:33:28 +0200 |
commit | 22f54eaee6c6dbe12ad7bb0ee1da09e3e026b970 (patch) | |
tree | eab05c98833ba8b966005aca6c4dd237fb026ec2 /lib/resource.c | |
parent | 6230d87c74e3629e21f1e0fe22a874a58302a01e (diff) |
Resource pools are now bound with domains.
Memory allocation is a fragile part of BIRD and we need checking that
everybody is using the resource pools in an appropriate way. To assure
this, all the resource pools are associated with locking domains and
every resource manipulation is thoroughly checked whether the
appropriate locking domain is locked.
With transitive resource manipulation like resource dumping or mass free
operations, domains are locked and unlocked on the go, thus we require
pool domains to have higher order than their parent to allow for this
transitive operations.
Adding pool locking revealed some cases of insecure memory manipulation
and this commit fixes that as well.
Diffstat (limited to 'lib/resource.c')
-rw-r--r-- | lib/resource.c | 139 |
1 files changed, 100 insertions, 39 deletions
diff --git a/lib/resource.c b/lib/resource.c index b1b89bdf..2071a411 100644 --- a/lib/resource.c +++ b/lib/resource.c @@ -46,6 +46,16 @@ static struct resclass pool_class = { pool root_pool; +static void +rp_init(pool *z, struct domain_generic *dom, const char *name) +{ + ASSERT_DIE(DG_IS_LOCKED(dom)); + + z->name = name; + z->domain = dom; + z->inside = (TLIST_LIST(resource)) {}; +} + /** * rp_new - create a resource pool * @p: parent pool @@ -55,77 +65,106 @@ pool root_pool; * parent pool. */ pool * -rp_new(pool *p, const char *name) +rp_new(pool *p, struct domain_generic *dom, const char *name) { pool *z = ralloc(p, &pool_class); - z->name = name; - init_list(&z->inside); + + if (dg_order(p->domain) > dg_order(dom)) + bug("Requested reverse order pool creation: %s (%d) can't be a parent of %s (%d)", + domain_name(p->domain), dg_order(p->domain), + domain_name(dom), dg_order(dom)); + + if ((dg_order(p->domain) == dg_order(dom)) && (p->domain != dom)) + bug("Requested incomparable order pool creation: %s (%d) can't be a parent of %s (%d)", + domain_name(p->domain), dg_order(p->domain), + domain_name(dom), dg_order(dom)); + + rp_init(z, dom, name); return z; } pool * -rp_vnewf(pool *p, const char *fmt, va_list args) +rp_vnewf(pool *p, struct domain_generic *dom, const char *fmt, va_list args) { - pool *z = rp_new(p, NULL); + pool *z = rp_new(p, dom, NULL); z->name = mb_vsprintf(p, fmt, args); return z; } pool * -rp_newf(pool *p, const char *fmt, ...) +rp_newf(pool *p, struct domain_generic *dom, const char *fmt, ...) { va_list args; va_start(args, fmt); - pool *z = rp_vnewf(p, fmt, args); + pool *z = rp_vnewf(p, dom, fmt, args); va_end(args); return z; } +#define POOL_LOCK \ + struct domain_generic *dom = p->domain; \ + int locking = !DG_IS_LOCKED(dom); \ + if (locking) \ + DG_LOCK(dom); \ + +#define POOL_UNLOCK if (locking) DG_UNLOCK(dom);\ + +void rp_free(pool *p) +{ + ASSERT_DIE(DG_IS_LOCKED(p->domain)); + rfree(p); +} static void pool_free(resource *P) { pool *p = (pool *) P; - resource *r, *rr; - r = HEAD(p->inside); - while (rr = (resource *) r->n.next) + POOL_LOCK; + WALK_TLIST_DELSAFE(resource, r, &p->inside) { r->class->free(r); xfree(r); - r = rr; } + POOL_UNLOCK; } + static void pool_dump(resource *P, unsigned indent) { pool *p = (pool *) P; - resource *r; + + POOL_LOCK; debug("%s\n", p->name); - WALK_LIST(r, p->inside) + WALK_TLIST_DELSAFE(resource, r, &p->inside) rdump(r, indent + 3); + + POOL_UNLOCK; } static struct resmem pool_memsize(resource *P) { pool *p = (pool *) P; - resource *r; struct resmem sum = { .effective = 0, .overhead = sizeof(pool) + ALLOC_OVERHEAD, }; - WALK_LIST(r, p->inside) + POOL_LOCK; + + WALK_TLIST(resource, r, &p->inside) { struct resmem add = rmemsize(r); sum.effective += add.effective; sum.overhead += add.overhead; } + POOL_UNLOCK; + return sum; } @@ -133,14 +172,25 @@ static resource * pool_lookup(resource *P, unsigned long a) { pool *p = (pool *) P; - resource *r, *q; + resource *q = NULL; + + POOL_LOCK; - WALK_LIST(r, p->inside) + WALK_TLIST(resource, r, &p->inside) if (r->class->lookup && (q = r->class->lookup(r, a))) - return q; - return NULL; + break; + + POOL_UNLOCK; + return q; +} + +static pool * +resource_parent(resource *r) +{ + return SKIP_BACK(pool, inside, resource_enlisted(r)); } + /** * rmove - move a resource * @res: resource @@ -152,13 +202,13 @@ pool_lookup(resource *P, unsigned long a) void rmove(void *res, pool *p) { resource *r = res; + pool *orig = resource_parent(r); - if (r) - { - if (r->n.next) - rem_node(&r->n); - add_tail(&p->inside, &r->n); - } + ASSERT_DIE(DG_IS_LOCKED(orig->domain)); + ASSERT_DIE(DG_IS_LOCKED(p->domain)); + + resource_rem_node(&orig->inside, r); + resource_add_tail(&p->inside, r); } /** @@ -179,8 +229,10 @@ rfree(void *res) if (!r) return; - if (r->n.next) - rem_node(&r->n); + pool *orig = resource_parent(r); + ASSERT_DIE(DG_IS_LOCKED(orig->domain)); + resource_rem_node(&orig->inside, r); + r->class->free(r); r->class = NULL; xfree(r); @@ -239,12 +291,14 @@ rmemsize(void *res) void * ralloc(pool *p, struct resclass *c) { + ASSERT_DIE(DG_IS_LOCKED(p->domain)); + resource *r = xmalloc(c->size); bzero(r, c->size); r->class = c; - if (p) - add_tail(&p->inside, &r->n); + resource_add_tail(&p->inside, r); + return r; } @@ -284,28 +338,29 @@ resource_init(void) rcu_init(); resource_sys_init(); - root_pool.r.class = &pool_class; - root_pool.name = "Root"; - init_list(&root_pool.inside); - tmp_init(&root_pool); + rp_init(&root_pool, the_bird_domain.the_bird, "Root"); + tmp_init(&root_pool, the_bird_domain.the_bird); } _Thread_local struct tmp_resources tmp_res; void -tmp_init(pool *p) +tmp_init(pool *p, struct domain_generic *dom) { tmp_res.lp = lp_new_default(p); tmp_res.parent = p; - tmp_res.pool = rp_new(p, "TMP"); + tmp_res.pool = rp_new(p, dom, "TMP"); + tmp_res.domain = dom; } void tmp_flush(void) { + ASSERT_DIE(DG_IS_LOCKED(tmp_res.domain)); + lp_flush(tmp_linpool); rp_free(tmp_res.pool); - tmp_res.pool = rp_new(tmp_res.parent, "TMP"); + tmp_res.pool = rp_new(tmp_res.parent, tmp_res.domain, "TMP"); } @@ -385,11 +440,13 @@ static struct resclass mb_class = { void * mb_alloc(pool *p, unsigned size) { + ASSERT_DIE(DG_IS_LOCKED(p->domain)); + struct mblock *b = xmalloc(sizeof(struct mblock) + size); b->r.class = &mb_class; - b->r.n = (node) {}; - add_tail(&p->inside, &b->r.n); + b->r.n = (struct resource_node) {}; + resource_add_tail(&p->inside, &b->r); b->size = size; return b->data; } @@ -434,10 +491,14 @@ void * mb_realloc(void *m, unsigned size) { struct mblock *b = SKIP_BACK(struct mblock, data, m); + struct pool *p = resource_parent(&b->r); + + ASSERT_DIE(DG_IS_LOCKED(p->domain)); b = xrealloc(b, sizeof(struct mblock) + size); - update_node(&b->r.n); b->size = size; + + resource_update_node(&p->inside, &b->r); return b->data; } |