myconf->lock (mylock_init/fini wiring) had landed but load_primary_config() itself was left in its RED-phase reproduction state (unguarded, decoding directly into the shared myconf->cluster_config field), so the fix's own regression test failed on resume: thread B raced through while thread A was parked mid-call. Wraps the whole free-decode-publish sequence in myconf->lock (acquired first, released on every return path) and decodes into a local cluster_config_t* first, publishing into myconf->cluster_config only after full decode and validation succeed -- closing the UAF/double-free window a live 3-node ASan soak caught (two concurrent handle_repl_config_push deliveries for the same standby racing two load_primary_config calls). Verified 4/4 clean full-suite runs (1036 tests, 0 failures) including the specific race test.
74 lines
3.9 KiB
C
74 lines
3.9 KiB
C
#if !defined(_MYCONF_H_)
|
|
|
|
#define _MYCONF_H_ 1
|
|
|
|
#define MAX_MASTER_CANDIDATES (64)
|
|
|
|
#include <time.h>
|
|
#include <stdint.h>
|
|
|
|
#include <tlog.h>
|
|
|
|
#include "clusterconfig.h"
|
|
#include "mylock.h"
|
|
#include "xce/cluster.h"
|
|
|
|
/* Forward declaration — avoids circular include with cluster_def.h */
|
|
typedef struct cluster_s cluster_t;
|
|
|
|
struct logging {
|
|
char* logdir;
|
|
char* loglevel;
|
|
};
|
|
|
|
typedef struct {
|
|
cluster_config_t* cluster_config;
|
|
char* conffile;
|
|
char* certfile;
|
|
char* keyfile;
|
|
char* workdir; /* working directory for WAL/snapshot storage */
|
|
char* name; /* controller name (hostname by default) */
|
|
xce_cluster_config_t peers_cfg; /* HA peer list parsed from --peers; count==0 = single-node */
|
|
uint64_t config_version_tag; /* first 8 bytes of SHA-256, host order */
|
|
uint8_t config_sha256[32]; /* full SHA-256 of conffile bytes */
|
|
int conf_keep_n; /* versioned file retention count (default 2) */
|
|
uint64_t config_generation; /* monotonic audit counter */
|
|
time_t conf_stale_timeout; /* seconds before saved config flagged stale (default 86400) */
|
|
int conf_stale; /* 1 when saved config older than conf_stale_timeout */
|
|
int vcpus; /* Req 4.3: --vcpus CLI value; 0 = use config default */
|
|
uint32_t sync_timeout_ms; /* --sync-timeout-ms; 0 = use persist default */
|
|
uint32_t wal_sync_ms; /* --wal-sync-ms; 0 = use persist default */
|
|
uint32_t max_wal_records; /* --max-wal-records; 0 = use persist default */
|
|
uint32_t wal_segment_bytes; /* --wal-segment-bytes; 0 = use persist default */
|
|
uint32_t jobmgr_nhash; /* --jobmgr-nhash CLI value; 0 = use hardcoded default */
|
|
uint32_t jobmgr_delta; /* --jobmgr-delta CLI value; 0 = use hardcoded default */
|
|
uint32_t workermgr_nhash; /* --workermgr-nhash CLI value; 0 = use hardcoded default */
|
|
uint32_t workermgr_delta; /* --workermgr-delta CLI value; 0 = use hardcoded default */
|
|
uint32_t qmgr_nhash; /* --qmgr-nhash CLI value; 0 = use hardcoded default */
|
|
uint32_t qmgr_delta; /* --qmgr-delta CLI value; 0 = use hardcoded default */
|
|
uint32_t resmgr_nhash; /* --resmgr-nhash CLI value; 0 = use hardcoded default */
|
|
uint32_t resmgr_delta; /* --resmgr-delta CLI value; 0 = use hardcoded default */
|
|
uint32_t resmgr_inst_delta; /* --resmgr-inst-delta CLI value; 0 = use hardcoded default */
|
|
uint32_t xstrings_nhash; /* --xstrings-nhash CLI value; 0 = use hardcoded default */
|
|
uint32_t xstrings_delta; /* --xstrings-delta CLI value; 0 = use hardcoded default */
|
|
/* bug-1476: serializes load_primary_config()'s free-decode-publish
|
|
* sequence against concurrent invocations for the SAME myconf_t (e.g.
|
|
* two racing handle_repl_config_push deliveries dispatched onto separate
|
|
* VTASK_LIVE_BLOCK workers for the same standby -- a live ASan
|
|
* heap-use-after-free was caught this way). Must be mylock_init()'d
|
|
* before first use (main.c) and mylock_fini()'d in myconf_fini(); test
|
|
* fixtures that drive the real load_primary_config()/
|
|
* config_activate_committed() must init it too (see
|
|
* t43_attach_myconf/t43_free_myconf in test_config_repl.c). */
|
|
mylock_t lock;
|
|
} myconf_t;
|
|
|
|
extern cluster_config_t* get_default_conf(void*);
|
|
extern int add_config(void*, char*, char*);
|
|
|
|
void myconf_fini(myconf_t *myconf);
|
|
|
|
int load_primary_config(cluster_t *c);
|
|
int fetch_config_from_primary(cluster_t *c);
|
|
|
|
#endif
|