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 /nest | |
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 'nest')
-rw-r--r-- | nest/cli.c | 6 | ||||
-rw-r--r-- | nest/cli.h | 1 | ||||
-rw-r--r-- | nest/iface.c | 7 | ||||
-rw-r--r-- | nest/locks.h | 1 | ||||
-rw-r--r-- | nest/password.h | 2 | ||||
-rw-r--r-- | nest/proto.c | 12 | ||||
-rw-r--r-- | nest/protocol.h | 2 | ||||
-rw-r--r-- | nest/rt-attr.c | 20 | ||||
-rw-r--r-- | nest/rt-show.c | 1 | ||||
-rw-r--r-- | nest/rt-table.c | 63 | ||||
-rw-r--r-- | nest/rt.h | 3 |
11 files changed, 79 insertions, 39 deletions
@@ -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; } @@ -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); @@ -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); |