diff options
author | Dave Young <hidave.darkstar@gmail.com> | 2007-06-19 03:14:26 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2007-07-10 02:03:33 -0400 |
commit | 554988d6fe369719ae5b41255c577569ecf47c30 (patch) | |
tree | d7e14d962b6dfad90815a44ff3c9dcf97ad903e9 | |
parent | 32eef964110985c5845472e07fa0a18838a970c4 (diff) |
[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: Dave Young <hidave.darkstar@gmail.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r-- | drivers/cdrom/cdrom.c | 216 |
1 files changed, 125 insertions, 91 deletions
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 3625a05bc3d3..aa5468f487ba 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c | |||
@@ -302,7 +302,7 @@ module_param(lockdoor, bool, 0); | |||
302 | module_param(check_media_type, bool, 0); | 302 | module_param(check_media_type, bool, 0); |
303 | module_param(mrw_format_restart, bool, 0); | 303 | module_param(mrw_format_restart, bool, 0); |
304 | 304 | ||
305 | static DEFINE_SPINLOCK(cdrom_lock); | 305 | static DEFINE_MUTEX(cdrom_mutex); |
306 | 306 | ||
307 | static const char *mrw_format_status[] = { | 307 | static const char *mrw_format_status[] = { |
308 | "not mrw", | 308 | "not mrw", |
@@ -438,10 +438,10 @@ int register_cdrom(struct cdrom_device_info *cdi) | |||
438 | cdo->generic_packet = cdrom_dummy_generic_packet; | 438 | cdo->generic_packet = cdrom_dummy_generic_packet; |
439 | 439 | ||
440 | cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); | 440 | cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); |
441 | spin_lock(&cdrom_lock); | 441 | mutex_lock(&cdrom_mutex); |
442 | cdi->next = topCdromPtr; | 442 | cdi->next = topCdromPtr; |
443 | topCdromPtr = cdi; | 443 | topCdromPtr = cdi; |
444 | spin_unlock(&cdrom_lock); | 444 | mutex_unlock(&cdrom_mutex); |
445 | return 0; | 445 | return 0; |
446 | } | 446 | } |
447 | #undef ENSURE | 447 | #undef ENSURE |
@@ -452,7 +452,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg) | |||
452 | cdinfo(CD_OPEN, "entering unregister_cdrom\n"); | 452 | cdinfo(CD_OPEN, "entering unregister_cdrom\n"); |
453 | 453 | ||
454 | prev = NULL; | 454 | prev = NULL; |
455 | spin_lock(&cdrom_lock); | 455 | mutex_lock(&cdrom_mutex); |
456 | cdi = topCdromPtr; | 456 | cdi = topCdromPtr; |
457 | while (cdi && cdi != unreg) { | 457 | while (cdi && cdi != unreg) { |
458 | prev = cdi; | 458 | prev = cdi; |
@@ -460,7 +460,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg) | |||
460 | } | 460 | } |
461 | 461 | ||
462 | if (cdi == NULL) { | 462 | if (cdi == NULL) { |
463 | spin_unlock(&cdrom_lock); | 463 | mutex_unlock(&cdrom_mutex); |
464 | return -2; | 464 | return -2; |
465 | } | 465 | } |
466 | if (prev) | 466 | if (prev) |
@@ -468,7 +468,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg) | |||
468 | else | 468 | else |
469 | topCdromPtr = cdi->next; | 469 | topCdromPtr = cdi->next; |
470 | 470 | ||
471 | spin_unlock(&cdrom_lock); | 471 | mutex_unlock(&cdrom_mutex); |
472 | 472 | ||
473 | if (cdi->exit) | 473 | if (cdi->exit) |
474 | cdi->exit(cdi); | 474 | cdi->exit(cdi); |
@@ -3289,103 +3289,137 @@ static struct cdrom_sysctl_settings { | |||
3289 | int check; /* check media type */ | 3289 | int check; /* check media type */ |
3290 | } cdrom_sysctl_settings; | 3290 | } cdrom_sysctl_settings; |
3291 | 3291 | ||
3292 | enum cdrom_print_option { | ||
3293 | CTL_NAME, | ||
3294 | CTL_SPEED, | ||
3295 | CTL_SLOTS, | ||
3296 | CTL_CAPABILITY | ||
3297 | }; | ||
3298 | |||
3299 | static int cdrom_print_info(const char *header, int val, char *info, | ||
3300 | int *pos, enum cdrom_print_option option) | ||
3301 | { | ||
3302 | const int max_size = sizeof(cdrom_sysctl_settings.info); | ||
3303 | struct cdrom_device_info *cdi; | ||
3304 | int ret; | ||
3305 | |||
3306 | ret = scnprintf(info + *pos, max_size - *pos, header); | ||
3307 | if (!ret) | ||
3308 | return 1; | ||
3309 | |||
3310 | *pos += ret; | ||
3311 | |||
3312 | for (cdi = topCdromPtr; cdi; cdi = cdi->next) { | ||
3313 | switch (option) { | ||
3314 | case CTL_NAME: | ||
3315 | ret = scnprintf(info + *pos, max_size - *pos, | ||
3316 | "\t%s", cdi->name); | ||
3317 | break; | ||
3318 | case CTL_SPEED: | ||
3319 | ret = scnprintf(info + *pos, max_size - *pos, | ||
3320 | "\t%d", cdi->speed); | ||
3321 | break; | ||
3322 | case CTL_SLOTS: | ||
3323 | ret = scnprintf(info + *pos, max_size - *pos, | ||
3324 | "\t%d", cdi->capacity); | ||
3325 | break; | ||
3326 | case CTL_CAPABILITY: | ||
3327 | ret = scnprintf(info + *pos, max_size - *pos, | ||
3328 | "\t%d", CDROM_CAN(val) != 0); | ||
3329 | break; | ||
3330 | default: | ||
3331 | printk(KERN_INFO "cdrom: invalid option%d\n", option); | ||
3332 | return 1; | ||
3333 | } | ||
3334 | if (!ret) | ||
3335 | return 1; | ||
3336 | *pos += ret; | ||
3337 | } | ||
3338 | |||
3339 | return 0; | ||
3340 | } | ||
3341 | |||
3292 | static int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp, | 3342 | static int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp, |
3293 | void __user *buffer, size_t *lenp, loff_t *ppos) | 3343 | void __user *buffer, size_t *lenp, loff_t *ppos) |
3294 | { | 3344 | { |
3295 | int pos; | 3345 | int pos; |
3296 | struct cdrom_device_info *cdi; | ||
3297 | char *info = cdrom_sysctl_settings.info; | 3346 | char *info = cdrom_sysctl_settings.info; |
3347 | const int max_size = sizeof(cdrom_sysctl_settings.info); | ||
3298 | 3348 | ||
3299 | if (!*lenp || (*ppos && !write)) { | 3349 | if (!*lenp || (*ppos && !write)) { |
3300 | *lenp = 0; | 3350 | *lenp = 0; |
3301 | return 0; | 3351 | return 0; |
3302 | } | 3352 | } |
3303 | 3353 | ||
3354 | mutex_lock(&cdrom_mutex); | ||
3355 | |||
3304 | pos = sprintf(info, "CD-ROM information, " VERSION "\n"); | 3356 | pos = sprintf(info, "CD-ROM information, " VERSION "\n"); |
3305 | 3357 | ||
3306 | pos += sprintf(info+pos, "\ndrive name:\t"); | 3358 | if (cdrom_print_info("\ndrive name:\t", 0, info, &pos, CTL_NAME)) |
3307 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3359 | goto done; |
3308 | pos += sprintf(info+pos, "\t%s", cdi->name); | 3360 | if (cdrom_print_info("\ndrive speed:\t", 0, info, &pos, CTL_SPEED)) |
3309 | 3361 | goto done; | |
3310 | pos += sprintf(info+pos, "\ndrive speed:\t"); | 3362 | if (cdrom_print_info("\ndrive # of slots:", 0, info, &pos, CTL_SLOTS)) |
3311 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3363 | goto done; |
3312 | pos += sprintf(info+pos, "\t%d", cdi->speed); | 3364 | if (cdrom_print_info("\nCan close tray:\t", |
3313 | 3365 | CDC_CLOSE_TRAY, info, &pos, CTL_CAPABILITY)) | |
3314 | pos += sprintf(info+pos, "\ndrive # of slots:"); | 3366 | goto done; |
3315 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3367 | if (cdrom_print_info("\nCan open tray:\t", |
3316 | pos += sprintf(info+pos, "\t%d", cdi->capacity); | 3368 | CDC_OPEN_TRAY, info, &pos, CTL_CAPABILITY)) |
3317 | 3369 | goto done; | |
3318 | pos += sprintf(info+pos, "\nCan close tray:\t"); | 3370 | if (cdrom_print_info("\nCan lock tray:\t", |
3319 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3371 | CDC_LOCK, info, &pos, CTL_CAPABILITY)) |
3320 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CLOSE_TRAY) != 0); | 3372 | goto done; |
3321 | 3373 | if (cdrom_print_info("\nCan change speed:", | |
3322 | pos += sprintf(info+pos, "\nCan open tray:\t"); | 3374 | CDC_SELECT_SPEED, info, &pos, CTL_CAPABILITY)) |
3323 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3375 | goto done; |
3324 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_OPEN_TRAY) != 0); | 3376 | if (cdrom_print_info("\nCan select disk:", |
3325 | 3377 | CDC_SELECT_DISC, info, &pos, CTL_CAPABILITY)) | |
3326 | pos += sprintf(info+pos, "\nCan lock tray:\t"); | 3378 | goto done; |
3327 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3379 | if (cdrom_print_info("\nCan read multisession:", |
3328 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_LOCK) != 0); | 3380 | CDC_MULTI_SESSION, info, &pos, CTL_CAPABILITY)) |
3329 | 3381 | goto done; | |
3330 | pos += sprintf(info+pos, "\nCan change speed:"); | 3382 | if (cdrom_print_info("\nCan read MCN:\t", |
3331 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3383 | CDC_MCN, info, &pos, CTL_CAPABILITY)) |
3332 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_SPEED) != 0); | 3384 | goto done; |
3333 | 3385 | if (cdrom_print_info("\nReports media changed:", | |
3334 | pos += sprintf(info+pos, "\nCan select disk:"); | 3386 | CDC_MEDIA_CHANGED, info, &pos, CTL_CAPABILITY)) |
3335 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3387 | goto done; |
3336 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_DISC) != 0); | 3388 | if (cdrom_print_info("\nCan play audio:\t", |
3337 | 3389 | CDC_PLAY_AUDIO, info, &pos, CTL_CAPABILITY)) | |
3338 | pos += sprintf(info+pos, "\nCan read multisession:"); | 3390 | goto done; |
3339 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3391 | if (cdrom_print_info("\nCan write CD-R:\t", |
3340 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MULTI_SESSION) != 0); | 3392 | CDC_CD_R, info, &pos, CTL_CAPABILITY)) |
3341 | 3393 | goto done; | |
3342 | pos += sprintf(info+pos, "\nCan read MCN:\t"); | 3394 | if (cdrom_print_info("\nCan write CD-RW:", |
3343 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3395 | CDC_CD_RW, info, &pos, CTL_CAPABILITY)) |
3344 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MCN) != 0); | 3396 | goto done; |
3345 | 3397 | if (cdrom_print_info("\nCan read DVD:\t", | |
3346 | pos += sprintf(info+pos, "\nReports media changed:"); | 3398 | CDC_DVD, info, &pos, CTL_CAPABILITY)) |
3347 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3399 | goto done; |
3348 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MEDIA_CHANGED) != 0); | 3400 | if (cdrom_print_info("\nCan write DVD-R:", |
3349 | 3401 | CDC_DVD_R, info, &pos, CTL_CAPABILITY)) | |
3350 | pos += sprintf(info+pos, "\nCan play audio:\t"); | 3402 | goto done; |
3351 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3403 | if (cdrom_print_info("\nCan write DVD-RAM:", |
3352 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_PLAY_AUDIO) != 0); | 3404 | CDC_DVD_RAM, info, &pos, CTL_CAPABILITY)) |
3353 | 3405 | goto done; | |
3354 | pos += sprintf(info+pos, "\nCan write CD-R:\t"); | 3406 | if (cdrom_print_info("\nCan read MRW:\t", |
3355 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3407 | CDC_MRW, info, &pos, CTL_CAPABILITY)) |
3356 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CD_R) != 0); | 3408 | goto done; |
3357 | 3409 | if (cdrom_print_info("\nCan write MRW:\t", | |
3358 | pos += sprintf(info+pos, "\nCan write CD-RW:"); | 3410 | CDC_MRW_W, info, &pos, CTL_CAPABILITY)) |
3359 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3411 | goto done; |
3360 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CD_RW) != 0); | 3412 | if (cdrom_print_info("\nCan write RAM:\t", |
3361 | 3413 | CDC_RAM, info, &pos, CTL_CAPABILITY)) | |
3362 | pos += sprintf(info+pos, "\nCan read DVD:\t"); | 3414 | goto done; |
3363 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3415 | if (!scnprintf(info + pos, max_size - pos, "\n\n")) |
3364 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD) != 0); | 3416 | goto done; |
3365 | 3417 | doit: | |
3366 | pos += sprintf(info+pos, "\nCan write DVD-R:"); | 3418 | mutex_unlock(&cdrom_mutex); |
3367 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3419 | return proc_dostring(ctl, write, filp, buffer, lenp, ppos); |
3368 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_R) != 0); | 3420 | done: |
3369 | 3421 | printk(KERN_INFO "cdrom: info buffer too small\n"); | |
3370 | pos += sprintf(info+pos, "\nCan write DVD-RAM:"); | 3422 | goto doit; |
3371 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3372 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_RAM) != 0); | ||
3373 | |||
3374 | pos += sprintf(info+pos, "\nCan read MRW:\t"); | ||
3375 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3376 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MRW) != 0); | ||
3377 | |||
3378 | pos += sprintf(info+pos, "\nCan write MRW:\t"); | ||
3379 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3380 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MRW_W) != 0); | ||
3381 | |||
3382 | pos += sprintf(info+pos, "\nCan write RAM:\t"); | ||
3383 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3384 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_RAM) != 0); | ||
3385 | |||
3386 | strcpy(info+pos,"\n\n"); | ||
3387 | |||
3388 | return proc_dostring(ctl, write, filp, buffer, lenp, ppos); | ||
3389 | } | 3423 | } |
3390 | 3424 | ||
3391 | /* Unfortunately, per device settings are not implemented through | 3425 | /* Unfortunately, per device settings are not implemented through |