RHEL 8.10.Z ERRATUM
CVE-2025-54389 aide: improper output neutralization enables bypassing resolves: RHEL-109907
This commit is contained in:
parent
8a006b5c48
commit
ea4fc9e55d
220
aide-0.16-CVE-2025-54389-part2.patch
Normal file
220
aide-0.16-CVE-2025-54389-part2.patch
Normal file
@ -0,0 +1,220 @@
|
||||
diff -up aide-0.16/src/db_disk.c.orig aide-0.16/src/db_disk.c
|
||||
--- aide-0.16/src/db_disk.c.orig 2025-08-21 09:58:21.271581589 +0200
|
||||
+++ aide-0.16/src/db_disk.c 2025-08-21 10:01:26.310573141 +0200
|
||||
@@ -139,7 +139,11 @@ void add_child (db_line * fil)
|
||||
int i;
|
||||
struct seltree *new_r;
|
||||
|
||||
- error (255, "Adding child %s\n", fil->filename);
|
||||
+ {
|
||||
+ char *fname_safe = stresc(fil->filename);
|
||||
+ error (255, "Adding child %s\n", fname_safe);
|
||||
+ free(fname_safe);
|
||||
+ }
|
||||
|
||||
new_r = get_seltree_node (r, fil->filename);
|
||||
if (new_r != NULL) {
|
||||
@@ -182,9 +186,13 @@ static int get_file_status(char *filenam
|
||||
if(sres == -1){
|
||||
char* er = strerror(errno);
|
||||
if (er == NULL) {
|
||||
- error(0,"get_file_status: lstat() failed for %s. strerror() failed for %i\n", filename, errno);
|
||||
+ char *filename_safe = stresc(filename);
|
||||
+ error(0,"get_file_status: lstat() failed for %s. strerror() failed for %i\n", filename_safe, errno);
|
||||
+ free(filename_safe);
|
||||
} else {
|
||||
- error(0,"get_file_status: lstat() failed for %s: %s\n", filename, er);
|
||||
+ char *filename_safe = stresc(filename);
|
||||
+ error(0,"get_file_status: lstat() failed for %s: %s\n", filename_safe, er);
|
||||
+ free(filename_safe);
|
||||
}
|
||||
}
|
||||
return sres;
|
||||
@@ -220,7 +228,11 @@ db_line *db_readline_disk ()
|
||||
error (240, "%s attr=%llu\n", &fullname[conf->root_prefix_length], attr);
|
||||
|
||||
if (fil != NULL) {
|
||||
- error (240, "%s attr=%llu\n", fil->filename, fil->attr);
|
||||
+ {
|
||||
+ char *fname_safe = stresc(fil->filename);
|
||||
+ error (240, "%s attr=%llu\n", fname_safe, fil->attr);
|
||||
+ free(fname_safe);
|
||||
+ }
|
||||
return fil;
|
||||
}
|
||||
}
|
||||
@@ -269,7 +281,11 @@ recursion:
|
||||
error (240, "%s attr=%llu\n", &fullname[conf->root_prefix_length], attr);
|
||||
|
||||
if (fil != NULL) {
|
||||
- error (240, "%s attr=%llu\n", fil->filename, fil->attr);
|
||||
+ {
|
||||
+ char *fname_safe = stresc(fil->filename);
|
||||
+ error (240, "%s attr=%llu\n", fname_safe, fil->attr);
|
||||
+ free(fname_safe);
|
||||
+ }
|
||||
} else {
|
||||
/*
|
||||
Something went wrong during read process ->
|
||||
diff -up aide-0.16/src/gen_list.c.orig aide-0.16/src/gen_list.c
|
||||
--- aide-0.16/src/gen_list.c.orig 2025-08-21 09:58:21.273581610 +0200
|
||||
+++ aide-0.16/src/gen_list.c 2025-08-21 10:04:29.190502666 +0200
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "list.h"
|
||||
#include "gen_list.h"
|
||||
#include "seltree.h"
|
||||
+#include "util.h"
|
||||
#include "db.h"
|
||||
#include "db_config.h"
|
||||
#include "commandconf.h"
|
||||
@@ -993,16 +994,28 @@ int check_rxtree(char* filename,seltree*
|
||||
if(conf->limit!=NULL) {
|
||||
retval=pcre_exec(conf->limit_crx, NULL, filename, strlen(filename), 0, PCRE_PARTIAL_SOFT, NULL, 0);
|
||||
if (retval >= 0) {
|
||||
- error(220, "check_rxtree: %s does match limit: %s\n", filename, conf->limit);
|
||||
+ char *fname_safe = stresc(filename);
|
||||
+ char *limit_safe = conf->limit?stresc(conf->limit):NULL;
|
||||
+ error(220, "check_rxtree: %s does match limit: %s\n", fname_safe, limit_safe?limit_safe:"");
|
||||
+ free(fname_safe);
|
||||
+ free(limit_safe);
|
||||
} else if (retval == PCRE_ERROR_PARTIAL) {
|
||||
- error(220, "check_rxtree: %s does PARTIAL match limit: %s\n", filename, conf->limit);
|
||||
+ char *fname_safe = stresc(filename);
|
||||
+ char *limit_safe = conf->limit?stresc(conf->limit):NULL;
|
||||
+ error(220, "check_rxtree: %s does PARTIAL match limit: %s\n", fname_safe, limit_safe?limit_safe:"");
|
||||
if(S_ISDIR(perm) && get_seltree_node(tree,filename)==NULL){
|
||||
- error(220, "check_rxtree: creating new seltree node for '%s'\n", filename);
|
||||
+ error(220, "check_rxtree: creating new seltree node for '%s'\n", fname_safe);
|
||||
new_seltree_node(tree,filename,0,NULL);
|
||||
}
|
||||
+ free(fname_safe);
|
||||
+ free(limit_safe);
|
||||
return -1;
|
||||
} else {
|
||||
- error(220, "check_rxtree: %s does NOT match limit: %s\n", filename, conf->limit);
|
||||
+ char *fname_safe = stresc(filename);
|
||||
+ char *limit_safe = conf->limit?stresc(conf->limit):NULL;
|
||||
+ error(220, "check_rxtree: %s does NOT match limit: %s\n", fname_safe, limit_safe?limit_safe:"");
|
||||
+ free(fname_safe);
|
||||
+ free(limit_safe);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
@@ -1039,13 +1052,25 @@ db_line* get_file_attrs(char* filename,D
|
||||
} else {
|
||||
|
||||
if(fs->st_atime>cur_time){
|
||||
- error(CLOCK_SKEW,_("%s atime in future\n"),filename);
|
||||
+ {
|
||||
+ char *fname_safe = stresc(filename);
|
||||
+ error(CLOCK_SKEW,_("%s atime in future\n"),fname_safe);
|
||||
+ free(fname_safe);
|
||||
+ }
|
||||
}
|
||||
if(fs->st_mtime>cur_time){
|
||||
- error(CLOCK_SKEW,_("%s mtime in future\n"),filename);
|
||||
+ {
|
||||
+ char *fname_safe = stresc(filename);
|
||||
+ error(CLOCK_SKEW,_("%s mtime in future\n"),fname_safe);
|
||||
+ free(fname_safe);
|
||||
+ }
|
||||
}
|
||||
if(fs->st_ctime>cur_time){
|
||||
- error(CLOCK_SKEW,_("%s ctime in future\n"),filename);
|
||||
+ {
|
||||
+ char *fname_safe = stresc(filename);
|
||||
+ error(CLOCK_SKEW,_("%s ctime in future\n"),fname_safe);
|
||||
+ free(fname_safe);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1220,7 +1245,11 @@ void hsymlnk(db_line* line) {
|
||||
int sres;
|
||||
sres=AIDE_STAT_FUNC(line->fullpath,&fs);
|
||||
if (sres!=0 && sres!=EACCES) {
|
||||
- error(4,"Dead symlink detected at %s\n",line->fullpath);
|
||||
+ {
|
||||
+ char *fp_safe = stresc(line->fullpath);
|
||||
+ error(4,"Dead symlink detected at %s\n",fp_safe);
|
||||
+ free(fp_safe);
|
||||
+ }
|
||||
}
|
||||
if(!(line->attr&DB_RDEV))
|
||||
fs.st_rdev=0;
|
||||
diff -up aide-0.16/src/util.c.orig aide-0.16/src/util.c
|
||||
--- aide-0.16/src/util.c.orig 2025-08-21 09:58:21.272581600 +0200
|
||||
+++ aide-0.16/src/util.c 2025-08-21 10:07:50.157894133 +0200
|
||||
@@ -104,9 +104,11 @@ url_t* parse_url(char* val)
|
||||
r+=2;
|
||||
for(i=0;r[0]!='/'&&r[0]!='\0';r++,i++);
|
||||
if(r[0]=='\0'){
|
||||
- error(0,"Invalid file-URL,no path after hostname: file:%s\n",t);
|
||||
+ char *t_safe = stresc(t);
|
||||
+ error(0,"Invalid file-URL,no path after hostname: file:%s\n",t_safe);
|
||||
+ free(t_safe);
|
||||
free(hostname);
|
||||
- return NULL;
|
||||
+ return NULL;
|
||||
}
|
||||
u->value=strdup(r);
|
||||
r[0]='\0';
|
||||
@@ -118,9 +120,11 @@ url_t* parse_url(char* val)
|
||||
free(hostname);
|
||||
break;
|
||||
} else {
|
||||
- error(0,"Invalid file-URL, cannot use hostname other than localhost or %s: file:%s\n",hostname,u->value);
|
||||
- free(hostname);
|
||||
- return NULL;
|
||||
+ char *value_safe = stresc(u->value);
|
||||
+ error(0,"Invalid file-URL, cannot use hostname other than localhost or %s: file:%s\n",hostname,value_safe);
|
||||
+ free(value_safe);
|
||||
+ free(hostname);
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -150,6 +154,43 @@ 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 = malloc(n);
|
||||
+ if (str == NULL) {
|
||||
+ error(0, "malloc: failed to allocate %d bytes of memory\n", n);
|
||||
+ exit(1);
|
||||
+ }
|
||||
+ 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)
|
||||
{
|
||||
@ -584,213 +584,6 @@ index c17828d3e8b732096e00253f21623339f2168ccf..41e216527a9b05b90f1b601a61279fd4
|
||||
if (forced_attrs) {
|
||||
error (2,_("Forced attributes: %s\n"),report_attrs(forced_attrs));
|
||||
}
|
||||
diff --git a/src/db_disk.c b/src/db_disk.c
|
||||
index 6161af38010633cbc2c4519a76e997c992439562..11f0d1c348a097a4175640e0f554979f7c74f7c1 100644
|
||||
--- a/src/db_disk.c
|
||||
+++ b/src/db_disk.c
|
||||
@@ -117,181 +117,197 @@ static char *name_construct (const char *s)
|
||||
{
|
||||
char *ret;
|
||||
int len2 = strlen (r->path);
|
||||
int len = len2 + strlen (s) + 2 + conf->root_prefix_length;
|
||||
|
||||
if (r->path[len2 - 1] != '/') {
|
||||
len++;
|
||||
}
|
||||
|
||||
ret = (char *) malloc (len);
|
||||
ret[0] = (char) 0;
|
||||
strcpy(ret, conf->root_prefix);
|
||||
strcat (ret, r->path);
|
||||
if (r->path[len2 - 1] != '/') {
|
||||
strcat (ret, "/");
|
||||
}
|
||||
strcat (ret, s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void add_child (db_line * fil)
|
||||
{
|
||||
int i;
|
||||
struct seltree *new_r;
|
||||
|
||||
- error (255, "Adding child %s\n", fil->filename);
|
||||
+ {
|
||||
+ char *fname_safe = stresc(fil->filename);
|
||||
+ error (255, "Adding child %s\n", fname_safe);
|
||||
+ free(fname_safe);
|
||||
+ }
|
||||
|
||||
new_r = get_seltree_node (r, fil->filename);
|
||||
if (new_r != NULL) {
|
||||
if (S_ISDIR (fil->perm_o)) {
|
||||
;
|
||||
} else {
|
||||
new_r->checked |= NODE_CHECKED;
|
||||
new_r->checked |= NODE_TRAVERSE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
new_r = malloc (sizeof (seltree));
|
||||
|
||||
new_r->attr = 0;
|
||||
i = strlen (fil->filename);
|
||||
|
||||
new_r->path = malloc (i + 1);
|
||||
strncpy(new_r->path, fil->filename, i+1);
|
||||
new_r->childs = NULL;
|
||||
new_r->sel_rx_lst = NULL;
|
||||
new_r->neg_rx_lst = NULL;
|
||||
new_r->equ_rx_lst = NULL;
|
||||
new_r->parent = r;
|
||||
new_r->checked = 0;
|
||||
new_r->new_data = NULL;
|
||||
new_r->old_data = NULL;
|
||||
if (S_ISDIR (fil->perm_o)) {
|
||||
;
|
||||
} else {
|
||||
new_r->checked |= NODE_CHECKED;
|
||||
new_r->checked |= NODE_TRAVERSE;
|
||||
}
|
||||
r->childs = list_sorted_insert (r->childs, new_r, compare_node_by_path);
|
||||
}
|
||||
|
||||
static int get_file_status(char *filename, struct AIDE_STAT_TYPE *fs) {
|
||||
int sres = 0;
|
||||
sres = AIDE_LSTAT_FUNC(filename,fs);
|
||||
if(sres == -1){
|
||||
char* er = strerror(errno);
|
||||
if (er == NULL) {
|
||||
- error(0,"get_file_status: lstat() failed for %s. strerror() failed for %i\n", filename, errno);
|
||||
+ char *filename_safe = stresc(filename);
|
||||
+ error(0,"get_file_status: lstat() failed for %s. strerror() failed for %i\n", filename_safe, errno);
|
||||
+ free(filename_safe);
|
||||
} else {
|
||||
- error(0,"get_file_status: lstat() failed for %s: %s\n", filename, er);
|
||||
+ char *filename_safe = stresc(filename);
|
||||
+ error(0,"get_file_status: lstat() failed for %s: %s\n", filename_safe, er);
|
||||
+ free(filename_safe);
|
||||
}
|
||||
}
|
||||
return sres;
|
||||
}
|
||||
|
||||
/*
|
||||
It might be a good idea to make this non recursive.
|
||||
Now implemented with goto-statement. Yeah, it's ugly and easy.
|
||||
*/
|
||||
|
||||
db_line *db_readline_disk ()
|
||||
{
|
||||
db_line *fil = NULL;
|
||||
DB_ATTR_TYPE attr;
|
||||
char *fullname;
|
||||
int add = 0;
|
||||
struct AIDE_STAT_TYPE fs;
|
||||
|
||||
/* root needs special handling */
|
||||
if (!root_handled) {
|
||||
root_handled = 1;
|
||||
fullname=malloc((conf->root_prefix_length+2)*sizeof(char));
|
||||
strcpy(fullname, conf->root_prefix);
|
||||
strcat (fullname, "/");
|
||||
if (!get_file_status(fullname, &fs)) {
|
||||
add = check_rxtree (&fullname[conf->root_prefix_length], conf->tree, &attr, fs.st_mode);
|
||||
error (240, "%s match=%d, tree=%p, attr=%llu\n", &fullname[conf->root_prefix_length], add,
|
||||
conf->tree, attr);
|
||||
|
||||
if (add > 0) {
|
||||
fil = get_file_attrs (fullname, attr, &fs);
|
||||
|
||||
error (240, "%s attr=%llu\n", &fullname[conf->root_prefix_length], attr);
|
||||
|
||||
if (fil != NULL) {
|
||||
- error (240, "%s attr=%llu\n", fil->filename, fil->attr);
|
||||
+ {
|
||||
+ char *fname_safe = stresc(fil->filename);
|
||||
+ error (240, "%s attr=%llu\n", fname_safe, fil->attr);
|
||||
+ free(fname_safe);
|
||||
+ }
|
||||
return fil;
|
||||
}
|
||||
}
|
||||
}
|
||||
free (fullname);
|
||||
}
|
||||
recursion:
|
||||
next_in_dir ();
|
||||
|
||||
if (in_this ()) {
|
||||
|
||||
/*
|
||||
Let's check if we have '.' or '..' entry.
|
||||
If have, just skipit.
|
||||
If don't do the 'normal' thing.
|
||||
*/
|
||||
if (strcmp (entp->d_name, ".") == 0 || strcmp (entp->d_name, "..") == 0) {
|
||||
goto recursion; // return db_readline_disk(db);
|
||||
}
|
||||
|
||||
/*
|
||||
Now we know that we actually can do something.
|
||||
*/
|
||||
|
||||
fullname = name_construct (entp->d_name);
|
||||
|
||||
/*
|
||||
Now we have a filename, which we must remember to free if it is
|
||||
not used.
|
||||
|
||||
Next thing is to see if we want to do something with it.
|
||||
If not call, db_readline_disk again...
|
||||
*/
|
||||
|
||||
if (get_file_status(fullname, &fs)) {
|
||||
free (fullname);
|
||||
goto recursion;
|
||||
}
|
||||
add = check_rxtree (&fullname[conf->root_prefix_length], conf->tree, &attr, fs.st_mode);
|
||||
error (240, "%s match=%d, tree=%p, attr=%llu\n", &fullname[conf->root_prefix_length], add,
|
||||
conf->tree, attr);
|
||||
|
||||
if (add > 0) {
|
||||
fil = get_file_attrs (fullname, attr, &fs);
|
||||
|
||||
error (240, "%s attr=%llu\n", &fullname[conf->root_prefix_length], attr);
|
||||
|
||||
if (fil != NULL) {
|
||||
- error (240, "%s attr=%llu\n", fil->filename, fil->attr);
|
||||
+ {
|
||||
+ char *fname_safe = stresc(fil->filename);
|
||||
+ error (240, "%s attr=%llu\n", fname_safe, fil->attr);
|
||||
+ free(fname_safe);
|
||||
+ }
|
||||
} else {
|
||||
/*
|
||||
Something went wrong during read process ->
|
||||
Let's try next one.
|
||||
*/
|
||||
free (fullname);
|
||||
goto recursion; // return db_readline_disk(db);
|
||||
}
|
||||
|
||||
if (add == 1) {
|
||||
/*
|
||||
add_children -> if dir, then add to children list.
|
||||
*/
|
||||
/* If ee are adding a file that is not a dir */
|
||||
/* add_child can make the determination and mark the tree
|
||||
accordingly
|
||||
*/
|
||||
add_child (fil);
|
||||
} else if (add == 2) {
|
||||
/*
|
||||
Don't add to children list.
|
||||
*/
|
||||
|
||||
/*
|
||||
Should we do something?
|
||||
diff --git a/src/db_sql.c b/src/db_sql.c
|
||||
index 154579070ccacb6e9b6b8393b989eb50c843e71d..09a32504c317607150174d2bec0fcddf47992995 100644
|
||||
--- a/src/db_sql.c
|
||||
@ -1258,405 +1051,3 @@ index 77d2e15f5f9cdba5168a92feaf2f97128e705f36..4a648b6f5ff14edd553a3f8d94b11717
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
diff --git a/src/gen_list.c b/src/gen_list.c
|
||||
index ab257811485831b1db1b027a94b5c0447a92f923..5b4a93eef28e1930a52e8156df661ca999035f54 100644
|
||||
--- a/src/gen_list.c
|
||||
+++ b/src/gen_list.c
|
||||
@@ -16,50 +16,51 @@
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <pcre.h>
|
||||
|
||||
#include "report.h"
|
||||
#include "list.h"
|
||||
#include "gen_list.h"
|
||||
#include "seltree.h"
|
||||
#include "db.h"
|
||||
+#include "util.h"
|
||||
#include "db_config.h"
|
||||
#include "commandconf.h"
|
||||
#include "report.h"
|
||||
/*for locale support*/
|
||||
#include "locale-aide.h"
|
||||
/*for locale support*/
|
||||
|
||||
#define CLOCK_SKEW 5
|
||||
|
||||
#ifdef WITH_MHASH
|
||||
#include <mhash.h>
|
||||
#endif
|
||||
#include "md.h"
|
||||
#include "do_md.h"
|
||||
|
||||
void hsymlnk(db_line* line);
|
||||
void fs2db_line(struct AIDE_STAT_TYPE* fs,db_line* line);
|
||||
void calc_md(struct AIDE_STAT_TYPE* old_fs,db_line* line);
|
||||
void no_hash(db_line* line);
|
||||
|
||||
static DB_ATTR_TYPE get_special_report_group(char* group) {
|
||||
DB_ATTR_TYPE attr = get_groupval(group);
|
||||
return attr==DB_ATTR_UNDEF?0:attr;
|
||||
}
|
||||
|
||||
@@ -971,103 +972,127 @@ static void add_file_to_tree(seltree* tree,db_line* file,int db,
|
||||
}
|
||||
}
|
||||
|
||||
int check_rxtree(char* filename,seltree* tree,DB_ATTR_TYPE* attr, mode_t perm)
|
||||
{
|
||||
int retval=0;
|
||||
char * tmp=NULL;
|
||||
char * parentname=NULL;
|
||||
seltree* pnode=NULL;
|
||||
|
||||
parentname=strdup(filename);
|
||||
tmp=strrchr(parentname,'/');
|
||||
if(tmp!=parentname){
|
||||
*tmp='\0';
|
||||
}else {
|
||||
|
||||
if(parentname[1]!='\0'){
|
||||
/* we are in the root dir */
|
||||
parentname[1]='\0';
|
||||
}
|
||||
}
|
||||
|
||||
if(conf->limit!=NULL) {
|
||||
retval=pcre_exec(conf->limit_crx, NULL, filename, strlen(filename), 0, PCRE_PARTIAL_SOFT, NULL, 0);
|
||||
if (retval >= 0) {
|
||||
- error(220, "check_rxtree: %s does match limit: %s\n", filename, conf->limit);
|
||||
+ char *fname_safe = stresc(filename);
|
||||
+ char *limit_safe = conf->limit?stresc(conf->limit):NULL;
|
||||
+ error(220, "check_rxtree: %s does match limit: %s\n", fname_safe, limit_safe?limit_safe:"");
|
||||
+ free(fname_safe);
|
||||
+ free(limit_safe);
|
||||
} else if (retval == PCRE_ERROR_PARTIAL) {
|
||||
- error(220, "check_rxtree: %s does PARTIAL match limit: %s\n", filename, conf->limit);
|
||||
+ char *fname_safe = stresc(filename);
|
||||
+ char *limit_safe = conf->limit?stresc(conf->limit):NULL;
|
||||
+ error(220, "check_rxtree: %s does PARTIAL match limit: %s\n", fname_safe, limit_safe?limit_safe:"");
|
||||
if(S_ISDIR(perm) && get_seltree_node(tree,filename)==NULL){
|
||||
- error(220, "check_rxtree: creating new seltree node for '%s'\n", filename);
|
||||
+ error(220, "check_rxtree: creating new seltree node for '%s'\n", fname_safe);
|
||||
new_seltree_node(tree,filename,0,NULL);
|
||||
}
|
||||
+ free(fname_safe);
|
||||
+ free(limit_safe);
|
||||
return -1;
|
||||
} else {
|
||||
- error(220, "check_rxtree: %s does NOT match limit: %s\n", filename, conf->limit);
|
||||
+ char *fname_safe = stresc(filename);
|
||||
+ char *limit_safe = conf->limit?stresc(conf->limit):NULL;
|
||||
+ error(220, "check_rxtree: %s does NOT match limit: %s\n", fname_safe, limit_safe?limit_safe:"");
|
||||
+ free(fname_safe);
|
||||
+ free(limit_safe);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
pnode=get_seltree_node(tree,parentname);
|
||||
|
||||
*attr=0;
|
||||
retval=check_node_for_match(pnode,filename, perm, 0,attr);
|
||||
|
||||
free(parentname);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
db_line* get_file_attrs(char* filename,DB_ATTR_TYPE attr, struct AIDE_STAT_TYPE *fs)
|
||||
{
|
||||
db_line* line=NULL;
|
||||
time_t cur_time;
|
||||
|
||||
if(!(attr&DB_RDEV))
|
||||
fs->st_rdev=0;
|
||||
/*
|
||||
Get current time for future time notification.
|
||||
*/
|
||||
cur_time=time(NULL);
|
||||
|
||||
if (cur_time==(time_t)-1) {
|
||||
char* er=strerror(errno);
|
||||
if (er==NULL) {
|
||||
error(0,_("Can not get current time. strerror failed for %i\n"),errno);
|
||||
} else {
|
||||
error(0,_("Can not get current time with reason %s\n"),er);
|
||||
}
|
||||
} else {
|
||||
|
||||
if(fs->st_atime>cur_time){
|
||||
- error(CLOCK_SKEW,_("%s atime in future\n"),filename);
|
||||
+ {
|
||||
+ char *fname_safe = stresc(filename);
|
||||
+ error(CLOCK_SKEW,_("%s atime in future\n"),fname_safe);
|
||||
+ free(fname_safe);
|
||||
+ }
|
||||
}
|
||||
if(fs->st_mtime>cur_time){
|
||||
- error(CLOCK_SKEW,_("%s mtime in future\n"),filename);
|
||||
+ {
|
||||
+ char *fname_safe = stresc(filename);
|
||||
+ error(CLOCK_SKEW,_("%s mtime in future\n"),fname_safe);
|
||||
+ free(fname_safe);
|
||||
+ }
|
||||
}
|
||||
if(fs->st_ctime>cur_time){
|
||||
- error(CLOCK_SKEW,_("%s ctime in future\n"),filename);
|
||||
+ {
|
||||
+ char *fname_safe = stresc(filename);
|
||||
+ error(CLOCK_SKEW,_("%s ctime in future\n"),fname_safe);
|
||||
+ free(fname_safe);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Malloc if we have something to store..
|
||||
*/
|
||||
|
||||
line=(db_line*)malloc(sizeof(db_line));
|
||||
|
||||
memset(line,0,sizeof(db_line));
|
||||
|
||||
/*
|
||||
We want filename
|
||||
*/
|
||||
|
||||
line->attr=attr|DB_FILENAME;
|
||||
|
||||
/*
|
||||
Just copy some needed fields.
|
||||
*/
|
||||
|
||||
line->fullpath=filename;
|
||||
line->filename=&filename[conf->root_prefix_length];
|
||||
line->perm_o=fs->st_mode;
|
||||
line->size_o=fs->st_size;
|
||||
@@ -1198,51 +1223,55 @@ void populate_tree(seltree* tree)
|
||||
initdbwarningprinted=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(conf->action&DO_INIT) {
|
||||
write_tree(tree);
|
||||
}
|
||||
}
|
||||
|
||||
void hsymlnk(db_line* line) {
|
||||
|
||||
if((S_ISLNK(line->perm_o))){
|
||||
int len=0;
|
||||
#ifdef WITH_ACL
|
||||
if(conf->no_acl_on_symlinks!=1) {
|
||||
line->attr&=(~DB_ACL);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(conf->warn_dead_symlinks==1) {
|
||||
struct AIDE_STAT_TYPE fs;
|
||||
int sres;
|
||||
sres=AIDE_STAT_FUNC(line->fullpath,&fs);
|
||||
if (sres!=0 && sres!=EACCES) {
|
||||
- error(4,"Dead symlink detected at %s\n",line->fullpath);
|
||||
+ {
|
||||
+ char *fp_safe = stresc(line->fullpath);
|
||||
+ error(4,"Dead symlink detected at %s\n",fp_safe);
|
||||
+ free(fp_safe);
|
||||
+ }
|
||||
}
|
||||
if(!(line->attr&DB_RDEV))
|
||||
fs.st_rdev=0;
|
||||
}
|
||||
/*
|
||||
Is this valid??
|
||||
No, We should do this elsewhere.
|
||||
*/
|
||||
line->linkname=(char*)malloc(_POSIX_PATH_MAX+1);
|
||||
if(line->linkname==NULL){
|
||||
error(0,_("malloc failed in hsymlnk()\n"));
|
||||
abort();
|
||||
}
|
||||
|
||||
/*
|
||||
Remember to nullify the buffer, because man page says
|
||||
|
||||
readlink places the contents of the symbolic link path in
|
||||
the buffer buf, which has size bufsiz. readlink does not
|
||||
append a NUL character to buf. It will truncate the con-
|
||||
tents (to a length of bufsiz characters), in case the
|
||||
buffer is too small to hold all of the contents.
|
||||
|
||||
*/
|
||||
memset(line->linkname,0,_POSIX_PATH_MAX+1);
|
||||
diff --git a/src/util.c b/src/util.c
|
||||
index 21c75a2f176270f47f480c8143984e8a00ce8780..7e3da74a6acbf6e656b833591972be06fb1ae0f1 100644
|
||||
--- a/src/util.c
|
||||
+++ b/src/util.c
|
||||
@@ -82,101 +82,142 @@ url_t* parse_url(char* val)
|
||||
|
||||
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];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (u->type) {
|
||||
case url_file : {
|
||||
if(r[0]=='/'&&(r+1)[0]=='/'&&(r+2)[0]=='/'){
|
||||
u->value=strdup(r+2);
|
||||
break;
|
||||
}
|
||||
if(r[0]=='/'&&(r+1)[0]=='/'&&(r+2)[0]!='/'){
|
||||
char*hostname=(char*)malloc(sizeof(char)*MAXHOSTNAMELEN);
|
||||
char* t=r+2;
|
||||
r+=2;
|
||||
for(i=0;r[0]!='/'&&r[0]!='\0';r++,i++);
|
||||
if(r[0]=='\0'){
|
||||
- error(0,"Invalid file-URL,no path after hostname: file:%s\n",t);
|
||||
+ char *t_safe = stresc(t);
|
||||
+ error(0,"Invalid file-URL,no path after hostname: file:%s\n",t_safe);
|
||||
+ free(t_safe);
|
||||
free(u);
|
||||
free(val_copy);
|
||||
free(hostname);
|
||||
- return NULL;
|
||||
+ return NULL;
|
||||
}
|
||||
u->value=strdup(r);
|
||||
r[0]='\0';
|
||||
if(gethostname(hostname,MAXHOSTNAMELEN)==-1){
|
||||
strncpy(hostname,"localhost",MAXHOSTNAMELEN);
|
||||
}
|
||||
|
||||
if( (strcmp(t,"localhost")==0)||(strcmp(t,hostname)==0)){
|
||||
free(hostname);
|
||||
break;
|
||||
} else {
|
||||
- error(0,"Invalid file-URL, cannot use hostname other than localhost or %s: file:%s\n",hostname,u->value);
|
||||
+ char *value_safe = stresc(u->value);
|
||||
+ error(0,"Invalid file-URL, cannot use hostname other than localhost or %s: file:%s\n",hostname,value_safe);
|
||||
+ free(value_safe);
|
||||
free(u->value);
|
||||
free(u);
|
||||
free(val_copy);
|
||||
- free(hostname);
|
||||
- return NULL;
|
||||
+ free(hostname);
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
u->value=strdup(r);
|
||||
|
||||
break;
|
||||
}
|
||||
case url_https :
|
||||
case url_http :
|
||||
case url_ftp : {
|
||||
u->value=strdup(val);
|
||||
break;
|
||||
}
|
||||
case url_unknown : {
|
||||
error(0,"Unknown URL-type:%s\n",val_copy);
|
||||
break;
|
||||
}
|
||||
default : {
|
||||
u->value=strdup(r);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(val_copy);
|
||||
|
||||
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 = malloc(n);
|
||||
+ if (str == NULL) {
|
||||
+ error(0, "malloc: failed to allocate %d bytes of memory\n", n);
|
||||
+ exit(1);
|
||||
+ }
|
||||
+ 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)
|
||||
{
|
||||
for (; *s; s++)
|
||||
if (strchr (URL_UNSAFE,(int) *s)||!ISPRINT((int)*s))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Decodes the forms %xy in a URL to the character the hexadecimal
|
||||
code of which is xy. xy are hexadecimal digits from
|
||||
[0123456789ABCDEF] (case-insensitive). If x or y are not
|
||||
hex-digits or `%' precedes `\0', the sequence is inserted
|
||||
literally. */
|
||||
|
||||
void decode_string (char* s)
|
||||
{
|
||||
char *p = s;
|
||||
|
||||
for (; *s; s++, p++)
|
||||
{
|
||||
if (*s != '%')
|
||||
*p = *s;
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
Summary: Intrusion detection environment
|
||||
Name: aide
|
||||
Version: 0.16
|
||||
Release: 15%{?dist}.1
|
||||
Release: 15%{?dist}.2
|
||||
URL: http://sourceforge.net/projects/aide
|
||||
License: GPLv2+
|
||||
Source0: %{url}/files/aide/%{version}/%{name}-%{version}.tar.gz
|
||||
@ -42,6 +42,7 @@ Patch8: aide-0.16-CVE-2021-45417.patch
|
||||
|
||||
# CVE-2025-54389 aide: improper output neutralization enables bypassing
|
||||
Patch9: aide-0.16-CVE-2025-54389.patch
|
||||
Patch10: aide-0.16-CVE-2025-54389-part2.patch
|
||||
|
||||
%description
|
||||
AIDE (Advanced Intrusion Detection Environment) is a file integrity
|
||||
@ -87,7 +88,7 @@ mkdir -p -m0700 %{buildroot}%{_localstatedir}/lib/aide
|
||||
%dir %attr(0700,root,root) %{_localstatedir}/log/aide
|
||||
|
||||
%changelog
|
||||
* Thu Aug 21 2025 Attila Lakatos <alakatos@redhat.com> - 0.16.15.1
|
||||
* Thu Aug 21 2025 Attila Lakatos <alakatos@redhat.com> - 0.16.15.2
|
||||
- CVE-2025-54389 aide: improper output neutralization enables bypassing
|
||||
resolves: RHEL-109907
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user