diff --git a/aide.spec b/aide.spec index f031d3e211065422770a59e56436cc00ee9b7989..ecb7bda9443456792519d340267c3220b9e624e1 100644 --- a/aide.spec +++ b/aide.spec @@ -1,6 +1,6 @@ Name: aide Version: 0.16.2 -Release: 7 +Release: 8 Summary: Advanced Intrusion Detection Environment License: GPLv2+ URL: http://sourceforge.net/projects/aide @@ -22,6 +22,7 @@ Patch4: aide-fix-reporting-to-http-https-ftp.patch Patch5: backport-Refactor-logging-and-config-parsing-code-check-memory-allocations.patch Patch6: backport-Check-return-value-after-dynamic-memory-allocations.patch Patch7: backport-CVE-2025-54409.patch +Patch8: backport-CVE-2025-54389.patch %description AIDE (Advanced Intrusion Detection Environment, [eyd]) is a file and directory integrity checker. @@ -69,6 +70,12 @@ mkdir -p -m0700 %{buildroot}%{_localstatedir}/lib/aide %{_mandir}/*/* %changelog +* Mon Aug 25 2025 yixiangzhike - 0.16.2-8 +- Type:CVE +- ID:CVE-2025-54389 +- SUG:NA +- DESC: fix CVE-2025-54389 + * Fri Aug 15 2025 yixiangzhike - 0.16.2-7 - Type:CVE - ID:CVE-2025-54409 diff --git a/backport-CVE-2025-54389.patch b/backport-CVE-2025-54389.patch new file mode 100644 index 0000000000000000000000000000000000000000..303f3088758f7f9a0632c183e569b6ceb6e7f8ce --- /dev/null +++ b/backport-CVE-2025-54389.patch @@ -0,0 +1,244 @@ +From 13ccb0fb08afe30e96ea767f038ed8ead1022255 Mon Sep 17 00:00:00 2001 +From: Hannes von Haugwitz +Date: Thu, 14 Aug 2025 04:18:43 +0800 +Subject: [PATCH] Fix CVE-2025-54389 + +The patch was backported from openwall mail list + +improper output neutralization (potential AIDE detection bypass) + +Signed-off-by: Jinchao Li +--- + doc/aide.1 | 13 ++++++++++++ + include/util.h | 3 +++ + src/aide.c | 3 ++- + src/compare_db.c | 55 +++++++++++++++++++++++++++++++++--------------- + src/util.c | 34 ++++++++++++++++++++++++++++++ + 5 files changed, 90 insertions(+), 18 deletions(-) + +diff --git a/doc/aide.1 b/doc/aide.1 +index 0260468..96460de 100644 +--- a/doc/aide.1 ++++ b/doc/aide.1 +@@ -97,12 +97,25 @@ conditions: + Please note that due to mmap issues, aide cannot be terminated with + SIGTERM. Use SIGKILL to terminate. + ++.IP "Checksum encoding" ++ + The checksums in the database and in the output are by default base64 + encoded (see also report_base16 option). + To decode them you can use the following shell command: + + echo | base64 \-d | hexdump \-v \-e '32/1 "%02x" "\\n"' + ++.IP "Control characters" ++ ++Control characters (00-31 and 127) are always escaped in log and plain report ++output. They are escaped by a literal backslash (\\) followed by exactly 3 ++digits representing the character in octal notation (e.g. a newline is output ++as "\fB\\012\fR"). A literal backslash is not escaped unless it is followed by ++3 digits (0-9), in this case the literal backslash is escaped as ++"\fB\\134\fR". Reports in JSON format are escaped according to the JSON specs ++(e.g. a newline is output as "\fB\\b\fR" or an escape (\fBESC\fR) is output as ++"\fB\\u001b\fR") ++ + .PP + .SH FILES + .IP \fB${prefix}/etc/aide.conf\fR +diff --git a/include/util.h b/include/util.h +index 0c21162..a638147 100644 +--- a/include/util.h ++++ b/include/util.h +@@ -49,6 +49,9 @@ url_t* parse_url(char*); + + int contains_unsafe(const char*); + ++char *strnesc(const char *, size_t); ++char *stresc(const char *); ++ + void decode_string(char*); + + char* encode_string(const char*); +diff --git a/src/aide.c b/src/aide.c +index 3298735..c5f67f6 100644 +--- a/src/aide.c ++++ b/src/aide.c +@@ -186,7 +186,8 @@ static int read_param(int argc,char**argv) + conf->limit=checked_malloc(strlen(optarg)+1); + strcpy(conf->limit,optarg); + if((conf->limit_crx=pcre_compile(conf->limit, PCRE_ANCHORED, &pcre_error, &pcre_erroffset, NULL)) == NULL) { +- error(0,_("Error in limit regexp '%s' at %i: %s\n"), conf->limit, pcre_erroffset, pcre_error); ++ char * limit_safe = stresc(conf->limit); ++ error(0,_("Error in limit regexp '%s' at %i: %s\n"), limit_safe, pcre_erroffset, pcre_error); + exit(INVALID_ARGUMENT_ERROR); + } + error(200,_("Limit set to '%s'\n"), conf->limit); +diff --git a/src/compare_db.c b/src/compare_db.c +index 67049ed..b31f3fc 100644 +--- a/src/compare_db.c ++++ b/src/compare_db.c +@@ -463,6 +463,7 @@ snprintf(*values[0], l, "%s",s); + } + + static void print_line(seltree* node) { ++ char *filename_safe = stresc(((node->checked&NODE_REMOVED)?node->old_data:node->new_data)->filename); + if(conf->summarize_changes==1) { + int i; + int length = sizeof(summary_attributes)/sizeof(DB_ATTR_TYPE); +@@ -508,22 +509,24 @@ static void print_line(seltree* node) { + } + } + summary[length]='\0'; +- error(2,"\n%s: %s", summary, ((node->checked&NODE_REMOVED)?node->old_data:node->new_data)->filename); ++ error(2, "\n%s: %s", summary, filename_safe); + free(summary); summary=NULL; + } else { + if (node->checked&NODE_ADDED) { +- error(2,"added: %s\n",(node->new_data)->filename); ++ error(2,"added: %s\n",filename_safe); + } else if (node->checked&NODE_REMOVED) { +- error(2,"removed: %s\n",(node->old_data)->filename); ++ error(2,"removed: %s\n",filename_safe); + } else if (node->checked&NODE_CHANGED) { +- error(2,"changed: %s\n",(node->new_data)->filename); ++ error(2,"changed: %s\n",filename_safe); + } + } ++ free(filename_safe); + } + + static void print_dbline_attributes(db_line* oline, db_line* nline, DB_ATTR_TYPE + changed_attrs, DB_ATTR_TYPE force_attrs) { +- char **ovalue, **nvalue; ++ char **ovalues = NULL; ++ char **nvalues = NULL; + int onumber, nnumber, olen, nlen, i, j, k, c; + int length = sizeof(details_attributes)/sizeof(DB_ATTR_TYPE); + int p = (width_details-(width_details%2?13:14))/2; +@@ -533,32 +536,46 @@ static void print_dbline_attributes(db_line* oline, db_line* nline, DB_ATTR_TYPE + if (file_type) { + error(2,"%s: ", file_type); + } +- error(2,"%s\n", (nline==NULL?oline:nline)->filename); ++ char *filename_safe = stresc((nline==NULL?oline:nline)->filename); ++ error(2, "%s\n", filename_safe); ++ free(filename_safe); + attrs=force_attrs|(~(ignored_changed_attrs)&changed_attrs); + for (j=0; j < length; ++j) { + if (details_attributes[j]&attrs) { +- onumber=get_attribute_values(details_attributes[j], oline, &ovalue); +- nnumber=get_attribute_values(details_attributes[j], nline, &nvalue); ++ onumber=get_attribute_values(details_attributes[j], oline, &ovalues); ++ nnumber=get_attribute_values(details_attributes[j], nline, &nvalues); + i = 0; + while (i= 0 || nlen-p*k >= 0) { + c = k*(p-1); + if (!onumber) { +- error(2," %s%-9s%c %-*c %.*s\n", width_details%2?"":" ", (i+k)?"":details_string[j], (i+k)?' ':':', p, ' ', p-1, nlen-c>0?&nvalue[i][c]:""); ++ error(2," %s%-9s%c %-*c %.*s\n", width_details%2?"":" ", (i+k)?"":details_string[j], (i+k)?' ':':', p, ' ', p-1, nlen-c>0?&nvalue[c]:""); + } else if (!nnumber) { +- error(2," %s%-9s%c %.*s\n", width_details%2?"":" ", (i+k)?"":details_string[j], (i+k)?' ':':', p-1, olen-c>0?&ovalue[i][c]:""); ++ error(2," %s%-9s%c %.*s\n", width_details%2?"":" ", (i+k)?"":details_string[j], (i+k)?' ':':', p-1, olen-c>0?&ovalue[c]:""); + } else { +- error(2," %s%-9s%c %-*.*s| %.*s\n", width_details%2?"":" ", (i+k)?"":details_string[j], (i+k)?' ':':', p, p-1, olen-c>0?&ovalue[i][c]:"", p-1, nlen-c>0?&nvalue[i][c]:""); ++ error(2," %s%-9s%c %-*.*s| %.*s\n", width_details%2?"":" ", (i+k)?"":details_string[j], (i+k)?' ':':', p, p-1, olen-c>0?&ovalue[c]:"", p-1, nlen-c>0?&nvalue[c]:""); + } + k++; + } + ++i; ++ free(ovalue); ++ free(nvalue); + } +- for(i=0; i < onumber; ++i) { free(ovalue[i]); ovalue[i]=NULL; } free(ovalue); ovalue=NULL; +- for(i=0; i < nnumber; ++i) { free(nvalue[i]); nvalue[i]=NULL; } free(nvalue); nvalue=NULL; ++ for(i=0; i < onumber; ++i) { free(ovalues[i]); ovalues[i]=NULL; } free(ovalues); ovalues=NULL; ++ for(i=0; i < nnumber; ++i) { free(nvalues[i]); nvalues[i]=NULL; } free(nvalues); nvalues=NULL; + } + } + } +@@ -658,13 +675,17 @@ static void print_report_header() { + error(2,_("Config version used: %s\n"),conf->config_version); + + if (conf->limit != NULL) { +- error (2,_("Limit: %s"), conf->limit); ++ char *limit_safe = stresc(conf->limit); ++ error (2,_("Limit: %s"), limit_safe); ++ free(limit_safe); + first = 0; + } + if (conf->action&(DO_INIT|DO_COMPARE) && conf->root_prefix_length > 0) { + if (first) { first=0; } + else { error (2," | "); } +- error (2,_("Root prefix: %s"),conf->root_prefix); ++ char *prefix_safe = stresc(conf->root_prefix); ++ error (2,_("Root prefix: %s"),prefix_safe); ++ free(prefix_safe); + } + if (conf->verbose_level != 5) { + if (first) { first=0; } +diff --git a/src/util.c b/src/util.c +index 14167ee..12dd2d0 100644 +--- a/src/util.c ++++ b/src/util.c +@@ -184,6 +184,40 @@ url_t* parse_url(char* val) + return u; + } + ++static size_t escape_str(const char *unescaped_str, char *str, size_t s) { ++ size_t n = 0; ++ size_t i = 0; ++ char c; ++ while (i < s && (c = unescaped_str[i])) { ++ if ((c >= 0 && (c < 0x1f || c == 0x7f)) || ++ (c == '\\' && isdigit(unescaped_str[i+1]) ++ && isdigit(unescaped_str[i+2]) ++ && isdigit(unescaped_str[i+3]) ++ ) ) { ++ if (str) { snprintf(&str[n], 5, "\\%03o", c); } ++ n += 4; ++ } else { ++ if (str) { str[n] = c; } ++ n++; ++ } ++ i++; ++ } ++ if (str) { str[n] = '\0'; } ++ n++; ++ return n; ++} ++ ++char *strnesc(const char *unescaped_str, size_t s) { ++ int n = escape_str(unescaped_str, NULL, s); ++ char *str = checked_malloc(n); ++ escape_str(unescaped_str, str, s); ++ return str; ++} ++ ++char *stresc(const char *unescaped_str) { ++ return strnesc(unescaped_str, strlen(unescaped_str)); ++} ++ + /* Returns 1 if the string contains unsafe characters, 0 otherwise. */ + int contains_unsafe (const char *s) + { +-- +2.27.0 + +