Re: [PATCH v5 1/4] platform/x86/amd/pmc: Use flex array when calling amd_pmc_stb_debugfs_open_v2()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Shyam,

On 10/9/23 12:09, Shyam Sundar S K wrote:
> Hi Hans,
> 
> On 10/9/2023 3:21 PM, Hans de Goede wrote:
>> Hi Shyam,
>>
>> On 10/9/23 11:45, Shyam Sundar S K wrote:
>>> Currently in amd_pmc_stb_debugfs_open_v2() the buffer size is assumed to
>>> be fixed and a second call to amd_pmc_stb_debugfs_open_v2() may race with
>>> a process holding open another fd. This could change "fsize" to a
>>> bigger size causing an out of bounds read.
>>>
>>> Instead create a struct with a flexarray to solve this.
>>>
>>> Suggested-by: Hans de Goede <hdegoede@xxxxxxxxxx>
>>> Signed-off-by: Sanket Goswami <Sanket.Goswami@xxxxxxx>
>>> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@xxxxxxx>
>>> ---
>>> v5:
>>>  - new patch based on comments in v4 from Hans.
>>>  - based on review-ilpo branch
>>>
>>>  drivers/platform/x86/amd/pmc/pmc.c | 22 ++++++++++++++--------
>>>  1 file changed, 14 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c
>>> index c92dd5077a16..e00d69801369 100644
>>> --- a/drivers/platform/x86/amd/pmc/pmc.c
>>> +++ b/drivers/platform/x86/amd/pmc/pmc.c
>>> @@ -122,6 +122,11 @@ enum s2d_arg {
>>>  	S2D_DRAM_SIZE,
>>>  };
>>>  
>>> +struct amd_pmc_stb_v2_data {
>>> +	size_t size;
>>> +	u8 data[] __counted_by(size);
>>> +};
>>> +
>>>  struct amd_pmc_bit_map {
>>>  	const char *name;
>>>  	u32 bit_mask;
>>> @@ -239,7 +244,8 @@ static const struct file_operations amd_pmc_stb_debugfs_fops = {
>>>  static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp)
>>>  {
>>>  	struct amd_pmc_dev *dev = filp->f_inode->i_private;
>>> -	u32 *buf, fsize, num_samples, val, stb_rdptr_offset = 0;
>>> +	u32 fsize, num_samples, val, stb_rdptr_offset = 0;
>>> +	struct amd_pmc_stb_v2_data *flex_arr;
>>>  	int ret;
>>>  
>>>  	/* Write dummy postcode while reading the STB buffer */
>>> @@ -247,10 +253,6 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp)
>>>  	if (ret)
>>>  		dev_err(dev->dev, "error writing to STB: %d\n", ret);
>>>  
>>> -	buf = kzalloc(S2D_TELEMETRY_BYTES_MAX, GFP_KERNEL);
>>> -	if (!buf)
>>> -		return -ENOMEM;
>>> -
>>>  	/* Spill to DRAM num_samples uses separate SMU message port */
>>>  	dev->msg_port = 1;
>>>  
>>> @@ -264,7 +266,6 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp)
>>>  	dev->msg_port = 0;
>>>  	if (ret) {
>>>  		dev_err(dev->dev, "error: S2D_NUM_SAMPLES not supported : %d\n", ret);
>>> -		kfree(buf);
>>>  		return ret;
>>>  	}
>>>  
>>> @@ -277,8 +278,13 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp)
>>>  		stb_rdptr_offset = 0;
>>>  	}
>>>  
>>> -	memcpy_fromio(buf, dev->stb_virt_addr + stb_rdptr_offset, fsize);
>>> -	filp->private_data = buf;
>>> +	flex_arr = kzalloc(struct_size(flex_arr, data, fsize), GFP_KERNEL);
>>> +	if (!flex_arr)
>>> +		return -ENOMEM;
>>> +
>>> +	memcpy_fromio(flex_arr->data, dev->stb_virt_addr + stb_rdptr_offset, fsize);
>>> +	flex_arr->size = fsize;
>>> +	filp->private_data = flex_arr->data;
>>>  
>>>  	return 0;
>>>  }
>>
>>
>> You are not adjusting amd_pmc_stb_debugfs_read_v2() to match it will still
>> return S2D_TELEMETRY_BYTES_MAX, likely overflowing the array!
>>
>> And it will now return the contents of the size_t prefixing the buffer to
>> userspace.
>>
>> So this is obviously broken, nack.
> 
> I think it was taken care in v5 4/4. Can you please take a look at it
> and see if something is really missing?

Please see my other emails in the thread, this really is broken, by
still using a size variable in the global data struct you are
not fixing the race of 2 amd_pmc_stb_debugfs_open_v2() being
made shortly behind each other and
by storing:

	filp->private_data = flex_arr->data;

instead of:

	filp->private_data = flex_arr;

You are causing a pointer not returned by kmalloc to get
passed to kfree() in release().

Regards,

Hans






> 
>         return simple_read_from_buffer(buf, size, pos, filp->private_data,
> -                                       S2D_TELEMETRY_BYTES_MAX);
> +                                        dev->fsize);
> 
> 
> Thanks,
> Shyam
> 
>>
>> Regards,
>>
>> Hans
>>
>>
> 




[Index of Archives]     [Linux Kernel Development]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux