summaryrefslogtreecommitdiff
path: root/nest
diff options
context:
space:
mode:
authorMaria Matejka <mq@ucw.cz>2023-04-21 15:26:06 +0200
committerMaria Matejka <mq@ucw.cz>2023-04-24 10:33:28 +0200
commit22f54eaee6c6dbe12ad7bb0ee1da09e3e026b970 (patch)
treeeab05c98833ba8b966005aca6c4dd237fb026ec2 /nest
parent6230d87c74e3629e21f1e0fe22a874a58302a01e (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 'nest')
-rw-r--r--nest/cli.c6
-rw-r--r--nest/cli.h1
-rw-r--r--nest/iface.c7
-rw-r--r--nest/locks.h1
-rw-r--r--nest/password.h2
-rw-r--r--nest/proto.c12
-rw-r--r--nest/protocol.h2
-rw-r--r--nest/rt-attr.c20
-rw-r--r--nest/rt-show.c1
-rw-r--r--nest/rt-table.c63
-rw-r--r--nest/rt.h3
11 files changed, 79 insertions, 39 deletions
diff --git a/nest/cli.c b/nest/cli.c
index 29591d26..b74edffb 100644
--- a/nest/cli.c
+++ b/nest/cli.c
@@ -262,7 +262,7 @@ cli_command(struct cli *c)
log(L_TRACE "CLI: %s", c->rx_buf);
bzero(&f, sizeof(f));
f.mem = c->parser_pool;
- f.pool = rp_new(c->pool, "Config");
+ f.pool = rp_new(c->pool, the_bird_domain.the_bird, "Config");
init_list(&f.symbols);
cf_read_hook = cli_cmd_read_hook;
cli_rh_pos = c->rx_buf;
@@ -309,7 +309,7 @@ cli_event(void *data)
cli *
cli_new(struct birdsock *sock)
{
- pool *p = rp_new(cli_pool, "CLI");
+ pool *p = rp_new(cli_pool, the_bird_domain.the_bird, "CLI");
cli *c = mb_alloc(p, sizeof(cli));
bzero(c, sizeof(cli));
@@ -433,7 +433,7 @@ cli_free(cli *c)
void
cli_init(void)
{
- cli_pool = rp_new(&root_pool, "CLI");
+ cli_pool = rp_new(&root_pool, the_bird_domain.the_bird, "CLI");
init_list(&cli_log_hooks);
cli_log_inited = 1;
}
diff --git a/nest/cli.h b/nest/cli.h
index 2d876571..c5cbd8d7 100644
--- a/nest/cli.h
+++ b/nest/cli.h
@@ -10,6 +10,7 @@
#define _BIRD_CLI_H_
#include "lib/resource.h"
+#include "lib/lists.h"
#include "lib/event.h"
#define CLI_RX_BUF_SIZE 4096
diff --git a/nest/iface.c b/nest/iface.c
index f1938664..a024b943 100644
--- a/nest/iface.c
+++ b/nest/iface.c
@@ -1018,12 +1018,15 @@ if_choose_router_id(struct iface_patt *mask, u32 old_id)
void
if_init(void)
{
- if_pool = rp_new(&root_pool, "Interfaces");
+ iface_domain = DOMAIN_NEW(attrs, "Interfaces");
+
+ IFACE_LOCK;
+ if_pool = rp_new(&root_pool, iface_domain.attrs, "Interfaces");
init_list(&global_iface_list);
iface_sub_slab = sl_new(if_pool, sizeof(struct iface_notification));
strcpy(default_vrf.name, "default");
neigh_init(if_pool);
- iface_domain = DOMAIN_NEW(attrs, "Interfaces");
+ IFACE_UNLOCK;
}
/*
diff --git a/nest/locks.h b/nest/locks.h
index 04571e69..993e296b 100644
--- a/nest/locks.h
+++ b/nest/locks.h
@@ -10,6 +10,7 @@
#define _BIRD_LOCKS_H_
#include "lib/resource.h"
+#include "lib/lists.h"
#include "lib/event.h"
/*
diff --git a/nest/password.h b/nest/password.h
index 53168bb7..335b9cd4 100644
--- a/nest/password.h
+++ b/nest/password.h
@@ -10,6 +10,8 @@
#ifndef PASSWORD_H
#define PASSWORD_H
+#include "lib/lists.h"
+
struct password_item {
node n;
const char *password; /* Key data, null terminated */
diff --git a/nest/proto.c b/nest/proto.c
index d6269272..32183c9d 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -367,6 +367,7 @@ channel_roa_subscribe(struct channel *c, rtable *tab, int dir)
.name = mb_sprintf(c->proto->pool, "%s.%s.roa-%s.%s",
c->proto->name, c->name, dir ? "in" : "out", tab->name),
.list = proto_work_list(c->proto),
+ .pool = c->proto->pool,
.trace_routes = c->debug | c->proto->debug,
.dump_req = channel_dump_roa_req,
.export_one = channel_export_one_roa,
@@ -495,6 +496,7 @@ channel_start_export(struct channel *c)
c->out_req = (struct rt_export_request) {
.name = mb_sprintf(c->proto->pool, "%s.%s", c->proto->name, c->name),
.list = proto_work_list(c->proto),
+ .pool = c->proto->pool,
.addr = c->out_subprefix,
.addr_mode = c->out_subprefix ? TE_ADDR_IN : TE_ADDR_NONE,
.trace_routes = c->debug | c->proto->debug,
@@ -685,6 +687,7 @@ channel_setup_in_table(struct channel *c)
c->reload_req = (struct rt_export_request) {
.name = mb_sprintf(c->proto->pool, "%s.%s.import", c->proto->name, c->name),
.list = proto_work_list(c->proto),
+ .pool = c->proto->pool,
.trace_routes = c->debug | c->proto->debug,
.export_bulk = channel_reload_export_bulk,
.dump_req = channel_reload_dump_req,
@@ -1132,15 +1135,14 @@ proto_loop_stopped(void *ptr)
{
struct proto *p = ptr;
- birdloop_enter(&main_birdloop);
+ ASSERT_DIE(birdloop_inside(&main_birdloop));
+ ASSERT_DIE(p->loop != &main_birdloop);
p->pool = NULL; /* is freed by birdloop_free() */
birdloop_free(p->loop);
p->loop = &main_birdloop;
proto_cleanup(p);
-
- birdloop_leave(&main_birdloop);
}
static void
@@ -1228,7 +1230,7 @@ proto_start(struct proto *p)
p->pool = birdloop_pool(p->loop);
}
else
- p->pool = rp_newf(proto_pool, "Protocol %s", p->cf->name);
+ p->pool = rp_newf(proto_pool, the_bird_domain.the_bird, "Protocol %s", p->cf->name);
p->iface_sub.target = proto_event_list(p);
@@ -1859,7 +1861,7 @@ protos_build(void)
{
protos_build_gen();
- proto_pool = rp_new(&root_pool, "Protocols");
+ proto_pool = rp_new(&root_pool, the_bird_domain.the_bird, "Protocols");
}
diff --git a/nest/protocol.h b/nest/protocol.h
index eccfcb73..02ec5c15 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -280,6 +280,8 @@ struct proto *proto_iterate_named(struct symbol *sym, struct protocol *proto, st
#define PROTO_LOCKED_FROM_MAIN(p) for (struct birdloop *_proto_loop = PROTO_ENTER_FROM_MAIN(p); _proto_loop; PROTO_LEAVE_FROM_MAIN(_proto_loop), (_proto_loop = NULL))
+static inline struct domain_generic *proto_domain(struct proto *p)
+{ return birdloop_domain(p->loop); }
#define CMD_RELOAD 0
#define CMD_RELOAD_IN 1
diff --git a/nest/rt-attr.c b/nest/rt-attr.c
index 903926f6..38612a4e 100644
--- a/nest/rt-attr.c
+++ b/nest/rt-attr.c
@@ -605,9 +605,16 @@ ea_register(pool *p, struct ea_class *def)
struct ea_class_ref *
ea_register_alloc(pool *p, struct ea_class cl)
{
+ struct ea_class_ref *ref;
+
+ RTA_LOCK;
struct ea_class *clp = ea_class_find_by_name(cl.name);
if (clp && clp->type == cl.type)
- return ea_ref_class(p, clp);
+ {
+ ref = ea_ref_class(p, clp);
+ RTA_UNLOCK;
+ return ref;
+ }
uint namelen = strlen(cl.name) + 1;
@@ -619,14 +626,18 @@ ea_register_alloc(pool *p, struct ea_class cl)
memcpy(cla->name, cl.name, namelen);
cla->cl.name = cla->name;
- return ea_register(p, &cla->cl);
+ ref = ea_register(p, &cla->cl);
+ RTA_UNLOCK;
+ return ref;
}
void
ea_register_init(struct ea_class *clp)
{
+ RTA_LOCK;
ASSERT_DIE(!ea_class_find_by_name(clp->name));
ea_register(&root_pool, clp);
+ RTA_UNLOCK;
}
struct ea_class *
@@ -1598,7 +1609,8 @@ rta_init(void)
{
attrs_domain = DOMAIN_NEW(attrs, "Attributes");
- rta_pool = rp_new(&root_pool, "Attributes");
+ RTA_LOCK;
+ rta_pool = rp_new(&root_pool, attrs_domain.attrs, "Attributes");
for (uint i=0; i<ARRAY_SIZE(ea_slab_sizes); i++)
ea_slab[i] = sl_new(rta_pool, ea_slab_sizes[i]);
@@ -1607,6 +1619,8 @@ rta_init(void)
rte_src_init();
ea_class_init();
+ RTA_UNLOCK;
+
/* These attributes are required to be first for nice "show route" output */
ea_register_init(&ea_gen_nexthop);
ea_register_init(&ea_gen_hostentry);
diff --git a/nest/rt-show.c b/nest/rt-show.c
index eacd4e31..7a8b629b 100644
--- a/nest/rt-show.c
+++ b/nest/rt-show.c
@@ -288,6 +288,7 @@ rt_show_cont(struct rt_show_data *d)
.addr = d->addr,
.name = "CLI Show Route",
.list = &global_work_list,
+ .pool = c->pool,
.export_bulk = rt_show_net_export_bulk,
.dump_req = rt_show_dump_req,
.log_state_change = rt_show_log_state_change,
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 9629db2c..f1e3c8f7 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -2131,7 +2131,7 @@ rt_table_export_start_locked(struct rtable_private *tab, struct rt_export_reques
struct rt_exporter *re = &tab->exporter.e;
rt_lock_table(tab);
- req->hook = rt_alloc_export(re, sizeof(struct rt_table_export_hook));
+ req->hook = rt_alloc_export(re, req->pool, sizeof(struct rt_table_export_hook));
req->hook->req = req;
struct rt_table_export_hook *hook = SKIP_BACK(struct rt_table_export_hook, h, req->hook);
@@ -2212,9 +2212,9 @@ rt_request_export_other(struct rt_exporter *re, struct rt_export_request *req)
}
struct rt_export_hook *
-rt_alloc_export(struct rt_exporter *re, uint size)
+rt_alloc_export(struct rt_exporter *re, pool *pp, uint size)
{
- pool *p = rp_new(re->rp, "Export hook");
+ pool *p = rp_new(pp, pp->domain, "Export hook");
struct rt_export_hook *hook = mb_allocz(p, size);
hook->pool = p;
@@ -2709,13 +2709,14 @@ rt_flowspec_link(rtable *src_pub, rtable *dst_pub)
if (!ln)
{
- pool *p = src->rp;
+ pool *p = birdloop_pool(dst_pub->loop);
ln = mb_allocz(p, sizeof(struct rt_flowspec_link));
ln->src = src_pub;
ln->dst = dst_pub;
ln->req = (struct rt_export_request) {
.name = mb_sprintf(p, "%s.flowspec.notifier", dst_pub->name),
.list = birdloop_event_list(dst_pub->loop),
+ .pool = p,
.trace_routes = src->config->debug,
.dump_req = rt_flowspec_dump_req,
.log_state_change = rt_flowspec_log_state_change,
@@ -2781,8 +2782,6 @@ rt_free(resource *_r)
{
struct rtable_private *r = SKIP_BACK(struct rtable_private, r, _r);
- DOMAIN_FREE(rtable, r->lock);
-
DBG("Deleting routing table %s\n", r->name);
ASSERT_DIE(r->use_count == 0);
@@ -2847,13 +2846,20 @@ rt_setup(pool *pp, struct rtable_config *cf)
/* Start the service thread */
struct birdloop *loop = birdloop_new(pp, DOMAIN_ORDER(service), 0, "Routing table service %s", cf->name);
+ birdloop_enter(loop);
pool *sp = birdloop_pool(loop);
- pool *p = rp_newf(sp, "Routing table data %s", cf->name);
+
+ /* Create the table domain and pool */
+ DOMAIN(rtable) dom = DOMAIN_NEW(rtable, cf->name);
+ LOCK_DOMAIN(rtable, dom);
+
+ pool *p = rp_newf(sp, dom.rtable, "Routing table data %s", cf->name);
/* Create the actual table */
struct rtable_private *t = ralloc(p, &rt_class);
t->rp = p;
t->loop = loop;
+ t->lock = dom;
t->rte_slab = sl_new(p, sizeof(struct rte_storage));
@@ -2864,8 +2870,6 @@ rt_setup(pool *pp, struct rtable_config *cf)
if (t->id >= rtable_max_id)
rtable_max_id = t->id + 1;
- t->lock = DOMAIN_NEW(rtable, t->name);
-
fib_init(&t->fib, p, t->addr_type, sizeof(net), OFFSETOF(net, n), 0, NULL);
if (cf->trie_used)
@@ -2911,8 +2915,9 @@ rt_setup(pool *pp, struct rtable_config *cf)
t->flowspec_trie->ipv4 = (t->addr_type == NET_FLOW4);
}
+ UNLOCK_DOMAIN(rtable, dom);
+
/* Setup the service thread flag handler */
- birdloop_enter(t->loop);
birdloop_flag_set_handler(t->loop, &t->fh);
birdloop_leave(t->loop);
@@ -2929,7 +2934,7 @@ void
rt_init(void)
{
rta_init();
- rt_table_pool = rp_new(&root_pool, "Routing tables");
+ rt_table_pool = rp_new(&root_pool, the_bird_domain.the_bird, "Routing tables");
init_list(&routing_tables);
init_list(&deleted_routing_tables);
ev_init_list(&rt_cork.queue, &main_birdloop, "Route cork release");
@@ -4067,13 +4072,14 @@ rt_shutdown(void *tab_)
static void
rt_delete(void *tab_)
{
- birdloop_enter(&main_birdloop);
+ ASSERT_DIE(birdloop_inside(&main_birdloop));
/* We assume that nobody holds the table reference now as use_count is zero.
* Anyway the last holder may still hold the lock. Therefore we lock and
* unlock it the last time to be sure that nobody is there. */
struct rtable_private *tab = RT_LOCK((rtable *) tab_);
struct config *conf = tab->deleted;
+ DOMAIN(rtable) dom = tab->lock;
RT_UNLOCK(RT_PUB(tab));
@@ -4081,7 +4087,8 @@ rt_delete(void *tab_)
birdloop_free(tab->loop);
config_del_obstacle(conf);
- birdloop_leave(&main_birdloop);
+ /* Also drop the domain */
+ DOMAIN_FREE(rtable, dom);
}
@@ -4636,18 +4643,9 @@ rt_init_hostcache(struct rtable_private *tab)
.data = tab,
};
- hc->req = (struct rt_export_request) {
- .name = mb_sprintf(tab->rp, "%s.hcu.notifier", tab->name),
- .list = birdloop_event_list(tab->loop),
- .trace_routes = tab->config->debug,
- .dump_req = hc_notify_dump_req,
- .log_state_change = hc_notify_log_state_change,
- .export_one = hc_notify_export_one,
- };
-
- rt_table_export_start_locked(tab, &hc->req);
-
tab->hostcache = hc;
+
+ ev_send_loop(tab->loop, &hc->update);
}
static void
@@ -4775,9 +4773,24 @@ rt_update_hostcache(void *data)
RT_LOCKED((rtable *) data, tab)
{
-
struct hostcache *hc = tab->hostcache;
+ /* Finish initialization */
+ if (!hc->req.name)
+ {
+ hc->req = (struct rt_export_request) {
+ .name = mb_sprintf(tab->rp, "%s.hcu.notifier", tab->name),
+ .list = birdloop_event_list(tab->loop),
+ .pool = tab->rp,
+ .trace_routes = tab->config->debug,
+ .dump_req = hc_notify_dump_req,
+ .log_state_change = hc_notify_log_state_change,
+ .export_one = hc_notify_export_one,
+ };
+
+ rt_table_export_start_locked(tab, &hc->req);
+ }
+
/* Shutdown shortcut */
if (!hc->req.hook)
RT_RETURN(tab);
diff --git a/nest/rt.h b/nest/rt.h
index 01372b8c..4fe8eb53 100644
--- a/nest/rt.h
+++ b/nest/rt.h
@@ -294,6 +294,7 @@ struct rt_export_request {
u8 addr_mode; /* Network prefilter mode (TE_ADDR_*) */
event_list *list; /* Where to schedule export events */
+ pool *pool; /* Pool to use for allocations */
/* There are two methods of export. You can either request feeding every single change
* or feeding the whole route feed. In case of regular export, &export_one is preferred.
@@ -438,7 +439,7 @@ int rpe_get_seen(struct rt_export_hook *hook, struct rt_pending_export *rpe);
*/
void rt_init_export(struct rt_exporter *re, struct rt_export_hook *hook);
-struct rt_export_hook *rt_alloc_export(struct rt_exporter *re, uint size);
+struct rt_export_hook *rt_alloc_export(struct rt_exporter *re, pool *pool, uint size);
void rt_stop_export_common(struct rt_export_hook *hook);
void rt_export_stopped(struct rt_export_hook *hook);
void rt_exporter_init(struct rt_exporter *re);