forked from lei.chen/myxce
fix(raft): reject n_peers > RAFT_MAX_PEERS in raft_init
next_index[]/match_index[]/pre_vote_replies[] are fixed-size RAFT_MAX_PEERS arrays indexed by peer; without an upper-bound check a caller passing n_peers > 8 would OOB-write in the leader-progress and pre-vote loops. Add the guard (returns -EINVAL, no mutation) + canary-checked test. Latent since task 1.1; surfaced by task 2.2 review (first loop writes into the new arrays). No current caller exceeds the bound (sim caps at 8, HA <= 4).
This commit is contained in:
parent
6ea89569fa
commit
fc87a662cd
2 changed files with 37 additions and 0 deletions
|
|
@ -15,6 +15,11 @@ int raft_init(raft_state_t *s, const raft_config_t *cfg)
|
|||
/* Validate required callbacks and n_peers before touching *s */
|
||||
if (cfg->n_peers < 1)
|
||||
return -EINVAL;
|
||||
/* Upper bound: next_index[]/match_index[]/pre_vote_replies[] are fixed-size
|
||||
* RAFT_MAX_PEERS arrays indexed by peer in [0, n_peers). Reject oversize
|
||||
* clusters so the leader-progress and pre-vote loops can never OOB-write. */
|
||||
if (cfg->n_peers > RAFT_MAX_PEERS)
|
||||
return -EINVAL;
|
||||
/* Even cluster sizes (>1) have no fault-tolerance advantage over the next
|
||||
* smaller odd size and can mislead operators into thinking split-brain is
|
||||
* impossible. Reject to prevent misconfiguration. */
|
||||
|
|
|
|||
|
|
@ -518,6 +518,37 @@ static void test_raft_init_even_peers_returns_einval(void)
|
|||
TEST_ASSERT_EQUAL_INT(RAFT_FOLLOWER, s.role);
|
||||
}
|
||||
|
||||
/* n_peers > RAFT_MAX_PEERS → -EINVAL: the fixed-size next_index[]/match_index[]/
|
||||
* pre_vote_replies[] arrays are indexed by peer, so an oversize cluster must be
|
||||
* rejected before any leader-progress/pre-vote loop can OOB-write. */
|
||||
static void test_raft_init_oversize_peers_returns_einval(void)
|
||||
{
|
||||
raft_state_t s;
|
||||
raft_callbacks_t cbs = make_full_cbs();
|
||||
raft_config_t cfg;
|
||||
|
||||
memset(&s, 0xAB, sizeof(s));
|
||||
|
||||
/* n_peers = RAFT_MAX_PEERS + 1 → must fail (would OOB next_index[]) */
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
cfg.n_peers = RAFT_MAX_PEERS + 1;
|
||||
cfg.self_idx = 0;
|
||||
cfg.cbs = &cbs;
|
||||
TEST_ASSERT_EQUAL_INT(-EINVAL, raft_init(&s, &cfg));
|
||||
|
||||
/* s must be untouched on rejection (canary) */
|
||||
{
|
||||
unsigned char buf[sizeof(s)];
|
||||
memset(buf, 0xAB, sizeof(buf));
|
||||
TEST_ASSERT_EQUAL_MEMORY(buf, &s, sizeof(s));
|
||||
}
|
||||
|
||||
/* n_peers = RAFT_MAX_PEERS (odd? RAFT_MAX_PEERS=8 is even → also rejected by
|
||||
* the even-peers rule, so use the largest valid odd size at the bound) */
|
||||
cfg.n_peers = RAFT_MAX_PEERS - 1; /* 7: odd, within bound → must succeed */
|
||||
TEST_ASSERT_EQUAL_INT(0, raft_init(&s, &cfg));
|
||||
}
|
||||
|
||||
/* n_peers == 0 → -EINVAL */
|
||||
static void test_raft_init_zero_peers_returns_einval(void)
|
||||
{
|
||||
|
|
@ -4063,6 +4094,7 @@ void test_raft(void)
|
|||
RUN_TEST(test_raft_init_null_truncate_from_returns_einval);
|
||||
RUN_TEST(test_raft_init_log_callbacks_present_succeeds);
|
||||
RUN_TEST(test_raft_init_even_peers_returns_einval);
|
||||
RUN_TEST(test_raft_init_oversize_peers_returns_einval);
|
||||
RUN_TEST(test_raft_init_zero_peers_returns_einval);
|
||||
RUN_TEST(test_raft_init_success_fields);
|
||||
RUN_TEST(test_raft_init_default_election_timeout);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue