diff mbox series

[v2] iproute2: prevent memory leak

Message ID 20231115023703.15417-1-heminhong@kylinos.cn (mailing list archive)
State Superseded
Delegated to: Stephen Hemminger
Headers show
Series [v2] iproute2: prevent memory leak | expand

Checks

Context Check Description
netdev/tree_selection success Not a local patch

Commit Message

Minhong He Nov. 15, 2023, 2:37 a.m. UTC
When the return value of rtnl_talk() is less than 0, 'answer' does not
need to release. When the return value of rtnl_talk() is greater than
or equal to 0, 'answer' will be allocated, if subsequent processing fails,
the memory should be free, otherwise it will cause memory leak.

Signed-off-by: heminhong <heminhong@kylinos.cn>
---
 ip/link_gre.c    | 2 ++
 ip/link_gre6.c   | 2 ++
 ip/link_ip6tnl.c | 2 ++
 ip/link_iptnl.c  | 2 ++
 ip/link_vti.c    | 2 ++
 ip/link_vti6.c   | 2 ++
 6 files changed, 12 insertions(+)

Comments

Florian Westphal Nov. 15, 2023, 3:32 a.m. UTC | #1
heminhong <heminhong@kylinos.cn> wrote:
> When the return value of rtnl_talk() is less than 0, 'answer' does not
> need to release. When the return value of rtnl_talk() is greater than
> or equal to 0, 'answer' will be allocated, if subsequent processing fails,
> the memory should be free, otherwise it will cause memory leak.

I don't understand this patch.  Care to elaborate where a memory leak is?

rtnl_talk -> __rtnl_talk -> __rtnl_talk_iov

 998 static int __rtnl_talk_iov(struct rtnl_handle *rtnl, struct iovec *iov,
 999                            size_t iovlen, struct nlmsghdr **answer,
1000                            bool show_rtnl_err, nl_ext_ack_fn_t errfn)
[..]
1102                                 if (answer)
1103                                         *answer = (struct nlmsghdr *)buf;
1104                                 else
1105                                         free(buf);
1106                                 return 0;
1107                         }
1108
1109                         if (answer) {
1110                                 *answer = (struct nlmsghdr *)buf;
1111                                 return 0;
1112                         }

I see no other spots where 'answer' is set, i.e. assignment ONLY on
'return 0'.

> Signed-off-by: heminhong <heminhong@kylinos.cn>
> ---
>  ip/link_gre.c    | 2 ++
>  ip/link_gre6.c   | 2 ++
>  ip/link_ip6tnl.c | 2 ++
>  ip/link_iptnl.c  | 2 ++
>  ip/link_vti.c    | 2 ++
>  ip/link_vti6.c   | 2 ++
>  6 files changed, 12 insertions(+)
> 
> diff --git a/ip/link_gre.c b/ip/link_gre.c
> index 74a5b5e9..b86ec22d 100644
> --- a/ip/link_gre.c
> +++ b/ip/link_gre.c
> @@ -111,6 +111,8 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
>  
>  		if (rtnl_talk(&rth, &req.n, &answer) < 0) {
>  get_failed:
> +			if (answer)
> +				free(answer);

This if() is not needed.  free(NULL) is fine.  But in this case,
'answer' can contain stack-garbage, as this variable isn't initialised
to NULL.

Moreover, the placement would need to be ABOVE the label, not below.

But, see above, I don't see a 'answer' related memleak.
Stephen Hemminger Nov. 15, 2023, 3:33 a.m. UTC | #2
On Wed, 15 Nov 2023 10:37:03 +0800
heminhong <heminhong@kylinos.cn> wrote:

> When the return value of rtnl_talk() is less than 0, 'answer' does not
> need to release. When the return value of rtnl_talk() is greater than
> or equal to 0, 'answer' will be allocated, if subsequent processing fails,
> the memory should be free, otherwise it will cause memory leak.
> 
> Signed-off-by: heminhong <heminhong@kylinos.cn>

No null check needed before free().

   free()
       The  free()  function  frees  the memory space pointed to by ptr, which
       must have been returned by a previous call to malloc() or related func‐
       tions.  Otherwise, or if ptr has already been freed, undefined behavior
       occurs.  If ptr is NULL, no operation is performed.
diff mbox series

Patch

diff --git a/ip/link_gre.c b/ip/link_gre.c
index 74a5b5e9..b86ec22d 100644
--- a/ip/link_gre.c
+++ b/ip/link_gre.c
@@ -111,6 +111,8 @@  static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
 
 		if (rtnl_talk(&rth, &req.n, &answer) < 0) {
 get_failed:
+			if (answer)
+				free(answer);
 			fprintf(stderr,
 				"Failed to get existing tunnel info.\n");
 			return -1;
diff --git a/ip/link_gre6.c b/ip/link_gre6.c
index b03bd65a..72ce148a 100644
--- a/ip/link_gre6.c
+++ b/ip/link_gre6.c
@@ -113,6 +113,8 @@  static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
 
 		if (rtnl_talk(&rth, &req.n, &answer) < 0) {
 get_failed:
+			if (answer)
+				free(answer);
 			fprintf(stderr,
 				"Failed to get existing tunnel info.\n");
 			return -1;
diff --git a/ip/link_ip6tnl.c b/ip/link_ip6tnl.c
index b27d696f..cffa8345 100644
--- a/ip/link_ip6tnl.c
+++ b/ip/link_ip6tnl.c
@@ -99,6 +99,8 @@  static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv,
 
 		if (rtnl_talk(&rth, &req.n, &answer) < 0) {
 get_failed:
+			if (answer)
+				free(answer);
 			fprintf(stderr,
 				"Failed to get existing tunnel info.\n");
 			return -1;
diff --git a/ip/link_iptnl.c b/ip/link_iptnl.c
index 1315aebe..b4ffed25 100644
--- a/ip/link_iptnl.c
+++ b/ip/link_iptnl.c
@@ -103,6 +103,8 @@  static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv,
 
 		if (rtnl_talk(&rth, &req.n, &answer) < 0) {
 get_failed:
+			if (answer)
+				free(answer);
 			fprintf(stderr,
 				"Failed to get existing tunnel info.\n");
 			return -1;
diff --git a/ip/link_vti.c b/ip/link_vti.c
index 50943254..3e4fd95e 100644
--- a/ip/link_vti.c
+++ b/ip/link_vti.c
@@ -67,6 +67,8 @@  static int vti_parse_opt(struct link_util *lu, int argc, char **argv,
 
 		if (rtnl_talk(&rth, &req.n, &answer) < 0) {
 get_failed:
+			if (answer)
+				free(answer);
 			fprintf(stderr,
 				"Failed to get existing tunnel info.\n");
 			return -1;
diff --git a/ip/link_vti6.c b/ip/link_vti6.c
index 5764221e..e70f5612 100644
--- a/ip/link_vti6.c
+++ b/ip/link_vti6.c
@@ -69,6 +69,8 @@  static int vti6_parse_opt(struct link_util *lu, int argc, char **argv,
 
 		if (rtnl_talk(&rth, &req.n, &answer) < 0) {
 get_failed:
+			if (answer)
+				free(answer);
 			fprintf(stderr,
 				"Failed to get existing tunnel info.\n");
 			return -1;