File toctou-race-allows-arbitrary-file-deletion.patch of Package fdupes.33850
From 85680897148f1ac33b55418e00334116e419717f Mon Sep 17 00:00:00 2001
From: Adrian Lopez <adrianlopezroche@gmail.com>
Date: Tue, 16 Aug 2022 14:39:18 -0400
Subject: [PATCH] Call stat() before deleting any file to ensure it's still the
same file.
---
Makefile.am | 4 ++++
fdupes.c | 11 +++++++----
ncurses-commands.c | 3 ++-
removeifnotchanged.c | 41 +++++++++++++++++++++++++++++++++++++++++
removeifnotchanged.h | 8 ++++++++
5 files changed, 62 insertions(+), 5 deletions(-)
create mode 100644 removeifnotchanged.c
create mode 100644 removeifnotchanged.h
Index: fdupes-1.6.1/fdupes.c
===================================================================
--- fdupes-1.6.1.orig/fdupes.c 2016-08-21 04:54:46.000000000 +0000
+++ fdupes-1.6.1/fdupes.c 2024-04-25 09:13:19.407546801 +0000
@@ -109,6 +109,42 @@ typedef struct _filetree {
struct _filetree *right;
} filetree_t;
+int removeifnotchanged(const file_t *file, char **errorstring)
+{
+ int result;
+ struct stat st;
+
+ static char *filechanged = "File contents changed during processing";
+ static char *unknownerror = "Unknown error";
+
+ stat(file->d_name, &st);
+
+ if (file->device != st.st_dev ||
+ file->inode != st.st_ino ||
+ file->mtime != st.st_mtime ||
+ file->size != st.st_size)
+ {
+ if (errorstring != 0)
+ *errorstring = filechanged;
+
+ return -2;
+ }
+ else
+ {
+ result = remove(file->d_name);
+
+ if (result != 0 && errorstring != 0)
+ {
+ *errorstring = strerror(errno);
+
+ if (*errorstring == 0)
+ *errorstring = unknownerror;
+ }
+
+ return result;
+ }
+}
+
void errormsg(char *message, ...)
{
va_list ap;
@@ -773,6 +809,7 @@ void deletefiles(file_t *files, int prom
int max = 0;
int x;
int i;
+ char *errorstring;
curfile = files;
@@ -884,11 +921,11 @@ void deletefiles(file_t *files, int prom
if (preserve[x])
printf(" [+] %s\n", dupelist[x]->d_name);
else {
- if (remove(dupelist[x]->d_name) == 0) {
+ if (removeifnotchanged(dupelist[x], &errorstring) == 0) {
printf(" [-] %s\n", dupelist[x]->d_name);
} else {
printf(" [!] %s ", dupelist[x]->d_name);
- printf("-- unable to delete file!\n");
+ printf("-- unable to delete file: %s!\n", errorstring);
}
}
}
@@ -977,6 +1014,7 @@ void deletesuccessor(file_t **existing,
{
file_t *to_keep;
file_t *to_delete;
+ char *errorstring;
if (comparef(duplicate, *existing) >= 0)
{
@@ -994,11 +1032,11 @@ void deletesuccessor(file_t **existing,
if (!ISFLAG(flags, F_HIDEPROGRESS)) fprintf(stderr, "\r%40s\r", " ");
printf(" [+] %s\n", to_keep->d_name);
- if (remove(to_delete->d_name) == 0) {
+ if (removeifnotchanged(to_delete, &errorstring) == 0) {
printf(" [-] %s\n", to_delete->d_name);
} else {
printf(" [!] %s ", to_delete->d_name);
- printf("-- unable to delete file!\n");
+ printf("-- unable to delete file: %s!\n", errorstring);
}
printf("\n");