Skip to contentSkip to conversation

kernel/taskstats.c: fix bogus nlmsg_free()

PATCH In review Adrian Bunk 2 participants 4 messages Oct 24, 2007 – Oct 26, 2007 Taskstats statistics interface

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 kernel/taskstats.c: fix bogus nlmsg_free()

We'd better not nlmsg_free on a pointer containing an undefined value (and without having anything allocated)...

Spotted by the Coverity checker.

---

 kernel/taskstats.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
kernel/taskstats.c renamed from kernel/taskstats.c.old +6 -6
@@ -383,67 +383,67 @@
 
 static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
 {
 	int rc = 0;
 	struct sk_buff *rep_skb;
 	struct cgroupstats *stats;
 	struct nlattr *na;
 	size_t size;
 	u32 fd;
 	struct file *file;
 	int fput_needed;
 
 	na = info->attrs[CGROUPSTATS_CMD_ATTR_FD];
 	if (!na)
 		return -EINVAL;
 
 	fd = nla_get_u32(info->attrs[CGROUPSTATS_CMD_ATTR_FD]);
 	file = fget_light(fd, &fput_needed);
 	if (file) {
 		size = nla_total_size(sizeof(struct cgroupstats));
 
 		rc = prepare_reply(info, CGROUPSTATS_CMD_NEW, &rep_skb,
 					size);
 		if (rc < 0)
-			goto err;
+			return rc;
 
 		na = nla_reserve(rep_skb, CGROUPSTATS_TYPE_CGROUP_STATS,
 					sizeof(struct cgroupstats));
 		stats = nla_data(na);
 		memset(stats, 0, sizeof(*stats));
 
 		rc = cgroupstats_build(stats, file->f_dentry);
+
+		fput_light(file, fput_needed);
+
 		if (rc < 0)
 			goto err;
 
-		fput_light(file, fput_needed);
 		return send_reply(rep_skb, info->snd_pid);
+err:
+		nlmsg_free(rep_skb);
 	}
 
-err:
-	if (file)
-		fput_light(file, fput_needed);
-	nlmsg_free(rep_skb);
 	return rc;
 }
 
 static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
 {
 	int rc = 0;
 	struct sk_buff *rep_skb;
 	struct taskstats *stats;
 	size_t size;
 	cpumask_t mask;
 
 	rc = parse(info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK], &mask);
 	if (rc < 0)
 		return rc;
 	if (rc == 0)
 		return add_del_listener(info->snd_pid, &mask, REGISTER);
 
 	rc = parse(info->attrs[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK], &mask);
 	if (rc < 0)
 		return rc;
 	if (rc == 0)
 		return add_del_listener(info->snd_pid, &mask, DEREGISTER);
 
 	/*
#1 lore raw
Quoted 32 lines · Adrian Bunk

We'd better not nlmsg_free on a pointer containing an undefined value (and without having anything allocated)...

Spotted by the Coverity checker.

---

 kernel/taskstats.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
kernel/taskstats.c renamed from kernel/taskstats.c.old +0 -0
@@ -383,67 +383,67 @@
 
 static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
 {
 	int rc = 0;
 	struct sk_buff *rep_skb;
 	struct cgroupstats *stats;
 	struct nlattr *na;
 	size_t size;
 	u32 fd;
 	struct file *file;
 	int fput_needed;
 
 	na = info->attrs[CGROUPSTATS_CMD_ATTR_FD];
 	if (!na)
 		return -EINVAL;
 
 	fd = nla_get_u32(info->attrs[CGROUPSTATS_CMD_ATTR_FD]);

kernel/taskstats.c line 408

Quoted 10 lines
kernel/taskstats.c renamed from kernel/taskstats.c.old +1 -1
 	file = fget_light(fd, &fput_needed);
 	if (file) {
 		size = nla_total_size(sizeof(struct cgroupstats));
 
 		rc = prepare_reply(info, CGROUPSTATS_CMD_NEW, &rep_skb,
 					size);
 		if (rc < 0)
-			goto err;
+			return rc;
 

We miss a fput_light() here

kernel/taskstats.c line 417

Quoted 9 lines
kernel/taskstats.c renamed from kernel/taskstats.c.old +3 -0
 		na = nla_reserve(rep_skb, CGROUPSTATS_TYPE_CGROUP_STATS,
 					sizeof(struct cgroupstats));
 		stats = nla_data(na);
 		memset(stats, 0, sizeof(*stats));
 
 		rc = cgroupstats_build(stats, file->f_dentry);
+
+		fput_light(file, fput_needed);
+

I don't understand this movement, it makes code reading a bit odd too. rc is the result, but we check the result after fput_light?

Quoted 15 lines
kernel/taskstats.c renamed from kernel/taskstats.c.old +2 -5
 		if (rc < 0)
 			goto err;
 
-		fput_light(file, fput_needed);
 		return send_reply(rep_skb, info->snd_pid);
+err:
+		nlmsg_free(rep_skb);
 	}
 
-err:
-	if (file)
-		fput_light(file, fput_needed);
-	nlmsg_free(rep_skb);
 	return rc;
 }
Signature · 4 lines
	Warm Regards,
	Balbir Singh
	Linux Technology Center
	IBM, ISTL
#2 lore raw

PATCH 1/1 kernel/taskstats.c: fix bogus nlmsg_free()

Quoted 16 lines · Balbir Singh
Quoted 14 lines · Adrian Bunk

We'd better not nlmsg_free on a pointer containing an undefined value (and without having anything allocated)...

Spotted by the Coverity checker.

---

 kernel/taskstats.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
kernel/taskstats.c renamed from kernel/taskstats.c.old +0 -0

...

Quoted 6 lines

kernel/taskstats.c

Quoted 4 lines
kernel/taskstats.c renamed from kernel/taskstats.c.old +1 -1
 		if (rc < 0)
-			goto err;
+			return rc;

We miss a fput_light() here

Sorry, my fault.

Quoted 5 lines
Quoted 5 lines
kernel/taskstats.c renamed from kernel/taskstats.c.old +0 -0
 		na = nla_reserve(rep_skb, CGROUPSTATS_TYPE_CGROUP_STATS,
 					sizeof(struct cgroupstats));
 		stats = nla_data(na);
 		memset(stats, 0, sizeof(*stats));
Quoted 8 lines

kernel/taskstats.c

Quoted 4 lines
kernel/taskstats.c renamed from kernel/taskstats.c.old +3 -0
 		rc = cgroupstats_build(stats, file->f_dentry);
+
+		fput_light(file, fput_needed);
+

I don't understand this movement, it makes code reading a bit odd too. rc is the result, but we check the result after fput_light?
...

I considered it more odd to read

                rc = cgroupstats_build(stats, file->f_dentry);
                if (rc < 0)
                        goto err;

                fput_light(file, fput_needed);
                return send_reply(rep_skb, info->snd_pid);
err:
                fput_light(file, fput_needed);
		nlmsg_free(rep_skb);

But that's just personal taste.

Anyway, duplicating the same fput_light() call two or three times isn't nice.

Originally I had the bigger patch below and considered it too big for only this fix, but now I think it might be appropriate.

If you ignore whitespace when diff'ing, then all it does is:

<-- snip -->

@@ -398,7 +398,9 @@ static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info)

fd = nla_get_u32(info->attrs[CGROUPSTATS_CMD_ATTR_FD]); file = fget_light(fd, &fput_needed);
- if (file) {
+ if (!file)
+ return 0;
+
size = nla_total_size(sizeof(struct cgroupstats));

rc = prepare_reply(info, CGROUPSTATS_CMD_NEW, &rep_skb,
@@ -412,17 +414,15 @@ static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
memset(stats, 0, sizeof(*stats));

rc = cgroupstats_build(stats, file->f_dentry);
- if (rc < 0)
+ if (rc < 0) {
+ nlmsg_free(rep_skb);
goto err;
-
- fput_light(file, fput_needed);
- return send_reply(rep_skb, info->snd_pid);
}

+ rc = send_reply(rep_skb, info->snd_pid);
+
err:
- if (file)
fput_light(file, fput_needed);
- nlmsg_free(rep_skb);
return rc;
}

<-- snip -->

Is this patch OK for you?

cu
Adrian

<-- snip -->

We'd better not nlmsg_free on a pointer containing an undefined value (and without having anything allocated).

Spotted by the Coverity checker.

---

 kernel/taskstats.c |   36 ++++++++++++++++++------------------
 1 file changed, 18 insertions(+), 18 deletions(-)

eedd297ac36b5d92fc38b937677ba40dc6df1cd0

kernel/taskstats.c +18 -18
index 354e74b..07e86a8 100644
@@ -398,31 +398,31 @@ static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
 
 	fd = nla_get_u32(info->attrs[CGROUPSTATS_CMD_ATTR_FD]);
 	file = fget_light(fd, &fput_needed);
-	if (file) {
-		size = nla_total_size(sizeof(struct cgroupstats));
+	if (!file)
+		return 0;
 
-		rc = prepare_reply(info, CGROUPSTATS_CMD_NEW, &rep_skb,
-					size);
-		if (rc < 0)
-			goto err;
+	size = nla_total_size(sizeof(struct cgroupstats));
 
-		na = nla_reserve(rep_skb, CGROUPSTATS_TYPE_CGROUP_STATS,
-					sizeof(struct cgroupstats));
-		stats = nla_data(na);
-		memset(stats, 0, sizeof(*stats));
+	rc = prepare_reply(info, CGROUPSTATS_CMD_NEW, &rep_skb,
+				size);
+	if (rc < 0)
+		goto err;
 
-		rc = cgroupstats_build(stats, file->f_dentry);
-		if (rc < 0)
-			goto err;
+	na = nla_reserve(rep_skb, CGROUPSTATS_TYPE_CGROUP_STATS,
+				sizeof(struct cgroupstats));
+	stats = nla_data(na);
+	memset(stats, 0, sizeof(*stats));
 
-		fput_light(file, fput_needed);
-		return send_reply(rep_skb, info->snd_pid);
+	rc = cgroupstats_build(stats, file->f_dentry);
+	if (rc < 0) {
+		nlmsg_free(rep_skb);
+		goto err;
 	}
 
+	rc = send_reply(rep_skb, info->snd_pid);
+
 err:
-	if (file)
-		fput_light(file, fput_needed);
-	nlmsg_free(rep_skb);
+	fput_light(file, fput_needed);
 	return rc;
 }
 
Acked-by on v1 1/1
#3 lore raw
Quoted 13 lines · Adrian Bunk

I considered it more odd to read

                rc = cgroupstats_build(stats, file->f_dentry);
                if (rc < 0)
                        goto err;

                fput_light(file, fput_needed);
                return send_reply(rep_skb, info->snd_pid);
err:
                fput_light(file, fput_needed);
		nlmsg_free(rep_skb);

I agree, but sometimes the alternative can be worse to read and understand

Quoted 117 lines

But that's just personal taste.

Anyway, duplicating the same fput_light() call two or three times isn't nice.

Originally I had the bigger patch below and considered it too big for only this fix, but now I think it might be appropriate.

If you ignore whitespace when diff'ing, then all it does is:

<-- snip -->

kernel/taskstats.c +7 -7
@@ -398,7 +398,9 @@ static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
 
 	fd = nla_get_u32(info->attrs[CGROUPSTATS_CMD_ATTR_FD]);
 	file = fget_light(fd, &fput_needed);
-	if (file) {
+	if (!file)
+		return 0;
+
 		size = nla_total_size(sizeof(struct cgroupstats));
 
 		rc = prepare_reply(info, CGROUPSTATS_CMD_NEW, &rep_skb,
@@ -412,17 +414,15 @@ static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
 		memset(stats, 0, sizeof(*stats));
 
 		rc = cgroupstats_build(stats, file->f_dentry);
-		if (rc < 0)
+	if (rc < 0) {
+		nlmsg_free(rep_skb);
 			goto err;
-
-		fput_light(file, fput_needed);
-		return send_reply(rep_skb, info->snd_pid);
 	}
 
+	rc = send_reply(rep_skb, info->snd_pid);
+
 err:
-	if (file)
 		fput_light(file, fput_needed);
-	nlmsg_free(rep_skb);
 	return rc;
 }
 

<-- snip -->

Is this patch OK for you?

cu
Adrian

<-- snip -->

We'd better not nlmsg_free on a pointer containing an undefined value (and without having anything allocated).

Spotted by the Coverity checker.

---

 kernel/taskstats.c |   36 ++++++++++++++++++------------------
 1 file changed, 18 insertions(+), 18 deletions(-)

eedd297ac36b5d92fc38b937677ba40dc6df1cd0

kernel/taskstats.c +15 -15
index 354e74b..07e86a8 100644
@@ -398,31 +398,31 @@ static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
 
 	fd = nla_get_u32(info->attrs[CGROUPSTATS_CMD_ATTR_FD]);
 	file = fget_light(fd, &fput_needed);
-	if (file) {
-		size = nla_total_size(sizeof(struct cgroupstats));
+	if (!file)
+		return 0;
 
-		rc = prepare_reply(info, CGROUPSTATS_CMD_NEW, &rep_skb,
-					size);
-		if (rc < 0)
-			goto err;
+	size = nla_total_size(sizeof(struct cgroupstats));
 
-		na = nla_reserve(rep_skb, CGROUPSTATS_TYPE_CGROUP_STATS,
-					sizeof(struct cgroupstats));
-		stats = nla_data(na);
-		memset(stats, 0, sizeof(*stats));
+	rc = prepare_reply(info, CGROUPSTATS_CMD_NEW, &rep_skb,
+				size);
+	if (rc < 0)
+		goto err;
 
-		rc = cgroupstats_build(stats, file->f_dentry);
-		if (rc < 0)
-			goto err;
+	na = nla_reserve(rep_skb, CGROUPSTATS_TYPE_CGROUP_STATS,
+				sizeof(struct cgroupstats));
+	stats = nla_data(na);
+	memset(stats, 0, sizeof(*stats));
 
-		fput_light(file, fput_needed);
-		return send_reply(rep_skb, info->snd_pid);
+	rc = cgroupstats_build(stats, file->f_dentry);
+	if (rc < 0) {
+		nlmsg_free(rep_skb);
+		goto err;
 	}
 

kernel/taskstats.c static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info) · line 428

Quoted 10 lines
kernel/taskstats.c +3 -3
+	rc = send_reply(rep_skb, info->snd_pid);
+
 err:
-	if (file)
-		fput_light(file, fput_needed);
-	nlmsg_free(rep_skb);
+	fput_light(file, fput_needed);
 	return rc;
 }
 

Looks good to me!

Yet to be tested, I'll try and test it soon.

Signature · 4 lines
	Warm Regards,
	Balbir Singh
	Linux Technology Center
	IBM, ISTL