release: version 1.0.2 - Audit security fixes and RPM packaging
Security hardening: - Add input sanitization for method (32), path (2048), host (256), http_version (16) - Prevent log injection via oversized HTTP values - Add LOG_THROTTLED macro for consistent error reporting - Improve socket state double-check pattern to avoid unnecessary reconnects Code quality: - Fix const qualifier warnings in get_header() - Add flags field to module definition - Add -Wno-error=format-security for compatibility Documentation: - Clarify timestamp precision (microseconds expressed as nanoseconds) - Update README and architecture.yml Testing: - Add 4 unit tests for input sanitization - All 78 tests passing Packaging: - Remove DEB package support (RPM only: el8, el9, el10) - Add CHANGELOG file included in RPM packages - Bump version to 1.0.2 Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
@ -39,6 +39,21 @@
|
||||
/* Maximum JSON log line size (64KB) - prevents memory exhaustion DoS */
|
||||
#define MAX_JSON_SIZE (64 * 1024)
|
||||
|
||||
/* Helper macro for throttled error logging - prevents error_log flooding */
|
||||
#define LOG_THROTTLED(state, cfg, s, level, err, msg, ...) do { \
|
||||
apr_time_t lt_now = apr_time_now(); \
|
||||
int lt_should_report = 0; \
|
||||
FD_MUTEX_LOCK(state); \
|
||||
if ((lt_now - state->last_error_report) >= apr_time_from_sec(cfg->error_report_interval)) { \
|
||||
state->last_error_report = lt_now; \
|
||||
lt_should_report = 1; \
|
||||
} \
|
||||
FD_MUTEX_UNLOCK(state); \
|
||||
if (lt_should_report) { \
|
||||
ap_log_error(APLOG_MARK, level, err, s, MOD_REQIN_LOG_NAME ": " msg, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/* Default sensitive headers blacklist - prevents accidental logging of credentials */
|
||||
static const char *const DEFAULT_SENSITIVE_HEADERS[] = {
|
||||
"Authorization",
|
||||
@ -126,7 +141,8 @@ module AP_MODULE_DECLARE_DATA reqin_log_module = {
|
||||
reqin_log_create_server_conf, /* server config creator */
|
||||
NULL, /* server config merger */
|
||||
reqin_log_cmds, /* command table */
|
||||
reqin_log_register_hooks /* register hooks */
|
||||
reqin_log_register_hooks, /* register hooks */
|
||||
0 /* flags */
|
||||
};
|
||||
|
||||
/* Get module configuration */
|
||||
@ -434,9 +450,7 @@ static int try_connect(reqin_log_config_t *cfg, reqin_log_child_state_t *state,
|
||||
{
|
||||
apr_time_t now;
|
||||
apr_time_t reconnect_interval;
|
||||
apr_time_t error_interval;
|
||||
int err = 0;
|
||||
int should_report = 0;
|
||||
int fd;
|
||||
int flags;
|
||||
struct sockaddr_un addr;
|
||||
@ -454,7 +468,6 @@ static int try_connect(reqin_log_config_t *cfg, reqin_log_child_state_t *state,
|
||||
|
||||
now = apr_time_now();
|
||||
reconnect_interval = apr_time_from_sec(cfg->reconnect_interval);
|
||||
error_interval = apr_time_from_sec(cfg->error_report_interval);
|
||||
|
||||
FD_MUTEX_LOCK(state);
|
||||
|
||||
@ -471,16 +484,9 @@ static int try_connect(reqin_log_config_t *cfg, reqin_log_child_state_t *state,
|
||||
if (state->socket_fd < 0) {
|
||||
err = errno;
|
||||
state->connect_failed = 1;
|
||||
if ((now - state->last_error_report) >= error_interval) {
|
||||
state->last_error_report = now;
|
||||
should_report = 1;
|
||||
}
|
||||
FD_MUTEX_UNLOCK(state);
|
||||
|
||||
if (should_report) {
|
||||
ap_log_error(APLOG_MARK, APLOG_ERR, err, s,
|
||||
MOD_REQIN_LOG_NAME ": Unix socket connect failed: cannot create socket");
|
||||
}
|
||||
LOG_THROTTLED(state, cfg, s, APLOG_ERR, err,
|
||||
"Unix socket connect failed: cannot create socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -508,16 +514,9 @@ static int try_connect(reqin_log_config_t *cfg, reqin_log_child_state_t *state,
|
||||
close(fd);
|
||||
state->socket_fd = -1;
|
||||
state->connect_failed = 1;
|
||||
if ((now - state->last_error_report) >= error_interval) {
|
||||
state->last_error_report = now;
|
||||
should_report = 1;
|
||||
}
|
||||
FD_MUTEX_UNLOCK(state);
|
||||
|
||||
if (should_report) {
|
||||
ap_log_error(APLOG_MARK, APLOG_ERR, err, s,
|
||||
MOD_REQIN_LOG_NAME ": Unix socket connect failed: %s", cfg->socket_path);
|
||||
}
|
||||
LOG_THROTTLED(state, cfg, s, APLOG_ERR, err,
|
||||
"Unix socket connect failed: %s", cfg->socket_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -530,8 +529,11 @@ static int ensure_connected(reqin_log_config_t *cfg, reqin_log_child_state_t *st
|
||||
{
|
||||
int connected;
|
||||
|
||||
/* Double-check pattern: validate config and state under lock to avoid
|
||||
* unnecessary reconnect attempts under high concurrency */
|
||||
FD_MUTEX_LOCK(state);
|
||||
connected = (state->socket_fd >= 0 && !state->connect_failed);
|
||||
connected = (state->socket_fd >= 0 && !state->connect_failed &&
|
||||
cfg != NULL && cfg->socket_path != NULL && cfg->socket_path[0] != '\0');
|
||||
FD_MUTEX_UNLOCK(state);
|
||||
|
||||
if (connected) {
|
||||
@ -546,14 +548,11 @@ static int write_to_socket(const char *data, apr_size_t len, server_rec *s,
|
||||
{
|
||||
int fd;
|
||||
ssize_t n;
|
||||
apr_time_t error_interval;
|
||||
|
||||
if (!cfg || !state || !s || !data || len == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
error_interval = apr_time_from_sec(cfg->error_report_interval);
|
||||
|
||||
FD_MUTEX_LOCK(state);
|
||||
|
||||
fd = state->socket_fd;
|
||||
@ -565,8 +564,6 @@ static int write_to_socket(const char *data, apr_size_t len, server_rec *s,
|
||||
n = send(fd, data, len, MSG_DONTWAIT | MSG_NOSIGNAL);
|
||||
if (n < 0) {
|
||||
int err = errno;
|
||||
apr_time_t now = apr_time_now();
|
||||
int should_report = 0;
|
||||
int conn_lost = (err == EPIPE || err == ECONNRESET || err == ENOTCONN);
|
||||
|
||||
if (conn_lost) {
|
||||
@ -575,24 +572,14 @@ static int write_to_socket(const char *data, apr_size_t len, server_rec *s,
|
||||
state->connect_failed = 1;
|
||||
}
|
||||
|
||||
if (err != EAGAIN && err != EWOULDBLOCK &&
|
||||
(now - state->last_error_report) >= error_interval) {
|
||||
state->last_error_report = now;
|
||||
should_report = 1;
|
||||
}
|
||||
|
||||
FD_MUTEX_UNLOCK(state);
|
||||
|
||||
if (should_report) {
|
||||
if (conn_lost) {
|
||||
ap_log_error(APLOG_MARK, APLOG_ERR, err, s,
|
||||
MOD_REQIN_LOG_NAME ": Unix socket write failed: connection lost");
|
||||
} else {
|
||||
ap_log_error(APLOG_MARK, APLOG_ERR, err, s,
|
||||
MOD_REQIN_LOG_NAME ": Unix socket write failed");
|
||||
}
|
||||
if (conn_lost) {
|
||||
LOG_THROTTLED(state, cfg, s, APLOG_ERR, err,
|
||||
"Unix socket write failed: connection lost");
|
||||
} else {
|
||||
LOG_THROTTLED(state, cfg, s, APLOG_ERR, err,
|
||||
"Unix socket write failed");
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -613,8 +600,8 @@ static int write_to_socket(const char *data, apr_size_t len, server_rec *s,
|
||||
static const char *get_header(request_rec *r, const char *name)
|
||||
{
|
||||
const apr_table_t *headers = r->headers_in;
|
||||
apr_array_header_t *arr = apr_table_elts(headers);
|
||||
apr_table_entry_t *elts = (apr_table_entry_t *)arr->elts;
|
||||
const apr_array_header_t *arr = apr_table_elts(headers);
|
||||
const apr_table_entry_t *elts = (const apr_table_entry_t *)arr->elts;
|
||||
int nelts = arr->nelts;
|
||||
|
||||
for (int i = 0; i < nelts; i++) {
|
||||
@ -654,11 +641,27 @@ static void log_request(request_rec *r, reqin_log_config_t *cfg, reqin_log_child
|
||||
dst_ip = r->connection->local_ip ? r->connection->local_ip : "";
|
||||
method = r->method ? r->method : "UNKNOWN";
|
||||
path = r->parsed_uri.path ? r->parsed_uri.path : "/";
|
||||
/* Sanitize method and path to prevent log injection via oversized values */
|
||||
if (strlen(method) > 32) {
|
||||
method = apr_pstrmemdup(pool, method, 32);
|
||||
}
|
||||
if (strlen(path) > 2048) {
|
||||
path = apr_pstrmemdup(pool, path, 2048);
|
||||
}
|
||||
host = apr_table_get(r->headers_in, "Host");
|
||||
if (host == NULL) {
|
||||
host = "";
|
||||
} else {
|
||||
/* Sanitize Host header to prevent log injection via oversized values */
|
||||
if (strlen(host) > 256) {
|
||||
host = apr_pstrmemdup(pool, host, 256);
|
||||
}
|
||||
}
|
||||
http_version = r->protocol ? r->protocol : "UNKNOWN";
|
||||
/* Sanitize HTTP version string */
|
||||
if (strlen(http_version) > 16) {
|
||||
http_version = apr_pstrmemdup(pool, http_version, 16);
|
||||
}
|
||||
|
||||
dynbuf_init(&buf, pool, 4096);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user