diff mbox series

[v2] EDAC/mc_sysfs: Add missing newlines when printing {max,dimm}_location

Message ID 1600051734-8993-1-git-send-email-wangxiongfeng2@huawei.com (mailing list archive)
State New, archived
Headers show
Series [v2] EDAC/mc_sysfs: Add missing newlines when printing {max,dimm}_location | expand

Commit Message

Xiongfeng Wang Sept. 14, 2020, 2:48 a.m. UTC
Reading those sysfs entries gives:

  [root@localhost /]# cat /sys/devices/system/edac/mc/mc0/max_location
  memory 3 [root@localhost /]# cat /sys/devices/system/edac/mc/mc0/dimm0/dimm_location
  memory 0 [root@localhost /]#

Add newlines after the value it prints for better readability.

Signed-off-by: Xiongfeng Wang <wangxiongfeng2@huawei.com>
---
 drivers/edac/edac_mc_sysfs.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

Comments

Borislav Petkov Sept. 16, 2020, 5 p.m. UTC | #1
On Mon, Sep 14, 2020 at 10:48:54AM +0800, Xiongfeng Wang wrote:
> @@ -813,15 +817,21 @@ static ssize_t mci_max_location_show(struct device *dev,
>  				     char *data)
>  {
>  	struct mem_ctl_info *mci = to_mci(dev);
> -	int i;
> +	int i, n;
>  	char *p = data;
> +	unsigned int len = PAGE_SIZE;
>  
>  	for (i = 0; i < mci->n_layers; i++) {
> -		p += sprintf(p, "%s %d ",
> +		n = snprintf(p, len, "%s %d ",
>  			     edac_layer_name[mci->layers[i].type],
>  			     mci->layers[i].size - 1);
> +		p += n;
> +		len -= n;

What happens if that subtraction causes len to wrap around and become a
huge positive unsigned integer?

> +		if (!len)

Would that test still work?

IOW, I did this to your patch ontop. Note that I've moved the "p"
pointer incrementation after the length check so that the pointer
doesn't overflow too:

---
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index bf0e075fb635..fa0551c81e63 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -817,19 +817,22 @@ static ssize_t mci_max_location_show(struct device *dev,
 				     char *data)
 {
 	struct mem_ctl_info *mci = to_mci(dev);
-	int i, n;
+	int len = PAGE_SIZE;
 	char *p = data;
-	unsigned int len = PAGE_SIZE;
+	int i, n;
 
 	for (i = 0; i < mci->n_layers; i++) {
 		n = snprintf(p, len, "%s %d ",
 			     edac_layer_name[mci->layers[i].type],
 			     mci->layers[i].size - 1);
-		p += n;
+
 		len -= n;
-		if (!len)
+		if (len < 0)
 			goto out;
+
+		p += n;
 	}
+
 	p += snprintf(p, len, "\n");
 out:
 	return p - data;
Xiongfeng Wang Sept. 17, 2020, 11:38 a.m. UTC | #2
Hi ,

On 2020/9/17 1:00, Borislav Petkov wrote:
> On Mon, Sep 14, 2020 at 10:48:54AM +0800, Xiongfeng Wang wrote:
>> @@ -813,15 +817,21 @@ static ssize_t mci_max_location_show(struct device *dev,
>>  				     char *data)
>>  {
>>  	struct mem_ctl_info *mci = to_mci(dev);
>> -	int i;
>> +	int i, n;
>>  	char *p = data;
>> +	unsigned int len = PAGE_SIZE;
>>  
>>  	for (i = 0; i < mci->n_layers; i++) {
>> -		p += sprintf(p, "%s %d ",
>> +		n = snprintf(p, len, "%s %d ",
>>  			     edac_layer_name[mci->layers[i].type],
>>  			     mci->layers[i].size - 1);
>> +		p += n;
>> +		len -= n;
> 
> What happens if that subtraction causes len to wrap around and become a
> huge positive unsigned integer?
> 
>> +		if (!len)
> 
> Would that test still work?

I am not sure if snprintf will return a value larger than its second input
paramter 'size'. But we can also check if 'len' is less than 0. It's better.

> 
> IOW, I did this to your patch ontop. Note that I've moved the "p"
> pointer incrementation after the length check so that the pointer
> doesn't overflow too:

Thanks. I will add it in the next version.

> 
> ---
> diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
> index bf0e075fb635..fa0551c81e63 100644
> --- a/drivers/edac/edac_mc_sysfs.c
> +++ b/drivers/edac/edac_mc_sysfs.c
> @@ -817,19 +817,22 @@ static ssize_t mci_max_location_show(struct device *dev,
>  				     char *data)
>  {
>  	struct mem_ctl_info *mci = to_mci(dev);
> -	int i, n;
> +	int len = PAGE_SIZE;
>  	char *p = data;
> -	unsigned int len = PAGE_SIZE;
> +	int i, n;
>  
>  	for (i = 0; i < mci->n_layers; i++) {
>  		n = snprintf(p, len, "%s %d ",
>  			     edac_layer_name[mci->layers[i].type],
>  			     mci->layers[i].size - 1);
> -		p += n;
> +
>  		len -= n;
> -		if (!len)
> +		if (len < 0)

Not sure whether we need to check 'len' equals to 0.
if (len <= 0) ?


>  			goto out;
> +
> +		p += n;
>  	}
> +
>  	p += snprintf(p, len, "\n");
>  out:
>  	return p - data;
> 

Thanks,
XIongfeng
Joe Perches Sept. 17, 2020, 3:28 p.m. UTC | #3
On Thu, 2020-09-17 at 19:38 +0800, Xiongfeng Wang wrote:
> On 2020/9/17 1:00, Borislav Petkov wrote:
> > On Mon, Sep 14, 2020 at 10:48:54AM +0800, Xiongfeng Wang wrote:
> > > @@ -813,15 +817,21 @@ static ssize_t mci_max_location_show(struct device *dev,
> > >  				     char *data)
> > >  {
> > >  	struct mem_ctl_info *mci = to_mci(dev);
> > > -	int i;
> > > +	int i, n;
> > >  	char *p = data;
> > > +	unsigned int len = PAGE_SIZE;
> > >  
> > >  	for (i = 0; i < mci->n_layers; i++) {
> > > -		p += sprintf(p, "%s %d ",
> > > +		n = snprintf(p, len, "%s %d ",
> > >  			     edac_layer_name[mci->layers[i].type],
> > >  			     mci->layers[i].size - 1);
> > > +		p += n;
> > > +		len -= n;
> > 
> > What happens if that subtraction causes len to wrap around and become a
> > huge positive unsigned integer?

If you're really concerned about wrapping, use scnprintf.
Borislav Petkov Sept. 17, 2020, 4:25 p.m. UTC | #4
On Thu, Sep 17, 2020 at 07:38:57PM +0800, Xiongfeng Wang wrote:
> I am not sure if snprintf will return a value larger than its second input
> paramter 'size'.

The comment over snprintf() says

 * The return value is the number of characters which would be
 * generated for the given input, excluding the trailing null,
 * as per ISO C99.  If the return is greater than or equal to
 * @size, the resulting string is truncated.

And let's try it, see diff at the end. Now look what that produces:

[    2.594796] kernel_init: len: 16, str: [A lo]

it returns 16 for len even though the buffer is 5 chars long. So in our
patch, we'd increment by 16 which would be wrong.

Now let's use scnprintf():

[    2.700142] kernel_init: len: 4, str: [A lo]

Much better. Lemme do that.

> Not sure whether we need to check 'len' equals to 0.
> if (len <= 0) ?

Yeah, lemme fix that too, so we have now incrementally ontop:

---
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index fa0551c81e63..c56e0004b39e 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -822,18 +822,17 @@ static ssize_t mci_max_location_show(struct device *dev,
 	int i, n;
 
 	for (i = 0; i < mci->n_layers; i++) {
-		n = snprintf(p, len, "%s %d ",
-			     edac_layer_name[mci->layers[i].type],
-			     mci->layers[i].size - 1);
-
+		n = scnprintf(p, len, "%s %d ",
+			      edac_layer_name[mci->layers[i].type],
+			      mci->layers[i].size - 1);
 		len -= n;
-		if (len < 0)
+		if (len <= 0)
 			goto out;
 
 		p += n;
 	}
 
-	p += snprintf(p, len, "\n");
+	p += scnprintf(p, len, "\n");
 out:
 	return p - data;
 }
---

Test diff:

---
diff --git a/init/main.c b/init/main.c
index ae78fb68d231..e2d6110d3a3d 100644
--- a/init/main.c
+++ b/init/main.c
@@ -1397,7 +1397,8 @@ void __weak free_initmem(void)
 
 static int __ref kernel_init(void *unused)
 {
-	int ret;
+	char str[5];
+	int ret, len;
 
 	kernel_init_freeable();
 	/* need to finish all async __init code before freeing the memory */
@@ -1419,6 +1420,11 @@ static int __ref kernel_init(void *unused)
 
 	do_sysctl_args();
 
+	len = snprintf(str, 5, "A longer string\n");
+
+	pr_info("%s: len: %d, str: [%s]\n",
+		__func__, len, str);
+
 	if (ramdisk_execute_command) {
 		ret = run_init_process(ramdisk_execute_command);
 		if (!ret)
Xiongfeng Wang Sept. 18, 2020, 2:37 a.m. UTC | #5
On 2020/9/18 0:25, Borislav Petkov wrote:
> On Thu, Sep 17, 2020 at 07:38:57PM +0800, Xiongfeng Wang wrote:
>> I am not sure if snprintf will return a value larger than its second input
>> paramter 'size'.
> 
> The comment over snprintf() says
> 
>  * The return value is the number of characters which would be
>  * generated for the given input, excluding the trailing null,
>  * as per ISO C99.  If the return is greater than or equal to
>  * @size, the resulting string is truncated.
> 
> And let's try it, see diff at the end. Now look what that produces:
> 
> [    2.594796] kernel_init: len: 16, str: [A lo]
> 
> it returns 16 for len even though the buffer is 5 chars long. So in our
> patch, we'd increment by 16 which would be wrong.
> 
> Now let's use scnprintf():
> 
> [    2.700142] kernel_init: len: 4, str: [A lo]
> 
> Much better. Lemme do that.
> 
>> Not sure whether we need to check 'len' equals to 0.
>> if (len <= 0) ?
> 
> Yeah, lemme fix that too, so we have now incrementally ontop:


Thansk a lot. I will send another version. Also I will change the 'snprintf' in
'dimmdev_location_show()' to 'scnprintf'

Thanks,
Xiongfeng

> 
> ---
> diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
> index fa0551c81e63..c56e0004b39e 100644
> --- a/drivers/edac/edac_mc_sysfs.c
> +++ b/drivers/edac/edac_mc_sysfs.c
> @@ -822,18 +822,17 @@ static ssize_t mci_max_location_show(struct device *dev,
>  	int i, n;
>  
>  	for (i = 0; i < mci->n_layers; i++) {
> -		n = snprintf(p, len, "%s %d ",
> -			     edac_layer_name[mci->layers[i].type],
> -			     mci->layers[i].size - 1);
> -
> +		n = scnprintf(p, len, "%s %d ",
> +			      edac_layer_name[mci->layers[i].type],
> +			      mci->layers[i].size - 1);
>  		len -= n;
> -		if (len < 0)
> +		if (len <= 0)
>  			goto out;
>  
>  		p += n;
>  	}
>  
> -	p += snprintf(p, len, "\n");
> +	p += scnprintf(p, len, "\n");
>  out:
>  	return p - data;
>  }
> ---
> 
> Test diff:
> 
> ---
> diff --git a/init/main.c b/init/main.c
> index ae78fb68d231..e2d6110d3a3d 100644
> --- a/init/main.c
> +++ b/init/main.c
> @@ -1397,7 +1397,8 @@ void __weak free_initmem(void)
>  
>  static int __ref kernel_init(void *unused)
>  {
> -	int ret;
> +	char str[5];
> +	int ret, len;
>  
>  	kernel_init_freeable();
>  	/* need to finish all async __init code before freeing the memory */
> @@ -1419,6 +1420,11 @@ static int __ref kernel_init(void *unused)
>  
>  	do_sysctl_args();
>  
> +	len = snprintf(str, 5, "A longer string\n");
> +
> +	pr_info("%s: len: %d, str: [%s]\n",
> +		__func__, len, str);
> +
>  	if (ramdisk_execute_command) {
>  		ret = run_init_process(ramdisk_execute_command);
>  		if (!ret)
>
Borislav Petkov Sept. 18, 2020, 7:12 a.m. UTC | #6
On Fri, Sep 18, 2020 at 10:37:28AM +0800, Xiongfeng Wang wrote:
> Thansk a lot. I will send another version. Also I will change the
> 'snprintf' in 'dimmdev_location_show()' to 'scnprintf'

No need to send another one - I have everything locally and just amended
it.

Thx.
Joe Perches Sept. 18, 2020, 1:31 p.m. UTC | #7
On Fri, 2020-09-18 at 09:12 +0200, Borislav Petkov wrote:
> On Fri, Sep 18, 2020 at 10:37:28AM +0800, Xiongfeng Wang wrote:
> > Thansk a lot. I will send another version. Also I will change the
> > 'snprintf' in 'dimmdev_location_show()' to 'scnprintf'
> 
> No need to send another one - I have everything locally and just amended
> it.

A generic question about sysfs is whether or not the
PAGE_SIZE buf output should be newline terminated or
not if an the buffer is completely filled and the
desired output cannot be newline terminated.

Likely not.

NUL termination without newline should be enough to
indicate overrun.
diff mbox series

Patch

diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 4e6aca5..bf0e075 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -474,8 +474,12 @@  static ssize_t dimmdev_location_show(struct device *dev,
 				     struct device_attribute *mattr, char *data)
 {
 	struct dimm_info *dimm = to_dimm(dev);
+	ssize_t count;
 
-	return edac_dimm_info_location(dimm, data, PAGE_SIZE);
+	count = edac_dimm_info_location(dimm, data, PAGE_SIZE);
+	count += snprintf(data + count, PAGE_SIZE - count, "\n");
+
+	return count;
 }
 
 static ssize_t dimmdev_label_show(struct device *dev,
@@ -813,15 +817,21 @@  static ssize_t mci_max_location_show(struct device *dev,
 				     char *data)
 {
 	struct mem_ctl_info *mci = to_mci(dev);
-	int i;
+	int i, n;
 	char *p = data;
+	unsigned int len = PAGE_SIZE;
 
 	for (i = 0; i < mci->n_layers; i++) {
-		p += sprintf(p, "%s %d ",
+		n = snprintf(p, len, "%s %d ",
 			     edac_layer_name[mci->layers[i].type],
 			     mci->layers[i].size - 1);
+		p += n;
+		len -= n;
+		if (!len)
+			goto out;
 	}
-
+	p += snprintf(p, len, "\n");
+out:
 	return p - data;
 }