Blob Blame History Raw
From 266d945d9c6432fc5746fa46e3e3ace2518600db Mon Sep 17 00:00:00 2001
From: Ivan Vecera <ivecera@redhat.com>
Date: Fri, 18 Mar 2016 12:50:43 +0100
Subject: [PATCH] ethtool.c: fix memory leaks

Memory allocated at several places is not appropriately freed.

Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
 ethtool.c | 60 +++++++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 45 insertions(+), 15 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index 0cd0d4f..ca0bf28 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -2065,10 +2065,14 @@ static int do_gfeatures(struct cmd_context *ctx)
 	features = get_features(ctx, defs);
 	if (!features) {
 		fprintf(stdout, "no feature info available\n");
+		free(defs);
 		return 1;
 	}
 
 	dump_features(defs, features, NULL);
+
+	free(features);
+	free(defs);
 	return 0;
 }
 
@@ -2078,11 +2082,11 @@ static int do_sfeatures(struct cmd_context *ctx)
 	int any_changed = 0, any_mismatch = 0;
 	u32 off_flags_wanted = 0;
 	u32 off_flags_mask = 0;
-	struct ethtool_sfeatures *efeatures;
+	struct ethtool_sfeatures *efeatures = NULL;
 	struct cmdline_info *cmdline_features;
-	struct feature_state *old_state, *new_state;
+	struct feature_state *old_state = NULL, *new_state = NULL;
 	struct ethtool_value eval;
-	int err;
+	int err, retval = 1;
 	int i, j;
 
 	defs = get_feature_defs(ctx);
@@ -2096,7 +2100,7 @@ static int do_sfeatures(struct cmd_context *ctx)
 				   sizeof(efeatures->features[0]));
 		if (!efeatures) {
 			perror("Cannot parse arguments");
-			return 1;
+			goto finish;
 		}
 		efeatures->cmd = ETHTOOL_SFEATURES;
 		efeatures->size = FEATURE_BITS_TO_BLOCKS(defs->n_features);
@@ -2114,7 +2118,7 @@ static int do_sfeatures(struct cmd_context *ctx)
 				  sizeof(cmdline_features[0]));
 	if (!cmdline_features) {
 		perror("Cannot parse arguments");
-		return 1;
+		goto finish;
 	}
 	for (i = 0; i < ARRAY_SIZE(off_flag_def); i++)
 		flag_to_cmdline_info(off_flag_def[i].short_name,
@@ -2133,12 +2137,13 @@ static int do_sfeatures(struct cmd_context *ctx)
 
 	if (!any_changed) {
 		fprintf(stdout, "no features changed\n");
-		return 0;
+		retval = 0;
+		goto finish;
 	}
 
 	old_state = get_features(ctx, defs);
 	if (!old_state)
-		return 1;
+		goto finish;
 
 	if (efeatures) {
 		/* For each offload that the user specified, update any
@@ -2182,7 +2187,7 @@ static int do_sfeatures(struct cmd_context *ctx)
 		err = send_ioctl(ctx, efeatures);
 		if (err < 0) {
 			perror("Cannot set device feature settings");
-			return 1;
+			goto finish;
 		}
 	} else {
 		for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
@@ -2197,7 +2202,7 @@ static int do_sfeatures(struct cmd_context *ctx)
 					fprintf(stderr,
 						"Cannot set device %s settings: %m\n",
 						off_flag_def[i].long_name);
-					return 1;
+					goto finish;
 				}
 			}
 		}
@@ -2211,7 +2216,8 @@ static int do_sfeatures(struct cmd_context *ctx)
 			err = send_ioctl(ctx, &eval);
 			if (err) {
 				perror("Cannot set device flag settings");
-				return 92;
+				retval = 92;
+				goto finish;
 			}
 		}
 	}
@@ -2219,7 +2225,7 @@ static int do_sfeatures(struct cmd_context *ctx)
 	/* Compare new state with requested state */
 	new_state = get_features(ctx, defs);
 	if (!new_state)
-		return 1;
+		goto finish;
 	any_changed = new_state->off_flags != old_state->off_flags;
 	any_mismatch = (new_state->off_flags !=
 			((old_state->off_flags & ~off_flags_mask) |
@@ -2238,13 +2244,19 @@ static int do_sfeatures(struct cmd_context *ctx)
 		if (!any_changed) {
 			fprintf(stderr,
 				"Could not change any device features\n");
-			return 1;
+			goto finish;
 		}
 		printf("Actual changes:\n");
 		dump_features(defs, new_state, old_state);
 	}
 
-	return 0;
+	retval = 0;
+finish:
+	free(new_state);
+	free(old_state);
+	free(efeatures);
+	free(defs);
+	return retval;
 }
 
 static int do_gset(struct cmd_context *ctx)
@@ -2705,8 +2717,18 @@ static int do_gregs(struct cmd_context *ctx)
 			return 75;
 		}
 
-		regs = realloc(regs, sizeof(*regs) + st.st_size);
-		regs->len = st.st_size;
+		if (regs->len != st.st_size) {
+			struct ethtool_regs *new_regs;
+			new_regs = realloc(regs, sizeof(*regs) + st.st_size);
+			if (!new_regs) {
+				perror("Cannot allocate memory for register "
+				       "dump");
+				free(regs);
+				return 73;
+			}
+			regs = new_regs;
+			regs->len = st.st_size;
+		}
 		nread = fread(regs->data, regs->len, 1, f);
 		fclose(f);
 		if (nread != 1) {
@@ -3775,6 +3797,7 @@ static int do_gprivflags(struct cmd_context *ctx)
 	}
 	if (strings->len == 0) {
 		fprintf(stderr, "No private flags defined\n");
+		free(strings);
 		return 1;
 	}
 	if (strings->len > 32) {
@@ -3786,6 +3809,7 @@ static int do_gprivflags(struct cmd_context *ctx)
 	flags.cmd = ETHTOOL_GPFLAGS;
 	if (send_ioctl(ctx, &flags)) {
 		perror("Cannot get private flags");
+		free(strings);
 		return 1;
 	}
 
@@ -3804,6 +3828,7 @@ static int do_gprivflags(struct cmd_context *ctx)
 		       (const char *)strings->data + i * ETH_GSTRING_LEN,
 		       (flags.data & (1U << i)) ? "on" : "off");
 
+	free(strings);
 	return 0;
 }
 
@@ -3825,6 +3850,7 @@ static int do_sprivflags(struct cmd_context *ctx)
 	}
 	if (strings->len == 0) {
 		fprintf(stderr, "No private flags defined\n");
+		free(strings);
 		return 1;
 	}
 	if (strings->len > 32) {
@@ -3836,6 +3862,7 @@ static int do_sprivflags(struct cmd_context *ctx)
 	cmdline = calloc(strings->len, sizeof(*cmdline));
 	if (!cmdline) {
 		perror("Cannot parse arguments");
+		free(strings);
 		return 1;
 	}
 	for (i = 0; i < strings->len; i++) {
@@ -3852,6 +3879,7 @@ static int do_sprivflags(struct cmd_context *ctx)
 	flags.cmd = ETHTOOL_GPFLAGS;
 	if (send_ioctl(ctx, &flags)) {
 		perror("Cannot get private flags");
+		free(strings);
 		return 1;
 	}
 
@@ -3859,9 +3887,11 @@ static int do_sprivflags(struct cmd_context *ctx)
 	flags.data = (flags.data & ~seen_flags) | wanted_flags;
 	if (send_ioctl(ctx, &flags)) {
 		perror("Cannot set private flags");
+		free(strings);
 		return 1;
 	}
 
+	free(strings);
 	return 0;
 }
 
-- 
2.7.3