fix: correction bugs + tests + migration el7 vers el10
Correctifs de bugs critiques: - Overflow entier dans le calcul du timestamp (nanoseconds) - Validation des composantes temporelles dans format_iso8601 - Race condition mutex: échec dur pour MPM threadés (worker/event) - Rejet des espaces en tête dans parse_int_strict Nouveaux tests unitaires (38 ajoutés): - Overflow timestamp, limites ISO8601, format fixe 20 chars - Limite de taille JSON 64KB - Détection headers sensibles (blacklist) - Validation parse_int_strict - dynbuf NULL handling et strlen mode Migration packaging: - Suppression CentOS 7 (EOL) - Ajout AlmaLinux 10 (el10) - RPMs supportés: el8, el9, el10 Mise à jour CI/CD et documentation: - .gitlab-ci.yml: jobs verify pour el8/el9/el10 - architecture.yml: OS supportés à jour - 70/70 tests pass Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
@ -15,6 +15,7 @@
|
||||
#include "apr_time.h"
|
||||
#include "apr_lib.h"
|
||||
#include "ap_config.h"
|
||||
#include "ap_mpm.h"
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
@ -237,10 +238,33 @@ static void format_iso8601(dynbuf_t *db, apr_time_t t)
|
||||
apr_time_exp_t tm;
|
||||
apr_time_exp_gmt(&tm, t);
|
||||
|
||||
/* Validate time components to prevent buffer overflow and invalid output.
|
||||
* apr_time_exp_gmt should always produce valid values, but we validate
|
||||
* defensively to catch any APR bugs or memory corruption. */
|
||||
int year = tm.tm_year + 1900;
|
||||
int mon = tm.tm_mon + 1;
|
||||
int day = tm.tm_mday;
|
||||
int hour = tm.tm_hour;
|
||||
int min = tm.tm_min;
|
||||
int sec = tm.tm_sec;
|
||||
|
||||
/* Clamp values to valid ranges to ensure fixed-width output (20 chars + null) */
|
||||
if (year < 0) year = 0;
|
||||
if (year > 9999) year = 9999;
|
||||
if (mon < 1) mon = 1;
|
||||
if (mon > 12) mon = 12;
|
||||
if (day < 1) day = 1;
|
||||
if (day > 31) day = 31;
|
||||
if (hour < 0) hour = 0;
|
||||
if (hour > 23) hour = 23;
|
||||
if (min < 0) min = 0;
|
||||
if (min > 59) min = 59;
|
||||
if (sec < 0) sec = 0;
|
||||
if (sec > 61) sec = 61;
|
||||
|
||||
char time_str[32];
|
||||
snprintf(time_str, sizeof(time_str), "%04d-%02d-%02dT%02d:%02d:%02dZ",
|
||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
year, mon, day, hour, min, sec);
|
||||
dynbuf_append(db, time_str, -1);
|
||||
}
|
||||
|
||||
@ -249,6 +273,10 @@ static int parse_int_strict(const char *arg, int *out)
|
||||
char *end = NULL;
|
||||
long v;
|
||||
if (arg == NULL || *arg == '\0' || out == NULL) return -1;
|
||||
|
||||
/* Reject leading whitespace (strtol skips it by default) */
|
||||
if (apr_isspace(*arg)) return -1;
|
||||
|
||||
errno = 0;
|
||||
v = strtol(arg, &end, 10);
|
||||
if (errno != 0 || end == arg || *end != '\0' || v < INT_MIN || v > INT_MAX) return -1;
|
||||
@ -644,7 +672,8 @@ static void log_request(request_rec *r, reqin_log_config_t *cfg, reqin_log_child
|
||||
/* timestamp (nanoseconds since epoch) */
|
||||
{
|
||||
apr_time_t now = apr_time_now();
|
||||
apr_uint64_t ns = (apr_uint64_t)now * 1000;
|
||||
/* Cast to apr_uint64_t before multiplication to prevent overflow */
|
||||
apr_uint64_t ns = ((apr_uint64_t)now) * APR_UINT64_C(1000);
|
||||
char ts_buf[32];
|
||||
snprintf(ts_buf, sizeof(ts_buf), "%" APR_UINT64_T_FMT, ns);
|
||||
dynbuf_append(&buf, "\"timestamp\":", 12);
|
||||
@ -799,6 +828,8 @@ static int reqin_log_post_read_request(request_rec *r)
|
||||
static void reqin_log_child_init(apr_pool_t *p, server_rec *s)
|
||||
{
|
||||
reqin_log_server_conf_t *srv_conf = get_server_conf(s);
|
||||
int threaded_mpm = 0;
|
||||
int mpm_threads;
|
||||
|
||||
if (srv_conf == NULL) {
|
||||
return;
|
||||
@ -809,12 +840,31 @@ static void reqin_log_child_init(apr_pool_t *p, server_rec *s)
|
||||
srv_conf->child_state.last_error_report = 0;
|
||||
srv_conf->child_state.connect_failed = 0;
|
||||
|
||||
/* Detect if we're running in a threaded MPM (worker/event) */
|
||||
if (ap_mpm_query(AP_MPMQ_IS_THREADED, &mpm_threads) == APR_SUCCESS &&
|
||||
mpm_threads > 0) {
|
||||
threaded_mpm = 1;
|
||||
}
|
||||
|
||||
srv_conf->child_state.fd_mutex = NULL;
|
||||
if (apr_thread_mutex_create(&srv_conf->child_state.fd_mutex,
|
||||
APR_THREAD_MUTEX_DEFAULT, p) != APR_SUCCESS) {
|
||||
srv_conf->child_state.fd_mutex = NULL;
|
||||
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
|
||||
MOD_REQIN_LOG_NAME ": Failed to create mutex, continuing in degraded mode");
|
||||
|
||||
if (threaded_mpm) {
|
||||
/* Critical error: cannot ensure thread safety in worker/event MPM */
|
||||
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
|
||||
MOD_REQIN_LOG_NAME ": Failed to create mutex for thread safety. "
|
||||
"Module cannot operate safely in threaded MPM. Disabling.");
|
||||
/* Disable module by clearing config */
|
||||
srv_conf->config->enabled = 0;
|
||||
return;
|
||||
} else {
|
||||
/* Prefork MPM: single thread per process, mutex not strictly needed */
|
||||
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
|
||||
MOD_REQIN_LOG_NAME ": Failed to create mutex, continuing in "
|
||||
"degraded mode (prefork MPM detected)");
|
||||
}
|
||||
}
|
||||
|
||||
if (srv_conf->config == NULL || !srv_conf->config->enabled ||
|
||||
|
||||
Reference in New Issue
Block a user