diff mbox series

[1/2] cmd64x: potential buffer overflow in cmd64x_program_timings()

Message ID 20200107130441.y3owvcnxdljailt5@kili.mountain
State Accepted
Delegated to: David Miller
Headers show
Series [1/2] cmd64x: potential buffer overflow in cmd64x_program_timings() | expand

Commit Message

Dan Carpenter Jan. 7, 2020, 1:04 p.m. UTC
The "drive->dn" value is a u8 and it is controlled by root only, but
it could be out of bounds here so let's check.

Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
---
 drivers/ide/cmd64x.c | 3 +++
 1 file changed, 3 insertions(+)

Comments

David Miller Jan. 20, 2020, 1:40 p.m. UTC | #1
From: Dan Carpenter <dan.carpenter@oracle.com>
Date: Tue, 7 Jan 2020 16:04:41 +0300

> The "drive->dn" value is a u8 and it is controlled by root only, but
> it could be out of bounds here so let's check.
> 
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>

Applied.
Bartlomiej Zolnierkiewicz Jan. 21, 2020, 11:15 a.m. UTC | #2
Hi,

On 1/20/20 2:40 PM, David Miller wrote:
> From: Dan Carpenter <dan.carpenter@oracle.com>
> Date: Tue, 7 Jan 2020 16:04:41 +0300
> 
>> The "drive->dn" value is a u8 and it is controlled by root only, but
>> it could be out of bounds here so let's check.

drive->dn should not be root controllable, please point me where it
happens as this may need fixing instead of cmd64x driver.

[ IDE core makes sure that drive->dn is never > 3 and a lot of code
  assumes it. ]

>> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
> 
> Applied. 
Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics
Dan Carpenter Jan. 21, 2020, 11:48 a.m. UTC | #3
On Tue, Jan 21, 2020 at 12:15:54PM +0100, Bartlomiej Zolnierkiewicz wrote:
> 
> Hi,
> 
> On 1/20/20 2:40 PM, David Miller wrote:
> > From: Dan Carpenter <dan.carpenter@oracle.com>
> > Date: Tue, 7 Jan 2020 16:04:41 +0300
> > 
> >> The "drive->dn" value is a u8 and it is controlled by root only, but
> >> it could be out of bounds here so let's check.
> 
> drive->dn should not be root controllable, please point me where it
> happens as this may need fixing instead of cmd64x driver.
> 
> [ IDE core makes sure that drive->dn is never > 3 and a lot of code
>   assumes it. ]
> 

It's a marked as a setable field in ide-proc.c

drivers/ide/ide-proc.c
   206  ide_devset_rw(current_speed, xfer_rate);
   207  ide_devset_rw_field(init_speed, init_speed);
   208  ide_devset_rw_flag(nice1, IDE_DFLAG_NICE1);
   209  ide_devset_rw_field(number, dn);
                            ^^^^^^^^^^
Sets ->dn

   210  
   211  static const struct ide_proc_devset ide_generic_settings[] = {
   212          IDE_PROC_DEVSET(current_speed, 0, 70),
   213          IDE_PROC_DEVSET(init_speed, 0, 70),
   214          IDE_PROC_DEVSET(io_32bit,  0, 1 + (SUPPORT_VLB_SYNC << 1)),
   215          IDE_PROC_DEVSET(keepsettings, 0, 1),
   216          IDE_PROC_DEVSET(nice1, 0, 1),
   217          IDE_PROC_DEVSET(number, 0, 3),
   218          IDE_PROC_DEVSET(pio_mode, 0, 255),
   219          IDE_PROC_DEVSET(unmaskirq, 0, 1),
   220          IDE_PROC_DEVSET(using_dma, 0, 1),
   221          { NULL },
   222  };

drivers/ide/ide-devsets.c
   159  int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting,
   160                         int arg)
   161  {
   162          struct request_queue *q = drive->queue;
   163          struct request *rq;
   164          int ret = 0;
   165  
   166          if (!(setting->flags & DS_SYNC))
   167                  return setting->set(drive, arg);
                               ^^^^^^^^^^^^^^^^^^^^^^^^
Called from here according to Smatch.

   168  
   169          rq = blk_get_request(q, REQ_OP_DRV_IN, 0);

regards,
dan carpenter
Dan Carpenter Jan. 21, 2020, 11:55 a.m. UTC | #4
On Tue, Jan 21, 2020 at 02:48:35PM +0300, Dan Carpenter wrote:
> On Tue, Jan 21, 2020 at 12:15:54PM +0100, Bartlomiej Zolnierkiewicz wrote:
> > 
> > Hi,
> > 
> > On 1/20/20 2:40 PM, David Miller wrote:
> > > From: Dan Carpenter <dan.carpenter@oracle.com>
> > > Date: Tue, 7 Jan 2020 16:04:41 +0300
> > > 
> > >> The "drive->dn" value is a u8 and it is controlled by root only, but
> > >> it could be out of bounds here so let's check.
> > 
> > drive->dn should not be root controllable, please point me where it
> > happens as this may need fixing instead of cmd64x driver.
> > 
> > [ IDE core makes sure that drive->dn is never > 3 and a lot of code
> >   assumes it. ]
> > 
> 
> It's a marked as a setable field in ide-proc.c
> 
> drivers/ide/ide-proc.c
>    206  ide_devset_rw(current_speed, xfer_rate);
>    207  ide_devset_rw_field(init_speed, init_speed);
>    208  ide_devset_rw_flag(nice1, IDE_DFLAG_NICE1);
>    209  ide_devset_rw_field(number, dn);
>                             ^^^^^^^^^^
> Sets ->dn
> 
>    210  
>    211  static const struct ide_proc_devset ide_generic_settings[] = {
>    212          IDE_PROC_DEVSET(current_speed, 0, 70),
>    213          IDE_PROC_DEVSET(init_speed, 0, 70),
>    214          IDE_PROC_DEVSET(io_32bit,  0, 1 + (SUPPORT_VLB_SYNC << 1)),
>    215          IDE_PROC_DEVSET(keepsettings, 0, 1),
>    216          IDE_PROC_DEVSET(nice1, 0, 1),
>    217          IDE_PROC_DEVSET(number, 0, 3),
                                          ^^^^
Argh...  This clamps it to 0-3 doesn't it.

Sorry, I didn't see that.

regards,
dan carpenter
Dan Carpenter Jan. 21, 2020, 12:07 p.m. UTC | #5
On Tue, Jan 21, 2020 at 02:48:35PM +0300, Dan Carpenter wrote:
> On Tue, Jan 21, 2020 at 12:15:54PM +0100, Bartlomiej Zolnierkiewicz wrote:
> > 
> > Hi,
> > 
> > On 1/20/20 2:40 PM, David Miller wrote:
> > > From: Dan Carpenter <dan.carpenter@oracle.com>
> > > Date: Tue, 7 Jan 2020 16:04:41 +0300
> > > 
> > >> The "drive->dn" value is a u8 and it is controlled by root only, but
> > >> it could be out of bounds here so let's check.
> > 
> > drive->dn should not be root controllable, please point me where it
> > happens as this may need fixing instead of cmd64x driver.
> > 
> > [ IDE core makes sure that drive->dn is never > 3 and a lot of code
> >   assumes it. ]
> > 
> 
> It's a marked as a setable field in ide-proc.c
> 
> drivers/ide/ide-proc.c
>    206  ide_devset_rw(current_speed, xfer_rate);
>    207  ide_devset_rw_field(init_speed, init_speed);
>    208  ide_devset_rw_flag(nice1, IDE_DFLAG_NICE1);
>    209  ide_devset_rw_field(number, dn);
>                             ^^^^^^^^^^
> Sets ->dn
> 
>    210  
>    211  static const struct ide_proc_devset ide_generic_settings[] = {
>    212          IDE_PROC_DEVSET(current_speed, 0, 70),
>    213          IDE_PROC_DEVSET(init_speed, 0, 70),
>    214          IDE_PROC_DEVSET(io_32bit,  0, 1 + (SUPPORT_VLB_SYNC << 1)),
>    215          IDE_PROC_DEVSET(keepsettings, 0, 1),
>    216          IDE_PROC_DEVSET(nice1, 0, 1),
>    217          IDE_PROC_DEVSET(number, 0, 3),
>    218          IDE_PROC_DEVSET(pio_mode, 0, 255),
>    219          IDE_PROC_DEVSET(unmaskirq, 0, 1),
>    220          IDE_PROC_DEVSET(using_dma, 0, 1),
>    221          { NULL },
>    222  };
> 
> drivers/ide/ide-devsets.c
>    159  int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting,
>    160                         int arg)
>    161  {
>    162          struct request_queue *q = drive->queue;
>    163          struct request *rq;
>    164          int ret = 0;
>    165  
>    166          if (!(setting->flags & DS_SYNC))
>    167                  return setting->set(drive, arg);
>                                ^^^^^^^^^^^^^^^^^^^^^^^^
> Called from here according to Smatch.
> 

Actually this is where I went wrong.  The function is never called from
here.

Sorry for the noise.  These patches are not required.

regards,
dan carpenter
Bartlomiej Zolnierkiewicz Jan. 21, 2020, 12:21 p.m. UTC | #6
On 1/21/20 12:48 PM, Dan Carpenter wrote:
> On Tue, Jan 21, 2020 at 12:15:54PM +0100, Bartlomiej Zolnierkiewicz wrote:
>>
>> Hi,
>>
>> On 1/20/20 2:40 PM, David Miller wrote:
>>> From: Dan Carpenter <dan.carpenter@oracle.com>
>>> Date: Tue, 7 Jan 2020 16:04:41 +0300
>>>
>>>> The "drive->dn" value is a u8 and it is controlled by root only, but
>>>> it could be out of bounds here so let's check.
>>
>> drive->dn should not be root controllable, please point me where it
>> happens as this may need fixing instead of cmd64x driver.
>>
>> [ IDE core makes sure that drive->dn is never > 3 and a lot of code
>>   assumes it. ]
>>
> 
> It's a marked as a setable field in ide-proc.c
> 
> drivers/ide/ide-proc.c
>    206  ide_devset_rw(current_speed, xfer_rate);
>    207  ide_devset_rw_field(init_speed, init_speed);
>    208  ide_devset_rw_flag(nice1, IDE_DFLAG_NICE1);
>    209  ide_devset_rw_field(number, dn);
>                             ^^^^^^^^^^
> Sets ->dn

It is a bug.

We should add:

#define ide_devset_ro_field(_name, _field) \
ide_devset_get(_name, _field); \
IDE_DEVSET(_name, 0, get_##_name, NULL)

in <linux/ide.h> (just after ide_devset_rw_field())

and use it instead.

Care to make a patch?

>    210  
>    211  static const struct ide_proc_devset ide_generic_settings[] = {
>    212          IDE_PROC_DEVSET(current_speed, 0, 70),
>    213          IDE_PROC_DEVSET(init_speed, 0, 70),
>    214          IDE_PROC_DEVSET(io_32bit,  0, 1 + (SUPPORT_VLB_SYNC << 1)),
>    215          IDE_PROC_DEVSET(keepsettings, 0, 1),
>    216          IDE_PROC_DEVSET(nice1, 0, 1),
>    217          IDE_PROC_DEVSET(number, 0, 3),

Please note the minimum and maximum values above and look at code in
ide_write_setting():

	if ((ds->flags & DS_SYNC)
	    && (val < setting->min || val > setting->max))
		return -EINVAL;

[ DS_SYNC flag is set by ide_devset_rw_field() macro. ]

Thus even without fixing ide-proc.c both your patches are superfluous.

Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics

>    218          IDE_PROC_DEVSET(pio_mode, 0, 255),
>    219          IDE_PROC_DEVSET(unmaskirq, 0, 1),
>    220          IDE_PROC_DEVSET(using_dma, 0, 1),
>    221          { NULL },
>    222  };
> 
> drivers/ide/ide-devsets.c
>    159  int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting,
>    160                         int arg)
>    161  {
>    162          struct request_queue *q = drive->queue;
>    163          struct request *rq;
>    164          int ret = 0;
>    165  
>    166          if (!(setting->flags & DS_SYNC))
>    167                  return setting->set(drive, arg);
>                                ^^^^^^^^^^^^^^^^^^^^^^^^
> Called from here according to Smatch.
> 
>    168  
>    169          rq = blk_get_request(q, REQ_OP_DRV_IN, 0);
> 
> regards,
> dan carpenter
Bartlomiej Zolnierkiewicz Jan. 21, 2020, 12:38 p.m. UTC | #7
On 1/21/20 1:21 PM, Bartlomiej Zolnierkiewicz wrote:
> 
> On 1/21/20 12:48 PM, Dan Carpenter wrote:
>> On Tue, Jan 21, 2020 at 12:15:54PM +0100, Bartlomiej Zolnierkiewicz wrote:
>>>
>>> Hi,
>>>
>>> On 1/20/20 2:40 PM, David Miller wrote:
>>>> From: Dan Carpenter <dan.carpenter@oracle.com>
>>>> Date: Tue, 7 Jan 2020 16:04:41 +0300
>>>>
>>>>> The "drive->dn" value is a u8 and it is controlled by root only, but
>>>>> it could be out of bounds here so let's check.
>>>
>>> drive->dn should not be root controllable, please point me where it
>>> happens as this may need fixing instead of cmd64x driver.
>>>
>>> [ IDE core makes sure that drive->dn is never > 3 and a lot of code
>>>   assumes it. ]
>>>
>>
>> It's a marked as a setable field in ide-proc.c
>>
>> drivers/ide/ide-proc.c
>>    206  ide_devset_rw(current_speed, xfer_rate);
>>    207  ide_devset_rw_field(init_speed, init_speed);
>>    208  ide_devset_rw_flag(nice1, IDE_DFLAG_NICE1);
>>    209  ide_devset_rw_field(number, dn);
>>                             ^^^^^^^^^^
>> Sets ->dn
> 
> It is a bug.

PS The rationale for fixing it is:

- IDE core always sets ->dn correctly (changing it is never required)

- setting different value than assigned by IDE core is very likely to
  result in data corruption (due to wrong transfer timings being set on
  the controller etc.)

Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics
diff mbox series

Patch

diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c
index a1898e11b04e..943bf944bf72 100644
--- a/drivers/ide/cmd64x.c
+++ b/drivers/ide/cmd64x.c
@@ -66,6 +66,9 @@  static void cmd64x_program_timings(ide_drive_t *drive, u8 mode)
 	struct ide_timing t;
 	u8 arttim = 0;
 
+	if (drive->dn >= ARRAY_SIZE(drwtim_regs))
+		return;
+
 	ide_timing_compute(drive, mode, &t, T, 0);
 
 	/*