diff mbox series

[1/7] trace-cmd lib: Close FDs in create_buffer_recorder_fd2 it allocation fails

Message ID 20241205144439.127564-2-jmarchan@redhat.com (mailing list archive)
State New
Headers show
Series trace-cmd: Fix misc issues uncoverd by static analysis | expand

Commit Message

Jerome Marchand Dec. 5, 2024, 2:44 p.m. UTC
The behavior of create_buffer_recorder_fd2() wrt closing the file
descriptors is inconsistent. They aren't close if the function fails
early when allocating recorder, but they are closed in
tracecmd_free_recorder() if it fails later.

This cause use-after-free access when the caller tries to close the
FDs afterwards.

Always close the FDs in create_buffer_recorder_fd2() when it fails and
stop the caller to close them themselves.

Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
---
 lib/trace-cmd/trace-recorder.c | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

Comments

Steven Rostedt Dec. 18, 2024, 10:37 p.m. UTC | #1
On Thu,  5 Dec 2024 15:44:33 +0100
"Jerome Marchand" <jmarchan@redhat.com> wrote:

> The behavior of create_buffer_recorder_fd2() wrt closing the file
> descriptors is inconsistent. They aren't close if the function fails
> early when allocating recorder, but they are closed in
> tracecmd_free_recorder() if it fails later.
> 
> This cause use-after-free access when the caller tries to close the
> FDs afterwards.
> 
> Always close the FDs in create_buffer_recorder_fd2() when it fails and
> stop the caller to close them themselves.
> 
> Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
> ---
>  lib/trace-cmd/trace-recorder.c | 15 +++++++--------
>  1 file changed, 7 insertions(+), 8 deletions(-)
> 
> diff --git a/lib/trace-cmd/trace-recorder.c b/lib/trace-cmd/trace-recorder.c
> index 44f245d5..0413e529 100644
> --- a/lib/trace-cmd/trace-recorder.c
> +++ b/lib/trace-cmd/trace-recorder.c
> @@ -114,8 +114,12 @@ create_buffer_recorder_fd2(int fd, int fd2, int cpu, unsigned flags,
>  	bool nonblock = false;
>  
>  	recorder = malloc(sizeof(*recorder));
> -	if (!recorder)
> +	if (!recorder) {
> +		close(fd);
> +		if (fd2 != -1)
> +			close(fd2);
>  		return NULL;
> +	}

No. If a function does not open a file descriptor, it should not close it.
It's bad programming style if a called function closes a file descriptor on
error that was passed to it. That can easily introduce new bugs.

The fix is to not have it close a file descriptor at all!

-- Steve

diff --git a/lib/trace-cmd/trace-recorder.c b/lib/trace-cmd/trace-recorder.c
index 0413e5293766..df971e4adf97 100644
--- a/lib/trace-cmd/trace-recorder.c
+++ b/lib/trace-cmd/trace-recorder.c
@@ -69,7 +69,7 @@ void tracecmd_free_recorder(struct tracecmd_recorder *recorder)
 	if (!recorder)
 		return;
 
-	if (recorder->max) {
+	if (recorder->max && recorder->fd >= 0) {
 		/* Need to put everything into fd1 */
 		if (recorder->fd == recorder->fd1) {
 			int ret;
@@ -140,14 +140,12 @@ create_buffer_recorder_fd2(int fd, int fd2, int cpu, unsigned flags,
 	recorder->count = 0;
 	recorder->pages = 0;
 
-	/* fd always points to what to write to */
-	recorder->fd = fd;
-	recorder->fd1 = fd;
-	recorder->fd2 = fd2;
-
 	if (recorder->flags & TRACECMD_RECORD_POLL)
 		nonblock = true;
 
+	/* In case of error */
+	recorder->fd = -1;
+
 	if (tfd >= 0)
 		recorder->tcpu = tracefs_cpu_alloc_fd(tfd, recorder->page_size, nonblock);
 	else
@@ -156,6 +154,11 @@ create_buffer_recorder_fd2(int fd, int fd2, int cpu, unsigned flags,
 	if (!recorder->tcpu)
 		goto out_free;
 
+	/* fd always points to what to write to */
+	recorder->fd = fd;
+	recorder->fd1 = fd;
+	recorder->fd2 = fd2;
+
 	recorder->subbuf_size = tracefs_cpu_read_size(recorder->tcpu);
 	return recorder;
Steven Rostedt Dec. 18, 2024, 10:43 p.m. UTC | #2
On Wed, 18 Dec 2024 17:37:31 -0500
Steven Rostedt <rostedt@goodmis.org> wrote:

> No. If a function does not open a file descriptor, it should not close it.
> It's bad programming style if a called function closes a file descriptor on
> error that was passed to it. That can easily introduce new bugs.
> 
> The fix is to not have it close a file descriptor at all!

And this means all the callers should close their fd if the recorder fails.
It should have never done that in the first place. :-/

Oh well, that was written over 10 years ago ;-)

-- Steve
diff mbox series

Patch

diff --git a/lib/trace-cmd/trace-recorder.c b/lib/trace-cmd/trace-recorder.c
index 44f245d5..0413e529 100644
--- a/lib/trace-cmd/trace-recorder.c
+++ b/lib/trace-cmd/trace-recorder.c
@@ -114,8 +114,12 @@  create_buffer_recorder_fd2(int fd, int fd2, int cpu, unsigned flags,
 	bool nonblock = false;
 
 	recorder = malloc(sizeof(*recorder));
-	if (!recorder)
+	if (!recorder) {
+		close(fd);
+		if (fd2 != -1)
+			close(fd2);
 		return NULL;
+	}
 
 	recorder->flags = flags;
 
@@ -204,12 +208,8 @@  __tracecmd_create_buffer_recorder(const char *file, int cpu, unsigned flags,
 	}
 
 	recorder = create_buffer_recorder_fd2(fd, fd2, cpu, flags, instance, maxkb, tfd);
-	if (!recorder) {
-		close(fd);
+	if (!recorder)
 		unlink(file);
-		if (fd2 != -1)
-			close(fd2);
-	}
 
 	if (fd2 != -1) {
 		/* Unlink file2, we need to add everything to file at the end */
@@ -257,10 +257,9 @@  tracecmd_create_buffer_recorder_maxkb(const char *file, int cpu, unsigned flags,
 	free(file2);
 
 	return recorder;
- err2:
-	close(fd2);
  err:
 	close(fd);
+ err2:
 	unlink(file);
 	goto out;
 }