Skip to content

Commit

Permalink
Fix a race condition in data store flare operations
Browse files Browse the repository at this point in the history
The race (as seen via Zeek usage) goes like:

Thread A: enqueue item, get suspended
Thread B: sees mailbox has items
Thread B: dequeue item
Thread B: extinguish flare
Thread A: resume, fire flare

That ordering can leave the flare in an active state without any actual
items remaining in the mailbox.

This patch adds a mutex/lock such that extinguishing of the flare cannot
be interleaved between the enqueue and firing of the flare.

This likely relates to zeek/zeek#838
zeek/zeek#716, as well as this thread
http://mailman.icsi.berkeley.edu/pipermail/zeek/2020-February/015062.html

(cherry picked from commit d2737cd)
  • Loading branch information
jsiwek committed Mar 9, 2020
1 parent 4bfe735 commit fac96c5
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 4 deletions.
24 changes: 24 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,4 +1,28 @@

1.2.6 | 2020-03-09 13:11:25 -0700

* Release v1.2.6

* Fix a race condition in data store flare operations (Jon Siwek, Corelight)

The race (as seen via Zeek usage that results in high CPU load) goes like:

Thread A: enqueue item, get suspended
Thread B: sees mailbox has items
Thread B: dequeue item
Thread B: extinguish flare
Thread A: resume, fire flare

That ordering can leave the flare in an active state without any actual
items remaining in the mailbox.

This patch adds a mutex/lock such that extinguishing of the flare cannot
be interleaved between the enqueue and firing of the flare.

This likely relates to https://github.com/zeek/zeek/issues/838
https://github.com/zeek/zeek/issues/716, as well as this thread
http://mailman.icsi.berkeley.edu/pipermail/zeek/2020-February/015062.html

1.2.5 | 2020-02-22 16:07:31 -0800

* Release v1.2.5
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.2.5
1.2.6
5 changes: 3 additions & 2 deletions broker/detail/flare_actor.hh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#ifndef BROKER_DETAIL_FLARE_ACTOR_HH
#define BROKER_DETAIL_FLARE_ACTOR_HH

#include <atomic>
#include <mutex>
#include <chrono>
#include <limits>

Expand Down Expand Up @@ -53,7 +53,8 @@ public:

private:
flare flare_;
std::atomic<int> flare_count_;
int flare_count_;
std::mutex flare_mtx_;
};

} // namespace detail
Expand Down
2 changes: 1 addition & 1 deletion broker/version.hh
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ using type = unsigned;

constexpr type major = 1;
constexpr type minor = 2;
constexpr type patch = 5;
constexpr type patch = 6;
constexpr auto suffix = "";

constexpr type protocol = 2;
Expand Down
7 changes: 7 additions & 0 deletions src/detail/flare_actor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,27 @@ void flare_actor::act() {

void flare_actor::await_data() {
CAF_LOG_DEBUG("awaiting data");
std::unique_lock<std::mutex> lock{flare_mtx_};
if (flare_count_ > 0 )
return;
lock.unlock();
flare_.await_one();
}

bool flare_actor::await_data(timeout_type timeout) {
CAF_LOG_DEBUG("awaiting data with timeout");
std::unique_lock<std::mutex> lock{flare_mtx_};
if (flare_count_ > 0)
return true;
lock.unlock();
auto res = flare_.await_one(timeout);
return res;
}

void flare_actor::enqueue(caf::mailbox_element_ptr ptr, caf::execution_unit*) {
auto mid = ptr->mid;
auto sender = ptr->sender;
std::unique_lock<std::mutex> lock{flare_mtx_};
switch (mailbox().enqueue(ptr.release())) {
case caf::detail::enqueue_result::unblocked_reader: {
CAF_LOG_DEBUG("firing flare");
Expand All @@ -65,6 +70,7 @@ void flare_actor::enqueue(caf::mailbox_element_ptr ptr, caf::execution_unit*) {
}

caf::mailbox_element_ptr flare_actor::dequeue() {
std::unique_lock<std::mutex> lock{flare_mtx_};
auto rval = blocking_actor::dequeue();

if (rval)
Expand All @@ -78,6 +84,7 @@ const char* flare_actor::name() const {
}

void flare_actor::extinguish_one() {
std::unique_lock<std::mutex> lock{flare_mtx_};
auto extinguished = flare_.extinguish_one();
CAF_ASSERT(extinguished);
--flare_count_;
Expand Down

0 comments on commit fac96c5

Please sign in to comment.