Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/json_configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ Each event is composed of the following elements, all of which are optional exce

* <b>`label`</b> -- The name by which the event is identified. See the definition of `label` in the ABNF grammar below for permissible values.

* <b>`priority`</b> -- The priority of routes that have this event as their <b>`parent-event`</b> (see <b>`routes`</b> below). Lower number means higher priority.
* <b>`priority`</b> -- The priority of routes that have this event as their <b>`parent-event`</b> (see <b>`routes`</b> below). Lower number means higher priority. If omitted, the priority is 0, the highest priority.

* <b>`config`</b> -- The configuration to associate with routes with this <b>`parent-event`</b>, as above for <b>`config-update`</b>.

Expand Down
4 changes: 2 additions & 2 deletions src/actions.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,12 @@ WOLFSENTRY_LOCAL wolfsentry_errcode_t wolfsentry_action_insert_1(
goto out;
if ((ret = wolfsentry_id_allocate(WOLFSENTRY_CONTEXT_ARGS_OUT, &new->header)) < 0)
goto out;
if (id)
*id = new->header.id;
if ((ret = wolfsentry_table_ent_insert(WOLFSENTRY_CONTEXT_ARGS_OUT, &new->header, &wolfsentry->actions->header, 1 /* unique_p */)) < 0) {
ret = WOLFSENTRY_ERROR_RECODE(ret);
goto out;
}
if (id != NULL)
*id = new->header.id;
ret = WOLFSENTRY_ERROR_ENCODE(OK);

out:
Expand Down
137 changes: 112 additions & 25 deletions src/events.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,37 @@ static wolfsentry_errcode_t wolfsentry_event_init_1(const char *label, int label
WOLFSENTRY_RETURN_OK;
}

/* callers hold the context lock, which is what the plain flag write relies on */
static wolfsentry_errcode_t wolfsentry_event_aux_owner_add(struct wolfsentry_event *aux_event) {
wolfsentry_refcount_t owners;

WOLFSENTRY_ATOMIC_INCREMENT_UNSIGNED_SAFELY_BY_ONE(aux_event->aux_owner_count, owners);
if (owners == 0)
WOLFSENTRY_ERROR_RETURN(OVERFLOW_AVERTED);
if (! WOLFSENTRY_CHECK_BITS(aux_event->flags, WOLFSENTRY_EVENT_FLAG_IS_SUBEVENT))
WOLFSENTRY_SET_BITS(aux_event->flags, WOLFSENTRY_EVENT_FLAG_IS_SUBEVENT);
WOLFSENTRY_RETURN_OK;
}

/* may run without the context lock when a deleted owner is finally freed, so only the atomic count changes here; the mark is resynced under the lock */
static wolfsentry_errcode_t wolfsentry_event_aux_owner_remove(struct wolfsentry_event *aux_event) {
wolfsentry_refcount_t owners;

WOLFSENTRY_ATOMIC_DECREMENT_UNSIGNED_SAFELY_BY_ONE(aux_event->aux_owner_count, owners);
if (owners == MAX_UINT_OF(aux_event->aux_owner_count))
WOLFSENTRY_ERROR_RETURN(INTERNAL_CHECK_FATAL);
WOLFSENTRY_RETURN_OK;
}

static void wolfsentry_event_aux_owner_resync_mark(struct wolfsentry_event *event) {
if ((WOLFSENTRY_ATOMIC_LOAD(event->aux_owner_count) == 0) &&
WOLFSENTRY_CHECK_BITS(event->flags, WOLFSENTRY_EVENT_FLAG_IS_SUBEVENT))
{
WOLFSENTRY_CLEAR_BITS(event->flags, WOLFSENTRY_EVENT_FLAG_IS_SUBEVENT);
}
WOLFSENTRY_RETURN_VOID;
}

static void wolfsentry_event_free(WOLFSENTRY_CONTEXT_ARGS_IN, struct wolfsentry_event *event) {
WOLFSENTRY_WARN_ON_FAILURE(wolfsentry_action_list_delete_all(WOLFSENTRY_CONTEXT_ARGS_OUT, &event->post_action_list));
WOLFSENTRY_WARN_ON_FAILURE(wolfsentry_action_list_delete_all(WOLFSENTRY_CONTEXT_ARGS_OUT, &event->insert_action_list));
Expand Down Expand Up @@ -149,6 +180,10 @@ WOLFSENTRY_LOCAL wolfsentry_errcode_t wolfsentry_event_clone_bare(
memcpy(*new_event, src_event, new_size);
WOLFSENTRY_TABLE_ENT_HEADER_RESET(**new_ent);

/* no route in a route-free clone can depend on the copied layout */
if (WOLFSENTRY_CHECK_BITS(flags, WOLFSENTRY_CLONE_FLAG_NO_ROUTES))
WOLFSENTRY_CLEAR_BITS((*new_event)->flags, WOLFSENTRY_EVENT_FLAG_IS_PARENT_EVENT);

WOLFSENTRY_LIST_HEADER_RESET((*new_event)->post_action_list.header);
WOLFSENTRY_LIST_HEADER_RESET((*new_event)->insert_action_list.header);
WOLFSENTRY_LIST_HEADER_RESET((*new_event)->match_action_list.header);
Expand All @@ -157,6 +192,8 @@ WOLFSENTRY_LOCAL wolfsentry_errcode_t wolfsentry_event_clone_bare(
WOLFSENTRY_LIST_HEADER_RESET((*new_event)->decision_action_list.header);

(*new_event)->aux_event = NULL;
(*new_event)->aux_owner_count = 0;
WOLFSENTRY_CLEAR_BITS((*new_event)->flags, WOLFSENTRY_EVENT_FLAG_IS_SUBEVENT);

if (src_event->config) {
if (((*new_event)->config = WOLFSENTRY_MALLOC_1(dest_context->hpi.allocator, sizeof *(*new_event)->config)) == NULL) {
Expand Down Expand Up @@ -257,6 +294,8 @@ WOLFSENTRY_LOCAL wolfsentry_errcode_t wolfsentry_event_clone_resolve(
}
WOLFSENTRY_REFCOUNT_INCREMENT(new_event->aux_event->header.refcount, ret);
WOLFSENTRY_RERETURN_IF_ERROR(ret);
ret = wolfsentry_event_aux_owner_add(new_event->aux_event);
WOLFSENTRY_RERETURN_IF_ERROR(ret);
}

WOLFSENTRY_RETURN_OK;
Expand Down Expand Up @@ -289,12 +328,12 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_event_insert(
wolfsentry_event_free(WOLFSENTRY_CONTEXT_ARGS_OUT, new);
WOLFSENTRY_ERROR_UNLOCK_AND_RERETURN(ret);
}
if (id)
*id = new->header.id;
if ((ret = wolfsentry_table_ent_insert(WOLFSENTRY_CONTEXT_ARGS_OUT, &new->header, &wolfsentry->events->header, 1 /* unique_p */)) < 0) {
wolfsentry_event_free(WOLFSENTRY_CONTEXT_ARGS_OUT, new);
WOLFSENTRY_ERROR_UNLOCK_AND_RETURN_RECODED(ret);
}
if (id)
*id = new->header.id;

WOLFSENTRY_ERROR_UNLOCK_AND_RERETURN(ret);
}
Expand All @@ -306,7 +345,17 @@ WOLFSENTRY_API const char *wolfsentry_event_get_label(const struct wolfsentry_ev

WOLFSENTRY_API wolfsentry_event_flags_t wolfsentry_event_get_flags(const struct wolfsentry_event *event)
{
return event ? event->flags : WOLFSENTRY_EVENT_FLAG_NONE;
wolfsentry_event_flags_t flags;

if (event == NULL)
return WOLFSENTRY_EVENT_FLAG_NONE;
/* an owner freed without the context lock only drops the count, so derive the mark from it */
flags = event->flags;
if (WOLFSENTRY_ATOMIC_LOAD(event->aux_owner_count) > 0)
WOLFSENTRY_SET_BITS(flags, WOLFSENTRY_EVENT_FLAG_IS_SUBEVENT);
else
WOLFSENTRY_CLEAR_BITS(flags, WOLFSENTRY_EVENT_FLAG_IS_SUBEVENT);
return flags;
}

WOLFSENTRY_API const struct wolfsentry_event *wolfsentry_event_get_aux_event(const struct wolfsentry_event *event)
Expand All @@ -319,7 +368,7 @@ static wolfsentry_errcode_t wolfsentry_event_get_1(WOLFSENTRY_CONTEXT_ARGS_IN, c
WOLFSENTRY_STACKBUF(
struct wolfsentry_event,
label,
WOLFSENTRY_MAX_LABEL_BYTES,
WOLFSENTRY_MAX_LABEL_BYTES + 1,
target);
struct wolfsentry_event *event_1 = &target.target;

Expand Down Expand Up @@ -356,27 +405,56 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_event_get_config(WOLFSENTRY_CONTE
WOLFSENTRY_ERROR_UNLOCK_AND_RERETURN(ret);
}

static int wolfsentry_event_has_routes(const struct wolfsentry_context *wolfsentry, const struct wolfsentry_event *event) {
const struct wolfsentry_table_ent_header *ent;

if (WOLFSENTRY_CHECK_BITS(event->flags, WOLFSENTRY_EVENT_FLAG_IS_PARENT_EVENT))
return 1;
/* an aux event parents the ephemeral routes its owners generate */
if (WOLFSENTRY_ATOMIC_LOAD(event->aux_owner_count) != 0)
return 1;
/* beyond the table's own reference, each live route, deleted or not, holds one */
if (WOLFSENTRY_ATOMIC_LOAD(event->header.refcount) > 1)
return 1;
for (ent = wolfsentry_table_first(&wolfsentry->routes->header); ent != NULL; ent = ent->next) {
if (((const struct wolfsentry_route *)ent)->parent_event == event)
return 1;
}
return 0;
}

WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_event_update_config(WOLFSENTRY_CONTEXT_ARGS_IN, const char *label, int label_len, const struct wolfsentry_eventconfig *config) {
struct wolfsentry_event *event;
const struct wolfsentry_eventconfig_internal *current_config;
struct wolfsentry_eventconfig_internal new_config;
wolfsentry_errcode_t ret;

if (config == NULL)
WOLFSENTRY_ERROR_RETURN(INVALID_ARG);

WOLFSENTRY_MUTEX_OR_RETURN();

ret = wolfsentry_event_get_1(WOLFSENTRY_CONTEXT_ARGS_OUT, label, label_len, &event);
WOLFSENTRY_UNLOCK_AND_RERETURN_IF_ERROR(ret);

ret = wolfsentry_eventconfig_load(config, &new_config);
WOLFSENTRY_UNLOCK_AND_RERETURN_IF_ERROR(ret);

current_config = (event->config != NULL) ? event->config : &wolfsentry->config;

/* existing routes were allocated, and are accessed and freed, using the event's current layout */
if (wolfsentry_event_has_routes(wolfsentry, event) &&
((new_config.config.route_private_data_size != current_config->config.route_private_data_size) ||
(new_config.config.route_private_data_alignment != current_config->config.route_private_data_alignment)))
WOLFSENTRY_ERROR_UNLOCK_AND_RETURN(INCOMPATIBLE_STATE);

if (event->config == NULL) {
if ((event->config = (struct wolfsentry_eventconfig_internal *)WOLFSENTRY_MALLOC(sizeof *event->config)) == NULL)
WOLFSENTRY_ERROR_UNLOCK_AND_RETURN(SYS_RESOURCE_FAILED);
if ((ret = wolfsentry_eventconfig_load(config, event->config)) < 0) {
WOLFSENTRY_FREE(event->config);
event->config = NULL;
}
WOLFSENTRY_ERROR_UNLOCK_AND_RERETURN(ret);
} else {
ret = wolfsentry_eventconfig_load(config, event->config);
WOLFSENTRY_ERROR_UNLOCK_AND_RERETURN(ret);
}
memcpy(event->config, &new_config, sizeof *event->config);

WOLFSENTRY_UNLOCK_AND_RETURN_OK;
}

WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_event_get_reference(WOLFSENTRY_CONTEXT_ARGS_IN, const char *label, int label_len, struct wolfsentry_event **event) {
Expand Down Expand Up @@ -418,6 +496,8 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_event_drop_reference(WOLFSENTRY_C
if (refs_left > 0)
WOLFSENTRY_RETURN_OK;
if (event->aux_event) {
ret = wolfsentry_event_aux_owner_remove(event->aux_event);
WOLFSENTRY_RERETURN_IF_ERROR(ret);
ret = wolfsentry_event_drop_reference(WOLFSENTRY_CONTEXT_ARGS_OUT, event->aux_event, NULL);
WOLFSENTRY_RERETURN_IF_ERROR(ret);
event->aux_event = NULL;
Expand Down Expand Up @@ -613,45 +693,52 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_event_set_aux_event(
int aux_event_label_len)
{
wolfsentry_errcode_t ret;
struct wolfsentry_event *event, *aux_event = NULL;
struct wolfsentry_event *event, *aux_event = NULL, *old_aux_event;

WOLFSENTRY_MUTEX_OR_RETURN();

ret = wolfsentry_event_get_reference(WOLFSENTRY_CONTEXT_ARGS_OUT, event_label, event_label_len, &event);
WOLFSENTRY_UNLOCK_AND_RERETURN_IF_ERROR(ret);
if (WOLFSENTRY_CHECK_BITS(event->flags, WOLFSENTRY_EVENT_FLAG_IS_SUBEVENT)) {
/* the owner count is authoritative; a mark left by an owner freed without the lock is cleared here */
if (WOLFSENTRY_ATOMIC_LOAD(event->aux_owner_count) != 0) {
ret = WOLFSENTRY_ERROR_ENCODE(INCOMPATIBLE_STATE);
goto out;
}
wolfsentry_event_aux_owner_resync_mark(event);
if (aux_event_label) {
ret = wolfsentry_event_get_reference(WOLFSENTRY_CONTEXT_ARGS_OUT, aux_event_label, aux_event_label_len, &aux_event);
if (ret < 0) {
aux_event = NULL;
goto out;
}
if (WOLFSENTRY_CHECK_BITS(aux_event->flags, WOLFSENTRY_EVENT_FLAG_IS_PARENT_EVENT)) {
if ((aux_event == event) ||
WOLFSENTRY_CHECK_BITS(aux_event->flags, WOLFSENTRY_EVENT_FLAG_IS_PARENT_EVENT)) {
ret = WOLFSENTRY_ERROR_ENCODE(INCOMPATIBLE_STATE);
goto out;
}
} else
aux_event = NULL;

if (event->aux_event)
WOLFSENTRY_WARN_ON_FAILURE(wolfsentry_event_drop_reference(WOLFSENTRY_CONTEXT_ARGS_OUT, event->aux_event, NULL /* action_results */));
if (aux_event != NULL) {
ret = wolfsentry_event_aux_owner_add(aux_event);
if (ret < 0)
goto out;
}

old_aux_event = event->aux_event;
event->aux_event = aux_event;
if (old_aux_event != NULL) {
WOLFSENTRY_WARN_ON_FAILURE(wolfsentry_event_aux_owner_remove(old_aux_event));
wolfsentry_event_aux_owner_resync_mark(old_aux_event);
WOLFSENTRY_WARN_ON_FAILURE(wolfsentry_event_drop_reference(WOLFSENTRY_CONTEXT_ARGS_OUT, old_aux_event, NULL /* action_results */));
}
ret = WOLFSENTRY_ERROR_ENCODE(OK);

out:

WOLFSENTRY_WARN_ON_FAILURE(wolfsentry_event_drop_reference(WOLFSENTRY_CONTEXT_ARGS_OUT, event, NULL /* action_results */));
if (aux_event) {
if (ret < 0)
WOLFSENTRY_WARN_ON_FAILURE(wolfsentry_event_drop_reference(WOLFSENTRY_CONTEXT_ARGS_OUT, aux_event, NULL /* action_results */));
else {
if (! WOLFSENTRY_CHECK_BITS(aux_event->flags, WOLFSENTRY_EVENT_FLAG_IS_SUBEVENT))
WOLFSENTRY_SET_BITS(aux_event->flags, WOLFSENTRY_EVENT_FLAG_IS_SUBEVENT);
}
}
if ((aux_event != NULL) && (ret < 0))
WOLFSENTRY_WARN_ON_FAILURE(wolfsentry_event_drop_reference(WOLFSENTRY_CONTEXT_ARGS_OUT, aux_event, NULL /* action_results */));

WOLFSENTRY_ERROR_UNLOCK_AND_RERETURN(ret);
}
Expand Down
2 changes: 1 addition & 1 deletion src/json/load_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -1100,7 +1100,7 @@ static wolfsentry_errcode_t handle_event_clause(struct wolfsentry_json_process_s
}

if ((jps->cur_depth == 3) && (type == JSON_STRING) && (! strcmp(jps->cur_keyname, "label"))) {
if (data_size >= sizeof jps->o_u_c.event.label)
if (data_size > sizeof jps->o_u_c.event.label)
WOLFSENTRY_ERROR_RETURN(STRING_ARG_TOO_LONG);
memcpy(jps->o_u_c.event.label, data, data_size);
jps->o_u_c.event.label_len = (int)data_size;
Expand Down
1 change: 1 addition & 0 deletions src/wolfsentry_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ struct wolfsentry_event {
* policy for the ephemeral route.
*/

wolfsentry_refcount_t aux_owner_count; /* events whose aux_event is this one */

byte label_len;
char label[WOLFSENTRY_FLEXIBLE_ARRAY_SIZE];
Expand Down
Loading
Loading