File logrotate-shred-CVE-2011-1154.patch of Package logrotate.361

Index: logrotate.c
===================================================================
--- logrotate.c.orig
+++ logrotate.c
@@ -71,7 +71,7 @@ const char * compress_cmd_list[][2] = {
 
 time_t nowSecs = 0;
 
-static int shred_file(char *filename, struct logInfo *log);
+static int shred_file(int fd, char *filename, struct logInfo *log);
 
 static int globerr(const char *pathname, int theerr)
 {
@@ -233,58 +233,78 @@ int createOutputFile(char *fileName, int
     return fd;
 }
 
-#define SHRED_CALL "shred -u "
-#define SHRED_COUNT_FLAG "-n "
 #define DIGITS 10
+
 /* unlink, but try to call shred from GNU fileutils */
-static int shred_file(char *filename, struct logInfo *log)
+static int shred_file(int fd, char *filename, struct logInfo *log)
 {
-	int len, ret;
-	char *cmd;
 	char count[DIGITS];    /*  that's a lot of shredding :)  */
+	const char **fullCommand;
+	int id = 0;
+	int status;
 
 	if (!(log->flags & LOG_FLAG_SHRED)) {
 		return unlink(filename);
 	}
 
-	len = strlen(filename) + strlen(SHRED_CALL);
-	len += strlen(SHRED_COUNT_FLAG) + DIGITS;
-	cmd = malloc(len);
+	message(MESS_DEBUG, "Using shred to remove the file %s\n", filename);
 
-	if (!cmd) {
-		message(MESS_ERROR, "malloc error while shredding");
-		return unlink(filename);
+	if (log->shred_cycles != 0) {
+		fullCommand = alloca(sizeof(*fullCommand) * 6);
+	}
+	else {
+		fullCommand = alloca(sizeof(*fullCommand) * 4);
 	}
-	strcpy(cmd, SHRED_CALL);
+	fullCommand[id++] = "shred";
+	fullCommand[id++] = "-u";
+
 	if (log->shred_cycles != 0) {
-		strcat(cmd, SHRED_COUNT_FLAG);
+		fullCommand[id++] = "-n";
 		snprintf(count, DIGITS - 1, "%d", log->shred_cycles);
-		strcat(count, " ");
-		strcat(cmd, count);
+		fullCommand[id++] = count;
 	}
-	strcat(cmd, filename);
-	ret = system(cmd);
-	free(cmd);
-	if (ret != 0) {
-		message(MESS_ERROR, "Failed to shred %s\n, trying unlink", filename);
-		if (ret != -1) {
-			message(MESS_NORMAL, "Shred returned %d\n", ret);
+	fullCommand[id++] = "-";
+	fullCommand[id++] = NULL;
+
+	if (!fork()) {
+		dup2(fd, 1);
+		close(fd);
+
+		execvp(fullCommand[0], (void *) fullCommand);
+		exit(1);
 		}
+	
+	wait(&status);
+
+	if (!WIFEXITED(status) || WEXITSTATUS(status)) {
+		message(MESS_ERROR, "Failed to shred %s\n, trying unlink", filename);
 		return unlink(filename);
-	} else {
-		return ret;
 	}
+
+	/* We have to unlink it after shred anyway,
+	 * because it doesn't remove the file itself */
+	return unlink(filename);
 }
 
 static int removeLogFile(char *name, struct logInfo *log)
 {
+	int fd;
     message(MESS_DEBUG, "removing old log %s\n", name);
 
-    if (!debug && shred_file(name, log)) {
+	if ((fd = open(name, O_RDWR)) < 0) {
+		message(MESS_ERROR, "error opening %s: %s\n",
+			name, strerror(errno));
+		return 1;
+	}
+
+	if (!debug && shred_file(fd, name, log)) {
 	message(MESS_ERROR, "Failed to remove old log %s: %s\n",
 		name, strerror(errno));
+		close(fd);
 	return 1;
     }
+
+	close(fd);
     return 0;
 }
 
@@ -312,7 +332,7 @@ static int compressLogFile(char *name, s
     compressedName = alloca(strlen(name) + strlen(log->compress_ext) + 2);
     sprintf(compressedName, "%s%s", name, log->compress_ext);
 
-    if ((inFile = open(name, O_RDONLY)) < 0) {
+    if ((inFile = open(name, O_RDWR)) < 0) {
 	message(MESS_ERROR, "unable to open %s for compression\n", name);
 	return 1;
     }
@@ -334,7 +354,6 @@ static int compressLogFile(char *name, s
 	exit(1);
     }
 
-    close(inFile);
     close(outFile);
 
     wait(&status);
@@ -350,7 +369,8 @@ static int compressLogFile(char *name, s
     /* If we can't change atime/mtime, it's not a disaster.
        It might possibly fail under SELinux. */
 
-    shred_file(name, log);
+    shred_file(inFile, name, log);
+	close(inFile);
 
     return 0;
 }