summaryrefslogtreecommitdiff
path: root/src/lib/crypt
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/crypt')
-rw-r--r--src/lib/crypt/keyrot.c25
1 files changed, 25 insertions, 0 deletions
diff --git a/src/lib/crypt/keyrot.c b/src/lib/crypt/keyrot.c
index 8b0d9429..def29297 100644
--- a/src/lib/crypt/keyrot.c
+++ b/src/lib/crypt/keyrot.c
@@ -469,12 +469,28 @@ void keyrot_destroy(struct keyrot * kr)
free(kr);
}
+/* A dup live epoch shadows straggler RX; epoch is peer-driven. */
+static bool kr_epoch_live(const struct kr_batch * cur,
+ const struct kr_batch * prev,
+ uint8_t epoch)
+{
+ if (epoch == cur->epoch)
+ return true;
+
+ if (prev == NULL)
+ return false;
+
+ return epoch == prev->epoch;
+}
+
int keyrot_rekey(struct keyrot * kr,
const uint8_t * root,
uint8_t epoch)
{
struct kr_batch * nb;
struct kr_batch * old_prev;
+ struct kr_batch * cur;
+ struct kr_batch * prev;
assert(kr != NULL);
assert(root != NULL);
@@ -488,6 +504,15 @@ int keyrot_rekey(struct keyrot * kr,
rcu_wrlock(&kr->guard);
+ cur = rcu_deref(kr->cur);
+ prev = rcu_deref(kr->prev);
+
+ if (kr_epoch_live(cur, prev, epoch)) {
+ rcu_wrunlock(&kr->guard);
+ kr_batch_free(nb);
+ return -1;
+ }
+
old_prev = kr->prev;
rcu_assign(kr->prev, kr->cur);
rcu_publish(nb);