Commit 554988d6 authored by Dave Young's avatar Dave Young Committed by Jens Axboe

[PATCH] cdrom_sysctl_info fix

Fix the cdrom_sysctl_info possible buffer overwrite bug. Also
fix the locking of accessing topCdromPtr pointer.
Signed-off-by: default avatarDave Young <hidave.darkstar@gmail.com>
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent 32eef964
...@@ -302,7 +302,7 @@ module_param(lockdoor, bool, 0); ...@@ -302,7 +302,7 @@ module_param(lockdoor, bool, 0);
module_param(check_media_type, bool, 0); module_param(check_media_type, bool, 0);
module_param(mrw_format_restart, bool, 0); module_param(mrw_format_restart, bool, 0);
static DEFINE_SPINLOCK(cdrom_lock); static DEFINE_MUTEX(cdrom_mutex);
static const char *mrw_format_status[] = { static const char *mrw_format_status[] = {
"not mrw", "not mrw",
...@@ -438,10 +438,10 @@ int register_cdrom(struct cdrom_device_info *cdi) ...@@ -438,10 +438,10 @@ int register_cdrom(struct cdrom_device_info *cdi)
cdo->generic_packet = cdrom_dummy_generic_packet; cdo->generic_packet = cdrom_dummy_generic_packet;
cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
spin_lock(&cdrom_lock); mutex_lock(&cdrom_mutex);
cdi->next = topCdromPtr; cdi->next = topCdromPtr;
topCdromPtr = cdi; topCdromPtr = cdi;
spin_unlock(&cdrom_lock); mutex_unlock(&cdrom_mutex);
return 0; return 0;
} }
#undef ENSURE #undef ENSURE
...@@ -452,7 +452,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg) ...@@ -452,7 +452,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg)
cdinfo(CD_OPEN, "entering unregister_cdrom\n"); cdinfo(CD_OPEN, "entering unregister_cdrom\n");
prev = NULL; prev = NULL;
spin_lock(&cdrom_lock); mutex_lock(&cdrom_mutex);
cdi = topCdromPtr; cdi = topCdromPtr;
while (cdi && cdi != unreg) { while (cdi && cdi != unreg) {
prev = cdi; prev = cdi;
...@@ -460,7 +460,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg) ...@@ -460,7 +460,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg)
} }
if (cdi == NULL) { if (cdi == NULL) {
spin_unlock(&cdrom_lock); mutex_unlock(&cdrom_mutex);
return -2; return -2;
} }
if (prev) if (prev)
...@@ -468,7 +468,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg) ...@@ -468,7 +468,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg)
else else
topCdromPtr = cdi->next; topCdromPtr = cdi->next;
spin_unlock(&cdrom_lock); mutex_unlock(&cdrom_mutex);
if (cdi->exit) if (cdi->exit)
cdi->exit(cdi); cdi->exit(cdi);
...@@ -3289,103 +3289,137 @@ static struct cdrom_sysctl_settings { ...@@ -3289,103 +3289,137 @@ static struct cdrom_sysctl_settings {
int check; /* check media type */ int check; /* check media type */
} cdrom_sysctl_settings; } cdrom_sysctl_settings;
enum cdrom_print_option {
CTL_NAME,
CTL_SPEED,
CTL_SLOTS,
CTL_CAPABILITY
};
static int cdrom_print_info(const char *header, int val, char *info,
int *pos, enum cdrom_print_option option)
{
const int max_size = sizeof(cdrom_sysctl_settings.info);
struct cdrom_device_info *cdi;
int ret;
ret = scnprintf(info + *pos, max_size - *pos, header);
if (!ret)
return 1;
*pos += ret;
for (cdi = topCdromPtr; cdi; cdi = cdi->next) {
switch (option) {
case CTL_NAME:
ret = scnprintf(info + *pos, max_size - *pos,
"\t%s", cdi->name);
break;
case CTL_SPEED:
ret = scnprintf(info + *pos, max_size - *pos,
"\t%d", cdi->speed);
break;
case CTL_SLOTS:
ret = scnprintf(info + *pos, max_size - *pos,
"\t%d", cdi->capacity);
break;
case CTL_CAPABILITY:
ret = scnprintf(info + *pos, max_size - *pos,
"\t%d", CDROM_CAN(val) != 0);
break;
default:
printk(KERN_INFO "cdrom: invalid option%d\n", option);
return 1;
}
if (!ret)
return 1;
*pos += ret;
}
return 0;
}
static int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp, static int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp,
void __user *buffer, size_t *lenp, loff_t *ppos) void __user *buffer, size_t *lenp, loff_t *ppos)
{ {
int pos; int pos;
struct cdrom_device_info *cdi;
char *info = cdrom_sysctl_settings.info; char *info = cdrom_sysctl_settings.info;
const int max_size = sizeof(cdrom_sysctl_settings.info);
if (!*lenp || (*ppos && !write)) { if (!*lenp || (*ppos && !write)) {
*lenp = 0; *lenp = 0;
return 0; return 0;
} }
mutex_lock(&cdrom_mutex);
pos = sprintf(info, "CD-ROM information, " VERSION "\n"); pos = sprintf(info, "CD-ROM information, " VERSION "\n");
pos += sprintf(info+pos, "\ndrive name:\t"); if (cdrom_print_info("\ndrive name:\t", 0, info, &pos, CTL_NAME))
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) goto done;
pos += sprintf(info+pos, "\t%s", cdi->name); if (cdrom_print_info("\ndrive speed:\t", 0, info, &pos, CTL_SPEED))
goto done;
pos += sprintf(info+pos, "\ndrive speed:\t"); if (cdrom_print_info("\ndrive # of slots:", 0, info, &pos, CTL_SLOTS))
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) goto done;
pos += sprintf(info+pos, "\t%d", cdi->speed); if (cdrom_print_info("\nCan close tray:\t",
CDC_CLOSE_TRAY, info, &pos, CTL_CAPABILITY))
pos += sprintf(info+pos, "\ndrive # of slots:"); goto done;
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) if (cdrom_print_info("\nCan open tray:\t",
pos += sprintf(info+pos, "\t%d", cdi->capacity); CDC_OPEN_TRAY, info, &pos, CTL_CAPABILITY))
goto done;
pos += sprintf(info+pos, "\nCan close tray:\t"); if (cdrom_print_info("\nCan lock tray:\t",
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) CDC_LOCK, info, &pos, CTL_CAPABILITY))
pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CLOSE_TRAY) != 0); goto done;
if (cdrom_print_info("\nCan change speed:",
pos += sprintf(info+pos, "\nCan open tray:\t"); CDC_SELECT_SPEED, info, &pos, CTL_CAPABILITY))
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) goto done;
pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_OPEN_TRAY) != 0); if (cdrom_print_info("\nCan select disk:",
CDC_SELECT_DISC, info, &pos, CTL_CAPABILITY))
pos += sprintf(info+pos, "\nCan lock tray:\t"); goto done;
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) if (cdrom_print_info("\nCan read multisession:",
pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_LOCK) != 0); CDC_MULTI_SESSION, info, &pos, CTL_CAPABILITY))
goto done;
pos += sprintf(info+pos, "\nCan change speed:"); if (cdrom_print_info("\nCan read MCN:\t",
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) CDC_MCN, info, &pos, CTL_CAPABILITY))
pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_SPEED) != 0); goto done;
if (cdrom_print_info("\nReports media changed:",
pos += sprintf(info+pos, "\nCan select disk:"); CDC_MEDIA_CHANGED, info, &pos, CTL_CAPABILITY))
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) goto done;
pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_DISC) != 0); if (cdrom_print_info("\nCan play audio:\t",
CDC_PLAY_AUDIO, info, &pos, CTL_CAPABILITY))
pos += sprintf(info+pos, "\nCan read multisession:"); goto done;
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) if (cdrom_print_info("\nCan write CD-R:\t",
pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MULTI_SESSION) != 0); CDC_CD_R, info, &pos, CTL_CAPABILITY))
goto done;
pos += sprintf(info+pos, "\nCan read MCN:\t"); if (cdrom_print_info("\nCan write CD-RW:",
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) CDC_CD_RW, info, &pos, CTL_CAPABILITY))
pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MCN) != 0); goto done;
if (cdrom_print_info("\nCan read DVD:\t",
pos += sprintf(info+pos, "\nReports media changed:"); CDC_DVD, info, &pos, CTL_CAPABILITY))
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) goto done;
pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MEDIA_CHANGED) != 0); if (cdrom_print_info("\nCan write DVD-R:",
CDC_DVD_R, info, &pos, CTL_CAPABILITY))
pos += sprintf(info+pos, "\nCan play audio:\t"); goto done;
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) if (cdrom_print_info("\nCan write DVD-RAM:",
pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_PLAY_AUDIO) != 0); CDC_DVD_RAM, info, &pos, CTL_CAPABILITY))
goto done;
pos += sprintf(info+pos, "\nCan write CD-R:\t"); if (cdrom_print_info("\nCan read MRW:\t",
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) CDC_MRW, info, &pos, CTL_CAPABILITY))
pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CD_R) != 0); goto done;
if (cdrom_print_info("\nCan write MRW:\t",
pos += sprintf(info+pos, "\nCan write CD-RW:"); CDC_MRW_W, info, &pos, CTL_CAPABILITY))
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) goto done;
pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CD_RW) != 0); if (cdrom_print_info("\nCan write RAM:\t",
CDC_RAM, info, &pos, CTL_CAPABILITY))
pos += sprintf(info+pos, "\nCan read DVD:\t"); goto done;
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) if (!scnprintf(info + pos, max_size - pos, "\n\n"))
pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD) != 0); goto done;
doit:
pos += sprintf(info+pos, "\nCan write DVD-R:"); mutex_unlock(&cdrom_mutex);
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) return proc_dostring(ctl, write, filp, buffer, lenp, ppos);
pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_R) != 0); done:
printk(KERN_INFO "cdrom: info buffer too small\n");
pos += sprintf(info+pos, "\nCan write DVD-RAM:"); goto doit;
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_RAM) != 0);
pos += sprintf(info+pos, "\nCan read MRW:\t");
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MRW) != 0);
pos += sprintf(info+pos, "\nCan write MRW:\t");
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MRW_W) != 0);
pos += sprintf(info+pos, "\nCan write RAM:\t");
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_RAM) != 0);
strcpy(info+pos,"\n\n");
return proc_dostring(ctl, write, filp, buffer, lenp, ppos);
} }
/* Unfortunately, per device settings are not implemented through /* Unfortunately, per device settings are not implemented through
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment