RHEL 9.7 ERRATUM

CVE-2025-54389 aide: improper output neutralization enables bypassing
Resolves: RHEL-109912
This commit is contained in:
Cropi 2025-08-20 12:36:24 +02:00
parent 4ed7b12b1e
commit 445369c9ce
4 changed files with 474 additions and 1 deletions

View File

@ -0,0 +1,292 @@
diff --git a/ChangeLog b/ChangeLog
index 263c438f4a2a38edc45f91c0d5a216112a8fa38c..6aa3de30b76ae98bebe89df49a7041bc6e50df25 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,27 +1,31 @@
+2025-08-07 Hannes von Haugwitz <hannes@vonhaugwitz.com>
+ * Escape control characters in report and log output (CVE-2025-54389),
+ thanks to Rajesh Pangare for reporting this issue
+
2016-07-25 Hannes von Haugwitz <hannes@vonhaugwitz.com>
- * Release version 0.16
+ * Release version 0.16
2016-07-11 Hannes von Haugwitz <hannes@vonhaugwitz.com>
* Fix example aide.conf (xattr -> xattrs)
* aide.conf.5: update "SELECTION LINES" section
* Released version 0.16rc1
2016-07-10 Hannes von Haugwitz <hannes@vonhaugwitz.com>
* Fix compilation with latest libaudit
* Use AC_PROG_CC_C99 instead of AC_PROG_CC
* Add AM_PROG_CC_C_O
* aide.conf.in: logfile -> file
* Update README
* Update manual pages (aide.1 and aide.conf.5)
2016-07-07 Hannes von Haugwitz <hannes@vonhaugwitz.com>
* Adapt manual to version 0.16
2016-06-08 Hannes von Haugwitz <hannes@vonhaugwitz.com>
* Add missing break statements
2016-04-15 Hannes von Haugwitz <hannes@vonhaugwitz.com>
* Released version 0.16b1
2016-04-13 Hannes von Haugwitz <hannes@vonhaugwitz.com>
* Fix spelling errors
diff --git a/include/util.h b/include/util.h
index 79988536c974ca83b14696380f6006031e0fa5e4..68e6ee2a905856bc7b73f1a67633585e0c1d814d 100644
--- a/include/util.h
+++ b/include/util.h
@@ -22,48 +22,51 @@
#ifndef _UTIL_H_INCLUDED
#define _UTIL_H_INCLUDED
#include <string.h>
#include <sys/types.h>
#include "db_config.h"
#define HEXD2ASC(x) (((x) < 10) ? ((x) + '0') : ((x) - 10 + 'A'))
#define ASC2HEXD(x) (((x) >= '0' && (x) <= '9') ? \
((x) - '0') : (toupper(x) - 'A' + 10))
#define ISXDIGIT(x) isxdigit ((unsigned char)(x))
#define CLEANDUP(x) (contains_unsafe (x) ? encode_string (x) : strdup (x))
#ifndef HAVE_STRICMP
# define stricmp(a,b) strcasecmp( (a), (b) )
#endif
int cmpurl(url_t*, url_t*);
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*);
char* perm_to_char(mode_t perm);
void sig_handler(int signal);
void init_sighandler(void);
char *expand_tilde(char * path);
#ifndef HAVE_STRNSTR
char* strnstr(char* haystack,char* needle,int n);
#endif
#ifndef HAVE_STRNLEN
size_t strnlen(const char *s, size_t maxlen);
#endif
int syslog_facility_lookup(char *);
#endif
diff --git a/src/aide.c b/src/aide.c
index f85c1b4b95301eb3e2cf9212093751f39ea49b10..b9b2e325cfffcd4f9f3ce4c0ae3d06dce7a6956b 100644
--- a/src/aide.c
+++ b/src/aide.c
@@ -164,54 +164,58 @@ static int read_param(int argc,char**argv)
error(0,_("-B must have a parameter\n"));
exit(INVALID_ARGUMENT_ERROR);
}
break;
}
case 'A': {
if (optarg!=NULL) {
int errorno=commandconf('A',optarg);
if (errorno!=0){
error(0,_("Configuration error in after statement:%s\n"),optarg);
exit(INVALID_CONFIGURELINE_ERROR);
}
} else {
error(0,_("-A must have a parameter\n"));
exit(INVALID_ARGUMENT_ERROR);
}
break;
}
case 'l': {
if (optarg!=NULL) {
const char* pcre_error;
int pcre_erroffset;
conf->limit=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);
+ free(limit_safe);
exit(INVALID_ARGUMENT_ERROR);
}
- error(200,_("Limit set to '%s'\n"), conf->limit);
+ char *limit_safe = stresc(conf->limit);
+ error(200,_("Limit set to '%s'\n"), limit_safe);
+ free(limit_safe);
} else {
error(0,_("-l must have an argument\n"));
exit(INVALID_ARGUMENT_ERROR);
}
break;
}
case 'r': {
if(optarg!=NULL) {
do_repurldef(optarg);
}else {
error(0,_("-r must have an argument\n"));
}
break;
}
case 'i': {
if(conf->action==0){
conf->action=DO_INIT;
}else {
error(0,
_("Cannot have multiple commands on a single commandline.\n"));
exit(INVALID_ARGUMENT_ERROR);
};
break;
}
case 'C': {
diff --git a/src/util.c b/src/util.c
index ea438273296fbac24fb5d83cd0f2661aa93c0c0a..c39ff352d7fd707471b6d6add8c099a3ca643b9d 100644
--- a/src/util.c
+++ b/src/util.c
@@ -2,89 +2,128 @@
*
* Copyright (C) 1999-2002,2004-2006,2010,2011,2013,2016 Rami Lehti, Pablo
* Virolainen, Mike Markley, Richard van den Berg, Hannes von Haugwitz
* $Header$
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "aide.h"
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
+#include <stdio.h>
#include <signal.h>
#include <ctype.h>
#include <syslog.h>
/*for locale support*/
#include "locale-aide.h"
/*for locale support*/
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 256
#endif
#include "report.h"
#include "db_config.h"
#include "util.h"
#define URL_UNSAFE " <>\"#%{}|\\^~[]`@:\033'"
#define ISPRINT(c) (isascii(c) && isprint(c))
static const char* url_name[] = {
"file", "stdin", "stdout", "stderr", "fd", "sql", "syslog", "database", "https", "http", "ftp" };
static const int url_value[] = {
url_file, url_stdin, url_stdout,url_stderr,url_fd, url_sql, url_syslog, url_database, url_https, url_http, url_ftp };
const int url_ntypes=sizeof(url_value)/sizeof(URL_TYPE);
int cmpurl(url_t* u1,url_t* u2)
{
if(u1->type!= u2->type){
return RETFAIL;
};
if(strcmp(u1->value,u2->value)!=0){
return RETFAIL;
}
return RETOK;
};
+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 = malloc(n);
+ if (str == NULL) {
+ error(0, "malloc: failed to allocate %d bytes of memory\n", n);
+ exit(EXIT_FAILURE);
+ }
+ escape_str(unescaped_str, str, s);
+ return str;
+}
+
+char *stresc(const char *unescaped_str) {
+ return strnesc(unescaped_str, strlen(unescaped_str));
+}
+
url_t* parse_url(char* val)
{
url_t* u=NULL;
char* r=NULL;
char* val_copy=NULL;
int i=0;
if(val==NULL){
return NULL;
}
u=(url_t*)malloc(sizeof(url_t));
/* We don't want to modify the original hence strdup(val) */
val_copy=strdup(val);
for(r=val_copy;r[0]!=':'&&r[0]!='\0';r++);
if(r[0]!='\0'){
r[0]='\0';
r++;
}
u->type=url_unknown;
for(i=0;i<url_ntypes;i++){
if(strcmp(val_copy,url_name[i])==0){
u->type=url_value[i];

View File

@ -0,0 +1,91 @@
diff -U0 aide-0.16/ChangeLog.orig aide-0.16/ChangeLog
diff -up aide-0.16/doc/aide.1.in.orig aide-0.16/doc/aide.1.in
diff -up aide-0.16/doc/aide.1.orig aide-0.16/doc/aide.1
diff -up aide-0.16/include/util.h.orig aide-0.16/include/util.h
diff -up aide-0.16/src/aide.c.orig aide-0.16/src/aide.c
diff -up aide-0.16/src/compare_db.c.orig aide-0.16/src/compare_db.c
--- aide-0.16/src/compare_db.c.orig 2025-08-20 16:40:25.219559352 +0200
+++ aide-0.16/src/compare_db.c 2025-08-20 16:40:33.945999660 +0200
@@ -526,15 +526,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);
+ const char *rawname = (node->checked&NODE_REMOVED?node->old_data:node->new_data)->filename;
+ char *filename_safe = stresc(rawname);
+ error(2,"\n%s: %s", summary, filename_safe);
+ free(filename_safe);
free(summary); summary=NULL;
} else {
if (node->checked&NODE_ADDED) {
- error(2,"added: %s\n",(node->new_data)->filename);
+ char *filename_safe = stresc((node->new_data)->filename);
+ error(2,"added: %s\n",filename_safe);
+ free(filename_safe);
} else if (node->checked&NODE_REMOVED) {
- error(2,"removed: %s\n",(node->old_data)->filename);
+ char *filename_safe = stresc((node->old_data)->filename);
+ error(2,"removed: %s\n",filename_safe);
+ free(filename_safe);
} else if (node->checked&NODE_CHANGED) {
- error(2,"changed: %s\n",(node->new_data)->filename);
+ char *filename_safe = stresc((node->new_data)->filename);
+ error(2,"changed: %s\n",filename_safe);
+ free(filename_safe);
}
}
}
@@ -552,6 +561,9 @@ static void print_dbline_attributes(db_l
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) {
@@ -559,21 +571,35 @@ static void print_dbline_attributes(db_l
nnumber=get_attribute_values(details_attributes[j], nline, &nvalue);
i = 0;
while (i<onumber || i<nnumber) {
- olen = i<onumber?strlen(ovalue[i]):0;
- nlen = i<nnumber?strlen(nvalue[i]):0;
+ char *ovalue_safe = NULL;
+ char *nvalue_safe = NULL;
+ if (i<onumber) {
+ ovalue_safe = stresc(ovalue[i]);
+ olen = strlen(ovalue_safe);
+ } else {
+ olen = 0;
+ }
+ if (i<nnumber) {
+ nvalue_safe = stresc(nvalue[i]);
+ nlen = strlen(nvalue_safe);
+ } else {
+ nlen = 0;
+ }
k = 0;
while (olen-p*k >= 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_safe[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_safe[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_safe[c]:"", p-1, nlen-c>0?&nvalue_safe[c]:"");
}
k++;
}
++i;
+ free(ovalue_safe);
+ free(nvalue_safe);
}
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;
diff -up aide-0.16/src/error.c.orig aide-0.16/src/error.c
diff -up aide-0.16/src/gen_list.c.orig aide-0.16/src/gen_list.c
diff -up aide-0.16/src/util.c.orig aide-0.16/src/util.c

View File

@ -0,0 +1,83 @@
diff -U0 aide-0.16/ChangeLog.orig aide-0.16/ChangeLog
--- aide-0.16/ChangeLog.orig 2025-08-20 12:10:17.957899161 +0200
+++ aide-0.16/ChangeLog 2025-08-20 12:10:21.043397557 +0200
@@ -0,0 +1,4 @@
+2025-08-07 Hannes von Haugwitz <hannes@vonhaugwitz.com>
+ * Escape control characters in report and log output (CVE-2025-54389),
+ thanks to Rajesh Pangare for reporting this issue
+
@@ -2 +6 @@
- * Release version 0.16
+ * Release version 0.16
diff -up aide-0.16/doc/aide.1.orig aide-0.16/doc/aide.1
diff -up aide-0.16/include/util.h.orig aide-0.16/include/util.h
--- aide-0.16/include/util.h.orig 2025-08-20 12:10:17.961526476 +0200
+++ aide-0.16/include/util.h 2025-08-20 12:10:21.043645131 +0200
@@ -44,6 +44,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 -up aide-0.16/src/aide.c.orig aide-0.16/src/aide.c
diff -up aide-0.16/src/gen_list.c.orig aide-0.16/src/gen_list.c
diff -up aide-0.16/src/util.c.orig aide-0.16/src/util.c
--- aide-0.16/src/util.c.orig 2025-08-20 12:10:17.954526409 +0200
+++ aide-0.16/src/util.c 2025-08-20 12:10:21.043912548 +0200
@@ -24,6 +24,7 @@
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
+#include <stdio.h>
#include <signal.h>
#include <ctype.h>
#include <syslog.h>
@@ -63,6 +64,44 @@ int cmpurl(url_t* u1,url_t* u2)
return RETOK;
};
+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 = malloc(n);
+ if (str == NULL) {
+ error(0, "malloc: failed to allocate %d bytes of memory\n", n);
+ exit(EXIT_FAILURE);
+ }
+ escape_str(unescaped_str, str, s);
+ return str;
+}
+
+char *stresc(const char *unescaped_str) {
+ return strnesc(unescaped_str, strlen(unescaped_str));
+}
+
url_t* parse_url(char* val)
{
url_t* u=NULL;

View File

@ -1,7 +1,7 @@
Summary: Intrusion detection environment
Name: aide
Version: 0.16
Release: 103%{?dist}
Release: 104%{?dist}
URL: http://sourceforge.net/projects/aide
License: GPLv2+
@ -41,6 +41,8 @@ Patch9: aide-static-analysis.patch
Patch10: aide-0.16-CVE-2021-45417.patch
Patch11: aide-db-problem.patch
Patch12: rootPrefix.patch
Patch13: aide-0.16-CVE-2025-54389-part1.patch
Patch14: aide-0.16-CVE-2025-54389-part2.patch
%description
AIDE (Advanced Intrusion Detection Environment) is a file integrity
@ -87,6 +89,11 @@ mkdir -p -m0700 %{buildroot}%{_localstatedir}/lib/aide
%dir %attr(0700,root,root) %{_localstatedir}/log/aide
%changelog
* Wed Aug 20 2025 Attila Lakatos <alakatos@redhat.com> - 0.16-104
RHEL 9.7 ERRATUM
- CVE-2025-54389 aide: improper output neutralization enables bypassing
Resolves: RHEL-109912
* Wed Jan 15 2025 Radovan Sroka <rsroka@redhat.com> - 0.16-103
RHEL 9.6.0 ERRATUM
- /boot/grub2/grubenv's timestamp is getting modified continuously due to "boot_success" implementation