@@ -124,18 +124,32 @@ static inline int selabel_is_validate_set(const struct selinux_opt *opts,
int selabel_validate(struct selabel_lookup_rec *contexts)
{
- int rc = 0;
+ bool validated;
+ int rc;
- if (contexts->validated)
- goto out;
+ validated = __atomic_load_n(&contexts->validated, __ATOMIC_ACQUIRE);
+ if (validated)
+ return 0;
+
+ __pthread_mutex_lock(&contexts->lock);
+
+ /* Check if another thread validated the context while we waited on the mutex */
+ validated = __atomic_load_n(&contexts->validated, __ATOMIC_ACQUIRE);
+ if (validated) {
+ __pthread_mutex_unlock(&contexts->lock);
+ return 0;
+ }
rc = selinux_validate(&contexts->ctx_raw);
+ if (rc == 0)
+ __atomic_store_n(&contexts->validated, true, __ATOMIC_RELEASE);
+
+ __pthread_mutex_unlock(&contexts->lock);
+
if (rc < 0)
- goto out;
+ return -1;
- contexts->validated = true;
-out:
- return rc;
+ return 0;
}
/* Public API helpers */
@@ -143,11 +157,35 @@ static int selabel_fini(const struct selabel_handle *rec,
struct selabel_lookup_rec *lr,
bool translating)
{
+ char *ctx_trans;
+ int rc;
+
if (compat_validate(rec, lr, rec->spec_file, lr->lineno))
return -1;
- if (translating && !lr->ctx_trans &&
- selinux_raw_to_trans_context(lr->ctx_raw, &lr->ctx_trans))
+ if (!translating)
+ return 0;
+
+ ctx_trans = __atomic_load_n(&lr->ctx_trans, __ATOMIC_ACQUIRE);
+ if (ctx_trans)
+ return 0;
+
+ __pthread_mutex_lock(&lr->lock);
+
+ /* Check if another thread translated the context while we waited on the mutex */
+ ctx_trans = __atomic_load_n(&lr->ctx_trans, __ATOMIC_ACQUIRE);
+ if (ctx_trans) {
+ __pthread_mutex_unlock(&lr->lock);
+ return 0;
+ }
+
+ rc = selinux_raw_to_trans_context(lr->ctx_raw, &ctx_trans);
+ if (rc == 0)
+ __atomic_store_n(&lr->ctx_trans, ctx_trans, __ATOMIC_RELEASE);
+
+ __pthread_mutex_unlock(&lr->lock);
+
+ if (rc)
return -1;
return 0;
@@ -186,6 +186,7 @@ db_close(struct selabel_handle *rec)
free(spec->key);
free(spec->lr.ctx_raw);
free(spec->lr.ctx_trans);
+ __pthread_mutex_destroy(&spec->lr.lock);
}
free(catalog);
}
@@ -358,6 +359,7 @@ out_error:
free(spec->key);
free(spec->lr.ctx_raw);
free(spec->lr.ctx_trans);
+ __pthread_mutex_destroy(&spec->lr.lock);
}
free(catalog);
fclose(filp);
@@ -661,6 +661,7 @@ static int insert_spec(const struct selabel_handle *rec, struct saved_data *data
.lr.ctx_trans = NULL,
.lr.lineno = lineno,
.lr.validated = false,
+ .lr.lock = PTHREAD_MUTEX_INITIALIZER,
};
data->num_specs++;
@@ -794,6 +795,7 @@ static int insert_spec(const struct selabel_handle *rec, struct saved_data *data
.lr.ctx_trans = NULL,
.lr.lineno = lineno,
.lr.validated = false,
+ .lr.lock = PTHREAD_MUTEX_INITIALIZER,
};
data->num_specs++;
@@ -818,6 +820,7 @@ static inline void free_spec_node(struct spec_node *node)
free(lspec->lr.ctx_raw);
free(lspec->lr.ctx_trans);
+ __pthread_mutex_destroy(&lspec->lr.lock);
if (lspec->from_mmap)
continue;
@@ -832,6 +835,7 @@ static inline void free_spec_node(struct spec_node *node)
free(rspec->lr.ctx_raw);
free(rspec->lr.ctx_trans);
+ __pthread_mutex_destroy(&rspec->lr.lock);
regex_data_free(rspec->regex);
__pthread_mutex_destroy(&rspec->regex_lock);
@@ -71,6 +71,7 @@ extern void digest_gen_hash(struct selabel_digest *digest);
struct selabel_lookup_rec {
char * ctx_raw;
char * ctx_trans;
+ pthread_mutex_t lock; /* lock for validation and translation */
unsigned int lineno;
bool validated;
};
@@ -177,6 +177,7 @@ static void close(struct selabel_handle *rec)
free(spec->key);
free(spec->lr.ctx_raw);
free(spec->lr.ctx_trans);
+ __pthread_mutex_destroy(&spec->lr.lock);
}
if (spec_arr)
@@ -204,6 +204,7 @@ static void close(struct selabel_handle *rec)
free(spec->key);
free(spec->lr.ctx_raw);
free(spec->lr.ctx_trans);
+ __pthread_mutex_destroy(&spec->lr.lock);
}
if (spec_arr)