0
0
Fork 0
mirror of https://github.com/netdata/netdata.git synced 2025-04-16 10:31:07 +00:00

Detect memory leaks ()

* make stderr remain intact when FSANITIZE_ADDRESS is set

* switching users makes the sanitizer fail

* check for failure to memory map journal file

* fix memory leak in buildinfo

* fix memory leak in stream_sender_structures_init(), when it is called via rrdhost_update()

* log more information when running under FSANITIZE_ADDRESS

* fix formatting
This commit is contained in:
Costa Tsaousis 2025-03-09 11:22:23 +00:00 committed by GitHub
parent 3c21d20c04
commit 070fcf1dc9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 99 additions and 59 deletions

View file

@ -159,6 +159,7 @@ static struct {
const char *json;
bool status;
const char *value;
bool value_allocated;
} BUILD_INFO[] = {
[BIB_PACKAGING_NETDATA_VERSION] = {
.category = BIC_PACKAGING,
@ -1117,7 +1118,14 @@ static struct {
};
static void build_info_set_value(BUILD_INFO_SLOT slot, const char *value) {
const char *old = BUILD_INFO[slot].value;
BUILD_INFO[slot].value = value;
if(BUILD_INFO[slot].value_allocated)
freez((void *)old);
BUILD_INFO[slot].value_allocated = false;
}
static void build_info_append_value(BUILD_INFO_SLOT slot, const char *value) {
@ -1133,13 +1141,30 @@ static void build_info_append_value(BUILD_INFO_SLOT slot, const char *value) {
else
strcpy(buf, value);
freez((void *)BUILD_INFO[slot].value);
const char *old = BUILD_INFO[slot].value;
BUILD_INFO[slot].value = strdupz(buf);
if(BUILD_INFO[slot].value_allocated)
freez((void *)old);
BUILD_INFO[slot].value_allocated = true;
}
static void build_info_set_value_strdupz(BUILD_INFO_SLOT slot, const char *value) {
if(!value) value = "";
build_info_set_value(slot, strdupz(value));
if(BUILD_INFO[slot].value && strcmp(BUILD_INFO[slot].value, value) == 0)
return;
const char *old = BUILD_INFO[slot].value;
BUILD_INFO[slot].value = strdupz(value);
if(old && BUILD_INFO[slot].value_allocated)
freez((void *)old);
BUILD_INFO[slot].value_allocated = true;
}
static void build_info_set_status(BUILD_INFO_SLOT slot, bool status) {
@ -1375,18 +1400,7 @@ __attribute__((constructor)) void initialize_build_info(void) {
// system info
static void populate_system_info(void) {
static bool populated = false;
static SPINLOCK spinlock = SPINLOCK_INITIALIZER;
if(populated)
return;
spinlock_lock(&spinlock);
if(populated) {
spinlock_unlock(&spinlock);
return;
}
FUNCTION_RUN_ONCE();
struct rrdhost_system_info *system_info;
bool free_system_info = false;
@ -1441,9 +1455,6 @@ static void populate_system_info(void) {
if(free_system_info)
rrdhost_system_info_free(system_info);
populated = true;
spinlock_unlock(&spinlock);
}
// ----------------------------------------------------------------------------
@ -1496,43 +1507,35 @@ void get_install_type(struct rrdhost_system_info *system_info) {
}
static struct {
SPINLOCK spinlock;
bool populated;
char *install_type;
char *prebuilt_arch;
char *prebuilt_distro;
} BUILD_PACKAGING_INFO = { 0 };
static void populate_packaging_info() {
if(!BUILD_PACKAGING_INFO.populated) {
spinlock_lock(&BUILD_PACKAGING_INFO.spinlock);
if(!BUILD_PACKAGING_INFO.populated) {
BUILD_PACKAGING_INFO.populated = true;
FUNCTION_RUN_ONCE();
get_install_type_internal(&BUILD_PACKAGING_INFO.install_type, &BUILD_PACKAGING_INFO.prebuilt_arch, &BUILD_PACKAGING_INFO.prebuilt_distro);
get_install_type_internal(&BUILD_PACKAGING_INFO.install_type, &BUILD_PACKAGING_INFO.prebuilt_arch, &BUILD_PACKAGING_INFO.prebuilt_distro);
if(!BUILD_PACKAGING_INFO.install_type)
BUILD_PACKAGING_INFO.install_type = "unknown";
if(!BUILD_PACKAGING_INFO.install_type)
BUILD_PACKAGING_INFO.install_type = "unknown";
if(!BUILD_PACKAGING_INFO.prebuilt_arch)
BUILD_PACKAGING_INFO.prebuilt_arch = "unknown";
if(!BUILD_PACKAGING_INFO.prebuilt_arch)
BUILD_PACKAGING_INFO.prebuilt_arch = "unknown";
if(!BUILD_PACKAGING_INFO.prebuilt_distro)
BUILD_PACKAGING_INFO.prebuilt_distro = "unknown";
if(!BUILD_PACKAGING_INFO.prebuilt_distro)
BUILD_PACKAGING_INFO.prebuilt_distro = "unknown";
build_info_set_value(BIB_PACKAGING_INSTALL_TYPE, strdupz(BUILD_PACKAGING_INFO.install_type));
build_info_set_value(BIB_PACKAGING_ARCHITECTURE, strdupz(BUILD_PACKAGING_INFO.prebuilt_arch));
build_info_set_value(BIB_PACKAGING_DISTRO, strdupz(BUILD_PACKAGING_INFO.prebuilt_distro));
build_info_set_value_strdupz(BIB_PACKAGING_INSTALL_TYPE, BUILD_PACKAGING_INFO.install_type);
build_info_set_value_strdupz(BIB_PACKAGING_ARCHITECTURE, BUILD_PACKAGING_INFO.prebuilt_arch);
build_info_set_value_strdupz(BIB_PACKAGING_DISTRO, BUILD_PACKAGING_INFO.prebuilt_distro);
CLEAN_BUFFER *wb = buffer_create(0, NULL);
ND_PROFILE_2buffer(wb, nd_profile_detect_and_configure(false), " ");
build_info_set_value_strdupz(BIB_RUNTIME_PROFILE, buffer_tostring(wb));
CLEAN_BUFFER *wb = buffer_create(0, NULL);
ND_PROFILE_2buffer(wb, nd_profile_detect_and_configure(false), " ");
build_info_set_value_strdupz(BIB_RUNTIME_PROFILE, buffer_tostring(wb));
build_info_set_status(BIB_RUNTIME_PARENT, stream_conf_is_parent(false));
build_info_set_status(BIB_RUNTIME_CHILD, stream_conf_is_child());
}
spinlock_unlock(&BUILD_PACKAGING_INFO.spinlock);
}
build_info_set_status(BIB_RUNTIME_PARENT, stream_conf_is_parent(false));
build_info_set_status(BIB_RUNTIME_CHILD, stream_conf_is_child());
OS_SYSTEM_MEMORY sm = os_system_memory(true);
if(OS_SYSTEM_MEMORY_OK(sm)) {

View file

@ -115,6 +115,7 @@ static int become_user(const char *username, int pid_fd) {
if(supplementary_groups)
freez(supplementary_groups);
#if !defined(FSANITIZE_ADDRESS)
if(os_setresgid(gid, gid, gid) != 0) {
netdata_log_error("Cannot switch to user's %s group (gid: %u).", username, gid);
return -1;
@ -129,10 +130,12 @@ static int become_user(const char *username, int pid_fd) {
netdata_log_error("Cannot switch to user's %s group (gid: %u).", username, gid);
return -1;
}
if(setegid(gid) != 0) {
netdata_log_error("Cannot effectively switch to user's %s group (gid: %u).", username, gid);
return -1;
}
if(setuid(uid) != 0) {
netdata_log_error("Cannot switch to user %s (uid: %u).", username, uid);
return -1;
@ -141,6 +144,9 @@ static int become_user(const char *username, int pid_fd) {
netdata_log_error("Cannot effectively switch to user %s (uid: %u).", username, uid);
return -1;
}
#else
fprintf(stderr, "Running with a Sanitizer, skipping setuid/setgid\n");
#endif
return(0);
}

View file

@ -742,11 +742,16 @@ int netdata_main(int argc, char **argv) {
}
}
#if !defined(FSANITIZE_ADDRESS)
if (close_open_fds == true) {
// close all open file descriptors, except the standard ones
// the caller may have left open files (lxc-attach has this issue)
os_close_all_non_std_open_fds_except(NULL, 0, 0);
}
#else
fprintf(stderr, "Running with a Sanitizer, custom allocators are disabled.\n");
fprintf(stderr, "Running with a Sanitizer, not closing open fds.\n");
#endif
if(!config_loaded) {
netdata_conf_load(NULL, 0, &user);
@ -1141,6 +1146,11 @@ int main(int argc, char *argv[])
if (rc != 10)
return rc;
#if defined(FSANITIZE_ADDRESS)
fprintf(stdout, "STDOUT: Sanitizers mode enabled...\n");
fprintf(stderr, "STDERR: Sanitizers mode enabled...\n");
#endif
nd_process_signals();
return 1;
}

View file

@ -87,9 +87,6 @@ static void posix_unmask_my_signals(void) {
}
void nd_initialize_signals(void) {
#if defined(FSANITIZE_ADDRESS)
;
#else
signals_block_all_except_deadly();
// Catch signals which we want to use
@ -112,7 +109,6 @@ void nd_initialize_signals(void) {
if(sigaction(signals_waiting[i].signo, &sa, NULL) == -1)
netdata_log_error("SIGNAL: Failed to change signal handler for: %s", signals_waiting[i].name);
}
#endif
}
static void process_triggered_signals(void) {
@ -165,10 +161,6 @@ static void process_triggered_signals(void) {
}
void nd_process_signals(void) {
#if defined(FSANITIZE_ADDRESS)
while(true)
pause();
#else
posix_unmask_my_signals();
const usec_t save_every_ut = 15 * 60 * USEC_PER_SEC;
usec_t last_update_mt = now_monotonic_usec();
@ -183,5 +175,4 @@ void nd_process_signals(void) {
poll(NULL, 0, 13 * MSEC_PER_SEC + 379);
process_triggered_signals();
}
#endif
}

View file

@ -1328,7 +1328,8 @@ void journalfile_migrate_to_v2_callback(Word_t section, unsigned datafile_fileno
int fd_v2;
uint8_t *data_start = nd_mmap_advanced(path, total_file_size, MAP_SHARED, 0, false, true, &fd_v2);
uint8_t *data = data_start;
if(!data_start)
fatal("DBENGINE: failed to memory map file '%s' of size %zu.", path, total_file_size);
memset(data_start, 0, extent_offset);
@ -1353,7 +1354,7 @@ void journalfile_migrate_to_v2_callback(Word_t section, unsigned datafile_fileno
struct journal_v2_block_trailer *journal_v2_trailer;
data = journalfile_v2_write_extent_list(JudyL_extents_pos, data_start + extent_offset);
uint8_t *data = journalfile_v2_write_extent_list(JudyL_extents_pos, data_start + extent_offset);
internal_error(true, "DBENGINE: write extent list so far %llu", (now_monotonic_usec() - start_loading) / USEC_PER_MS);
fatal_assert(data == data_start + extent_offset_trailer);

View file

@ -525,8 +525,7 @@ static void rrdhost_update(RRDHOST *host
, const char *prog_version
, int update_every
, long history
,
RRD_DB_MODE mode
, RRD_DB_MODE mode
, bool health
, bool stream
, STRING *parents

View file

@ -344,7 +344,11 @@ struct nd_log nd_log = {
.method = NDLM_DEFAULT,
.format = NDLF_LOGFMT,
.filename = LOG_DIR "/collector.log",
#if defined(FSANITIZE_ADDRESS)
.fd = -1,
#else
.fd = STDERR_FILENO,
#endif
.fp = NULL,
.min_priority = NDLP_INFO,
.limits = ND_LOG_LIMITS_DEFAULT,
@ -354,7 +358,11 @@ struct nd_log nd_log = {
.method = NDLM_DISABLED,
.format = NDLF_LOGFMT,
.filename = LOG_DIR "/debug.log",
#if defined(FSANITIZE_ADDRESS)
.fd = -1,
#else
.fd = STDOUT_FILENO,
#endif
.fp = NULL,
.min_priority = NDLP_DEBUG,
.limits = ND_LOG_LIMITS_UNLIMITED,

View file

@ -15,7 +15,7 @@ extern "C" {
#define ND_LOG_DEFAULT_THROTTLE_PERIOD 60
void errno_clear(void);
int nd_log_systemd_journal_fd(void);
void nd_log_set_user_settings(ND_LOG_SOURCES source, const char *setting);
void nd_log_set_facility(const char *facility);
void nd_log_set_priority_level(const char *setting);
@ -44,8 +44,10 @@ void nd_log_register_fatal_data_cb(log_event_t cb);
typedef void (*fatal_event_t)(void);
void nd_log_register_fatal_final_cb(fatal_event_t cb);
int nd_log_systemd_journal_fd(void);
int nd_log_health_fd(void);
int nd_log_collectors_fd(void);
typedef bool (*log_formatter_callback_t)(BUFFER *wb, void *data);
struct log_stack_entry {

View file

@ -1081,6 +1081,10 @@ SPAWN_SERVER* spawn_server_create(SPAWN_SERVER_OPTIONS options, const char *name
os_setproctitle(buf, server->argc, server->argv);
replace_stdio_with_dev_null();
if(nd_log_collectors_fd() != STDERR_FILENO)
dup2(nd_log_collectors_fd(), STDERR_FILENO);
int fds_to_keep[] = {
server->sock,
server->pipe[1],

View file

@ -46,12 +46,28 @@ void stream_sender_structures_init(RRDHOST *host, bool stream, STRING *parents,
spinlock_init(&host->sender->spinlock);
replication_sender_init(host->sender);
host->stream.snd.destination = string_dup(parents);
// gracefully swap destination
if(host->stream.snd.destination != parents) {
STRING *t = string_dup(parents);
SWAP(host->stream.snd.destination, t);
string_freez(t);
}
rrdhost_stream_parents_update_from_destination(host);
host->stream.snd.api_key = string_dup(api_key);
host->stream.snd.charts_matching = simple_pattern_create(
string2str(send_charts_matching), NULL, SIMPLE_PATTERN_EXACT, true);
// gracefully swap api_key
if(host->stream.snd.api_key != api_key) {
STRING *t = string_dup(api_key);
SWAP(host->stream.snd.api_key, t);
string_freez(t);
}
// gracefully swap send_charts_matching
{
SIMPLE_PATTERN *t = simple_pattern_create(
string2str(send_charts_matching), NULL, SIMPLE_PATTERN_EXACT, true);
SWAP(host->stream.snd.charts_matching, t);
simple_pattern_free(t);
}
rrdhost_option_set(host, RRDHOST_OPTION_SENDER_ENABLED);
}