Re: [PATCH] cdrom: Fix info leak/OOB read in cdrom_ioctl_drive_status

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

 



On Fri, Apr 27, 2018 at 08:43:03AM -0600, Scott Bauer wrote:
> 
> 
> On 04/27/2018 06:41 AM, Dan Carpenter wrote:
> > I sent you an email to send this patch, but reviewing it now it's not
> > actually a run time bug.  The cdrom_slot_status() function takes an
> > integer argument so it works.
> 
> It's still  runtime bug... I should reword the commit a bit to reflect that it's not
> like the upper 32 bit issue that you had found. Look at it this way, ints can be negative, right?
>

Oh.  Yeah.  Duh...

> The check is as follows:
> 
> 2545:	if (((int)arg >= cdi->capacity))
> 		return -EINVAL <https://elixir.bootlin.com/linux/v4.17-rc2/ident/EINVAL>;
> 	return cdrom_slot_status <https://elixir.bootlin.com/linux/v4.17-rc2/ident/cdrom_slot_status>(cdi, arg); so if (-65536 >= cdi->capacity) it's not so we don't return -einval. And we pass a negative index into cdrom_slot_status.
> 
> 
> where we do the following (https://elixir.bootlin.com/linux/v4.17-rc2/source/drivers/cdrom/cdrom.c#L1336):
> 
> 1336:
> 	if (info->slots <https://elixir.bootlin.com/linux/v4.17-rc2/ident/slots>[slot <https://elixir.bootlin.com/linux/v4.17-rc2/ident/slot>].disc_present)
> 		ret = CDS_DISC_OK <https://elixir.bootlin.com/linux/v4.17-rc2/ident/CDS_DISC_OK>;
> 
> 
> 
> >
> > I'm working on a static checker warning for these kinds of bugs:
> >
> > drivers/cdrom/cdrom.c:2444 cdrom_ioctl_select_disc() warn: truncated comparison 'arg' 'u64max' to 's32max'
> >
> > drivers/cdrom/cdrom.c
> >   2435  static int cdrom_ioctl_select_disc(struct cdrom_device_info *cdi,
> >   2436                  unsigned long arg)
> >   2437  {
> >   2438          cd_dbg(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n");
> >   2439  
> >   2440          if (!CDROM_CAN(CDC_SELECT_DISC))
> >   2441                  return -ENOSYS;
> >   2442  
> >   2443          if (arg != CDSL_CURRENT && arg != CDSL_NONE) {
> >   2444                  if ((int)arg >= cdi->capacity)
> >                             ^^^^^^^^^^^^^^^^^^^^^^^^^
> >   2445                          return -EINVAL;
> >   2446          }
> >   2447  
> >   2448          /*
> >   2449           * ->select_disc is a hook to allow a driver-specific way of
> >   2450           * seleting disc.  However, since there is no equivalent hook for
> >   2451           * cdrom_slot_status this may not actually be useful...
> >   2452           */
> >   2453          if (cdi->ops->select_disc)
> >   2454                  return cdi->ops->select_disc(cdi, arg);
> >                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > ->select_disc() also take an int so it's fine (plus there is no such
> > function so it's dead code).
> >
> >   2455  
> >   2456          cd_dbg(CD_CHANGER, "Using generic cdrom_select_disc()\n");
> >   2457          return cdrom_select_disc(cdi, arg);
> >                                               ^^^
> > Also an int.
> >
> >   2458  }
> >
> > So I think it's a good idea to fix these just for cleanliness and to
> > silence the static checker warnings but it doesn't affect runtime.
> 
> Yeah, this one was "fine" aside from being messy, that's why I didn't send a patch for it.
> 

I'm not convinced any more.  Could you patch it and resend?  We could
end up sending invalid commands to the cdrom firmware when we do
cdrom_load_unload() at the end of the cdrom_select_disc() function.
Proably there is no impact but we may as well fix it.  Here is my
analysis if you are curious:

  1371  /* If SLOT < 0, unload the current slot.  Otherwise, try to load SLOT. */
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
CDSL_CURRENT is INT_MAX and CDSL_NONE is "INT_MAX - 1" but
cdrom_select_disc() calls this with slot set to -1.

  1372  static int cdrom_load_unload(struct cdrom_device_info *cdi, int slot) 
  1373  {
  1374          struct packet_command cgc;
  1375  
  1376          cd_dbg(CD_CHANGER, "entering cdrom_load_unload()\n");
  1377          if (cdi->sanyo_slot && slot < 0)
  1378                  return 0;
  1379  
  1380          init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
  1381          cgc.cmd[0] = GPCMD_LOAD_UNLOAD;
  1382          cgc.cmd[4] = 2 + (slot >= 0);
                ^^^^^^^^^^
So cmd[4] is 2.

  1383          cgc.cmd[8] = slot;
                ^^^^^^^^^^^^^^^^^
Here were setting cmd[8] to any u8 value we choose.

  1384          cgc.timeout = 60 * HZ;
  1385  
  1386          /* The Sanyo 3 CD changer uses byte 7 of the 
  1387          GPCMD_TEST_UNIT_READY to command to switch CDs instead of
  1388          using the GPCMD_LOAD_UNLOAD opcode. */
  1389          if (cdi->sanyo_slot && -1 < slot) {
  1390                  cgc.cmd[0] = GPCMD_TEST_UNIT_READY;
  1391                  cgc.cmd[7] = slot;
  1392                  cgc.cmd[4] = cgc.cmd[8] = 0;
  1393                  cdi->sanyo_slot = slot ? slot : 3;
  1394          }
  1395  
  1396          return cdi->ops->generic_packet(cdi, &cgc);
  1397  }

> P.S. Is your static analysis tooling available for the general public to look at?

Sure.  I've been dorking with it for a couple days and I haven't tested
the latest version except on drivers/cdrom/cdrom.c so let me do some
more testing and then I'll post it.

regards,
dan carpenter




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

  Powered by Linux