Tarantool development patches archive
 help / color / mirror / Atom feed
* [Tarantool-patches] [PATCH] raft: more precise verification of incoming request state
@ 2021-06-25 10:07 Cyrill Gorcunov via Tarantool-patches
  2021-06-25 21:49 ` Vladislav Shpilevoy via Tarantool-patches
  0 siblings, 1 reply; 12+ messages in thread
From: Cyrill Gorcunov via Tarantool-patches @ 2021-06-25 10:07 UTC (permalink / raw)
  To: tml; +Cc: Vladislav Shpilevoy

When new raft message comes in from the network we need
to be sure that the payload is suitable for processing,
in particular `raft_msg::state` must be valid because
our code logic depends on it.

Since the `raft_msg::state` is declared as enum the
its processing is implementation defined an a compiler
might treat it as unsigned or signed int. In the latter
case the `if` statement won't be taken which will lead
to undefined behaviour. So

1) Use explicit unsigned type conversion to make sure
   the `state` requested is valid;
2) Use panic() instead of unreacheable() macro;
3) Extend testing.

Closes #6067

Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
---
issue https://github.com/tarantool/tarantool/issues/6067
branch gorcunov/gh-6067-raft-state-verify

 src/lib/raft/raft.c   |  7 +++++--
 test/unit/raft.c      | 10 +++++++++-
 test/unit/raft.result |  4 +++-
 3 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/src/lib/raft/raft.c b/src/lib/raft/raft.c
index eacdddb7e..409e983f0 100644
--- a/src/lib/raft/raft.c
+++ b/src/lib/raft/raft.c
@@ -309,7 +309,9 @@ raft_process_msg(struct raft *raft, const struct raft_msg *req, uint32_t source)
 	say_info("RAFT: message %s from %u", raft_msg_to_string(req), source);
 	assert(source > 0);
 	assert(source != raft->self);
-	if (req->term == 0 || req->state == 0 || req->state >= raft_state_MAX) {
+
+	if (req->term == 0 || req->state == 0 ||
+	    (unsigned)req->state >= raft_state_MAX) {
 		diag_set(RaftError, "Invalid term or state");
 		return -1;
 	}
@@ -406,7 +408,8 @@ raft_process_msg(struct raft *raft, const struct raft_msg *req, uint32_t source)
 			raft_sm_become_leader(raft);
 			break;
 		default:
-			unreachable();
+			panic("RAFT: unreacheable state hit");
+			break;
 		}
 	}
 	if (req->state != RAFT_STATE_LEADER) {
diff --git a/test/unit/raft.c b/test/unit/raft.c
index 6369c42d3..b9bc49b78 100644
--- a/test/unit/raft.c
+++ b/test/unit/raft.c
@@ -247,7 +247,7 @@ raft_test_recovery(void)
 static void
 raft_test_bad_msg(void)
 {
-	raft_start_test(9);
+	raft_start_test(11);
 	struct raft_msg msg;
 	struct raft_node node;
 	struct vclock vclock;
@@ -294,6 +294,14 @@ raft_test_bad_msg(void)
 	is(raft_node_process_msg(&node, &msg, 2), -1, "bad state");
 	is(node.raft.term, 1, "term from the bad message wasn't used");
 
+	msg = (struct raft_msg){
+		.state = -1,
+		.term = 10,
+		.vote = 2,
+	};
+	is(raft_node_process_msg(&node, &msg, 2), -1, "bad negative state");
+	is(node.raft.term, 1, "term from the bad message wasn't used");
+
 	raft_node_destroy(&node);
 	raft_finish_test();
 }
diff --git a/test/unit/raft.result b/test/unit/raft.result
index 598a7e760..f89cd1658 100644
--- a/test/unit/raft.result
+++ b/test/unit/raft.result
@@ -45,7 +45,7 @@ ok 1 - subtests
 ok 2 - subtests
 	*** raft_test_recovery: done ***
 	*** raft_test_bad_msg ***
-    1..9
+    1..11
     ok 1 - state can't be 0
     ok 2 - term from the bad message wasn't used
     ok 3 - node can't be a candidate but vote for another node
@@ -55,6 +55,8 @@ ok 2 - subtests
     ok 7 - term can't be 0
     ok 8 - bad state
     ok 9 - term from the bad message wasn't used
+    ok 10 - bad negative state
+    ok 11 - term from the bad message wasn't used
 ok 3 - subtests
 	*** raft_test_bad_msg: done ***
 	*** raft_test_vote ***
-- 
2.31.1


^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2021-07-08 21:17 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-25 10:07 [Tarantool-patches] [PATCH] raft: more precise verification of incoming request state Cyrill Gorcunov via Tarantool-patches
2021-06-25 21:49 ` Vladislav Shpilevoy via Tarantool-patches
2021-06-25 21:49   ` Vladislav Shpilevoy via Tarantool-patches
2021-06-26 13:34   ` Cyrill Gorcunov via Tarantool-patches
2021-06-27 14:12     ` Vladislav Shpilevoy via Tarantool-patches
2021-06-27 19:42       ` Cyrill Gorcunov via Tarantool-patches
2021-07-02 13:43       ` Cyrill Gorcunov via Tarantool-patches
2021-07-07 21:25         ` Vladislav Shpilevoy via Tarantool-patches
2021-07-07 21:59           ` Cyrill Gorcunov via Tarantool-patches
2021-07-07 22:05             ` Cyrill Gorcunov via Tarantool-patches
2021-07-08  9:28               ` [Tarantool-patches] [PATCH v3] raft: change request state to uint64_t Cyrill Gorcunov via Tarantool-patches
2021-07-08 21:17                 ` Vladislav Shpilevoy via Tarantool-patches

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox