Skip to content

Commit

Permalink
b2b_entities: fix crashes due to races when deleting entity
Browse files Browse the repository at this point in the history
An entity might have been deleted and freed while the lock has been released
when running the entity storage callbacks.

Related to #3110
  • Loading branch information
rvlad-patrascu committed Jun 30, 2023
1 parent b787802 commit 22bd818
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 40 deletions.
26 changes: 21 additions & 5 deletions modules/b2b_entities/b2be_clustering.c
Original file line number Diff line number Diff line change
Expand Up @@ -567,9 +567,12 @@ int receive_entity_update(bin_packet_t *packet)
unpack_update_fields(packet, dlg);

htable[hash_index].locked_by = process_no;
b2b_run_cb(dlg, hash_index, type, B2BCB_RECV_EVENT,
if ((rc = b2b_run_cb(dlg, hash_index, type, B2BCB_RECV_EVENT,
packet->type == REPL_ENTITY_UPDATE ? B2B_EVENT_UPDATE : B2B_EVENT_ACK,
packet, B2BCB_BACKEND_CLUSTER);
packet, B2BCB_BACKEND_CLUSTER)) != 0) {
lock_release(&htable[hash_index].lock);
return rc == -1 ? -1 : 0;
}
htable[hash_index].locked_by = -1;
} else {
rc = recv_b2bl_param_update(packet, dlg);
Expand All @@ -592,6 +595,7 @@ int receive_entity_delete(bin_packet_t *packet)
str *b2be_key;
b2b_table htable;
str callid, tag0, tag1;
int rc;

bin_pop_int(packet, &type);
bin_pop_str(packet, &tag0);
Expand Down Expand Up @@ -625,8 +629,12 @@ int receive_entity_delete(bin_packet_t *packet)
}

htable[hash_index].locked_by = process_no;
b2b_run_cb(dlg, hash_index, type, B2BCB_RECV_EVENT, B2B_EVENT_DELETE, packet,
B2BCB_BACKEND_CLUSTER);
if ((rc = b2b_run_cb(dlg, hash_index, type, B2BCB_RECV_EVENT, B2B_EVENT_DELETE,
packet, B2BCB_BACKEND_CLUSTER)) != 0) {
htable[hash_index].locked_by = -1;
lock_release(&htable[hash_index].lock);
return rc == -1 ? -1 : 0;
}
htable[hash_index].locked_by = -1;

b2b_entity_db_delete(type, dlg);
Expand Down Expand Up @@ -687,6 +695,7 @@ static int pack_entities_sync(bin_packet_t **sync_packet, int node_id,
int i;
b2b_dlg_t *dlg;
str storage_cnt_buf;
int rc;

storage->buffer.s = NULL;

Expand All @@ -709,8 +718,15 @@ static int pack_entities_sync(bin_packet_t **sync_packet, int node_id,
return -1;
}

b2b_run_cb(dlg, i, etype, B2BCB_TRIGGER_EVENT, B2B_EVENT_CREATE,
rc = b2b_run_cb(dlg, i, etype, B2BCB_TRIGGER_EVENT, B2B_EVENT_CREATE,
storage, serialize_backend);
if (rc == -1) {
lock_release(&htable[i].lock);
return -1;
} else if (rc == 1) {
lock_release(&htable[i].lock);
continue;
}

bin_pack_entity(*sync_packet, dlg, etype);

Expand Down
93 changes: 59 additions & 34 deletions modules/b2b_entities/dlg.c
Original file line number Diff line number Diff line change
Expand Up @@ -531,11 +531,13 @@ b2b_dlg_t* b2bl_search_iteratively(str* callid, str* from_tag, str* ruri,
return dlg;
}

void b2b_run_cb(b2b_dlg_t *dlg, unsigned int hash_index, int entity_type,
int b2b_run_cb(b2b_dlg_t *dlg, unsigned int hash_index, int entity_type,
int cbs_type, int event_type, bin_packet_t *storage, int backend)
{
struct b2b_callback *cb;
str st;
b2b_dlg_t *aux_dlg;
b2b_table table = entity_type == B2B_SERVER ? server_htable:client_htable;

/* search for the callback registered by the module that
* this entity belongs to */
Expand All @@ -553,17 +555,17 @@ void b2b_run_cb(b2b_dlg_t *dlg, unsigned int hash_index, int entity_type,
if (cbs_type == B2BCB_TRIGGER_EVENT) {
if (!cb) {
storage->buffer.s = NULL;
return;
return 0;
}

if (bin_init(storage, &storage_cap, B2BE_STORAGE_BIN_TYPE,
B2BE_STORAGE_BIN_VERS, 0) < 0) {
LM_ERR("Failed to init entity storage buffer\n");
return;
return -1;
}
} else { /* B2BCB_RECV_EVENT */
if (!cb)
return;
return 0;

if (bin_get_content_pos(storage, &st) > 0) {
if (b2be_db_mode != NO_DB && event_type != B2B_EVENT_DELETE) {
Expand All @@ -576,7 +578,7 @@ void b2b_run_cb(b2b_dlg_t *dlg, unsigned int hash_index, int entity_type,
shm_free(dlg->storage.s);
if (shm_str_dup(&dlg->storage, &st) < 0) {
LM_ERR("oom!\n");
return;
return -1;
}
}
}
Expand All @@ -585,18 +587,24 @@ void b2b_run_cb(b2b_dlg_t *dlg, unsigned int hash_index, int entity_type,
}
}

if (entity_type == B2B_SERVER)
lock_release(&server_htable[hash_index].lock);
else
lock_release(&client_htable[hash_index].lock);
lock_release(&table[hash_index].lock);

cb->cbf(entity_type, entity_type == B2B_SERVER ? &dlg->tag[1] : &dlg->callid,
&dlg->logic_key, dlg->param, event_type, storage, backend);

if (entity_type == B2B_SERVER)
lock_get(&server_htable[hash_index].lock);
else
lock_get(&client_htable[hash_index].lock);
lock_get(&table[hash_index].lock);

/* search the dialog */
for(aux_dlg = table[hash_index].first; aux_dlg; aux_dlg = aux_dlg->next)
{
if(aux_dlg == dlg)
break;
}
if(!aux_dlg)
{
LM_DBG("Record not found anymore\n");
return 1;
}

if (cbs_type == B2BCB_TRIGGER_EVENT && event_type != B2B_EVENT_DELETE &&
b2be_db_mode != NO_DB && bin_get_content_start(storage, &st) > 0) {
Expand All @@ -607,10 +615,12 @@ void b2b_run_cb(b2b_dlg_t *dlg, unsigned int hash_index, int entity_type,
shm_free(dlg->storage.s);
if (shm_str_dup(&dlg->storage, &st) < 0) {
LM_ERR("oom!\n");
return;
return -1;
}
}
}

return 0;
}

static void run_create_cb_all(struct b2b_callback *cb, int etype)
Expand Down Expand Up @@ -1038,7 +1048,7 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam)
if(req_routeid > 0)
run_top_route(sroutes->request[req_routeid], msg);

goto done;
return SCB_DROP_MSG;
}
}

Expand Down Expand Up @@ -1293,13 +1303,15 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam)
if (dlg_state == B2B_ESTABLISHED) {
b2b_ev = B2B_EVENT_ACK;

b2b_run_cb(dlg, hash_index, etype, B2BCB_TRIGGER_EVENT, b2b_ev,
&storage, serialize_backend);
if (b2b_run_cb(dlg, hash_index, etype, B2BCB_TRIGGER_EVENT, b2b_ev,
&storage, serialize_backend) != 0)
goto done;
} else if (dlg_state == B2B_TERMINATED) {
b2b_ev = B2B_EVENT_DELETE;

b2b_run_cb(dlg, hash_index, etype, B2BCB_TRIGGER_EVENT, b2b_ev,
&storage, serialize_backend);
if (b2b_run_cb(dlg, hash_index, etype, B2BCB_TRIGGER_EVENT, b2b_ev,
&storage, serialize_backend) != 0)
goto done;
}
}

Expand All @@ -1324,7 +1336,7 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam)
bin_free_packet(&storage);

done:

lock_release(&table[hash_index].lock);
return SCB_DROP_MSG;
}

Expand Down Expand Up @@ -1784,12 +1796,14 @@ int b2b_send_reply(b2b_rpl_data_t* rpl_data)
* callbacks is not neccesary unless we have replication */
b2be_cluster) {
b2b_ev = B2B_EVENT_CREATE;
b2b_run_cb(dlg, hash_index, et, B2BCB_TRIGGER_EVENT, b2b_ev, &storage,
serialize_backend);
if (b2b_run_cb(dlg, hash_index, et, B2BCB_TRIGGER_EVENT, b2b_ev,
&storage, serialize_backend) != 0)
goto error;
} else if (prev_state == B2B_MODIFIED && dlg->state == B2B_CONFIRMED) {
b2b_ev = B2B_EVENT_UPDATE;
b2b_run_cb(dlg, hash_index, et, B2BCB_TRIGGER_EVENT, b2b_ev, &storage,
serialize_backend);
if (b2b_run_cb(dlg, hash_index, et, B2BCB_TRIGGER_EVENT, b2b_ev,
&storage, serialize_backend) != 0)
goto error;
}
}

Expand Down Expand Up @@ -1979,8 +1993,11 @@ void b2b_entity_delete(enum b2b_entity_type et, str* b2b_key,

if (B2BE_SERIALIZE_STORAGE() && replicate) {
trig_ev = 1;
b2b_run_cb(dlg, hash_index, et, B2BCB_TRIGGER_EVENT, B2B_EVENT_DELETE,
&storage, serialize_backend);
if (b2b_run_cb(dlg, hash_index, et, B2BCB_TRIGGER_EVENT,
B2B_EVENT_DELETE, &storage, serialize_backend) != 0) {
lock_release(&table[hash_index].lock);
return;
}
}

if(db_del)
Expand Down Expand Up @@ -2380,13 +2397,15 @@ int b2b_send_request(b2b_req_data_t* req_data)
if (dlg->state == B2B_ESTABLISHED) {
if (b2be_db_mode != NO_DB || dlg->replicated) {
b2b_ev = B2B_EVENT_ACK;
b2b_run_cb(dlg, hash_index, et, B2BCB_TRIGGER_EVENT, b2b_ev, &storage,
serialize_backend);
if (b2b_run_cb(dlg, hash_index, et, B2BCB_TRIGGER_EVENT,
b2b_ev, &storage, serialize_backend) != 0)
goto error;
}
} else if (dlg->state == B2B_TERMINATED) {
b2b_ev = B2B_EVENT_DELETE;
b2b_run_cb(dlg, hash_index, et, B2BCB_TRIGGER_EVENT, b2b_ev, &storage,
serialize_backend);
if (b2b_run_cb(dlg, hash_index, et, B2BCB_TRIGGER_EVENT, b2b_ev,
&storage, serialize_backend) != 0)
goto error;
}
}

Expand Down Expand Up @@ -3532,16 +3551,22 @@ void b2b_tm_cback(struct cell *t, b2b_table htable, struct tmcb_params *ps)

if (dlg->state != B2B_TERMINATED) {
b2b_ev = B2B_EVENT_UPDATE;
b2b_run_cb(dlg, hash_index, etype, B2BCB_TRIGGER_EVENT, b2b_ev,
&storage, serialize_backend);
if (b2b_run_cb(dlg, hash_index, etype, B2BCB_TRIGGER_EVENT,
b2b_ev, &storage, serialize_backend) != 0) {
lock_release(&htable[hash_index].lock);
return;
}
} else {
b2b_ev = -1;
}
} else if (b2b_ev == B2B_EVENT_CREATE) {

if (dlg->state != B2B_TERMINATED) {
b2b_run_cb(dlg, hash_index, etype, B2BCB_TRIGGER_EVENT, b2b_ev,
&storage, serialize_backend);
if (b2b_run_cb(dlg, hash_index, etype, B2BCB_TRIGGER_EVENT,
b2b_ev, &storage, serialize_backend) != 0) {
lock_release(&htable[hash_index].lock);
return;
}

if (b2be_db_mode == WRITE_THROUGH)
b2be_db_insert(dlg, etype);
Expand Down
2 changes: 1 addition & 1 deletion modules/b2b_entities/dlg.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ int b2b_apply_lumps(struct sip_msg* msg);

int b2b_register_cb(b2b_cb_t cb, int cb_type, str *mod_name);

void b2b_run_cb(b2b_dlg_t *dlg, unsigned int hash_index, int entity_type,
int b2b_run_cb(b2b_dlg_t *dlg, unsigned int hash_index, int entity_type,
int cbs_type, int event_type, bin_packet_t *storage, int backend);

dlg_leg_t* b2b_dup_leg(dlg_leg_t* leg, int mem_type);
Expand Down

0 comments on commit 22bd818

Please sign in to comment.