1
0
Fork 0

cdrom: Make device operations read-only

Since function tables are a common target for attackers, it's best to keep
them in read-only memory. As such, this makes the CDROM device ops tables
const. This drops additionally n_minors, since it isn't used meaningfully,
and sets the only user of cdrom_dummy_generic_packet explicitly so the
variables can all be const.

Inspired by similar changes in grsecurity/PaX.

Signed-off-by: Kees Cook <keescook@chromium.org>
Acked-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Jens Axboe <axboe@fb.com>
zero-colors
Kees Cook 2017-02-13 16:25:26 -08:00 committed by Jens Axboe
parent d1a987f35e
commit 853fe1bf75
7 changed files with 37 additions and 45 deletions

View File

@ -249,7 +249,6 @@ struct& cdrom_device_ops\ \{ \hidewidth\cr
unsigned\ long);\cr unsigned\ long);\cr
\noalign{\medskip} \noalign{\medskip}
&const\ int& capability;& capability flags \cr &const\ int& capability;& capability flags \cr
&int& n_minors;& number of active minor devices \cr
\};\cr \};\cr
} }
$$ $$
@ -258,13 +257,7 @@ it should add a function pointer to this $struct$. When a particular
function is not implemented, however, this $struct$ should contain a function is not implemented, however, this $struct$ should contain a
NULL instead. The $capability$ flags specify the capabilities of the NULL instead. The $capability$ flags specify the capabilities of the
\cdrom\ hardware and/or low-level \cdrom\ driver when a \cdrom\ drive \cdrom\ hardware and/or low-level \cdrom\ driver when a \cdrom\ drive
is registered with the \UCD. The value $n_minors$ should be a positive is registered with the \UCD.
value indicating the number of minor devices that are supported by
the low-level device driver, normally~1. Although these two variables
are `informative' rather than `operational,' they are included in
$cdrom_device_ops$ because they describe the capability of the {\em
driver\/} rather than the {\em drive}. Nomenclature has always been
difficult in computer programming.
Note that most functions have fewer parameters than their Note that most functions have fewer parameters than their
$blkdev_fops$ counterparts. This is because very little of the $blkdev_fops$ counterparts. This is because very little of the

View File

@ -273,7 +273,7 @@ static const struct block_device_operations pcd_bdops = {
.check_events = pcd_block_check_events, .check_events = pcd_block_check_events,
}; };
static struct cdrom_device_ops pcd_dops = { static const struct cdrom_device_ops pcd_dops = {
.open = pcd_open, .open = pcd_open,
.release = pcd_release, .release = pcd_release,
.drive_status = pcd_drive_status, .drive_status = pcd_drive_status,

View File

@ -342,8 +342,8 @@ static void cdrom_sysctl_register(void);
static LIST_HEAD(cdrom_list); static LIST_HEAD(cdrom_list);
static int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi, int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi,
struct packet_command *cgc) struct packet_command *cgc)
{ {
if (cgc->sense) { if (cgc->sense) {
cgc->sense->sense_key = 0x05; cgc->sense->sense_key = 0x05;
@ -354,6 +354,7 @@ static int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi,
cgc->stat = -EIO; cgc->stat = -EIO;
return -EIO; return -EIO;
} }
EXPORT_SYMBOL(cdrom_dummy_generic_packet);
static int cdrom_flush_cache(struct cdrom_device_info *cdi) static int cdrom_flush_cache(struct cdrom_device_info *cdi)
{ {
@ -371,7 +372,7 @@ static int cdrom_flush_cache(struct cdrom_device_info *cdi)
static int cdrom_get_disc_info(struct cdrom_device_info *cdi, static int cdrom_get_disc_info(struct cdrom_device_info *cdi,
disc_information *di) disc_information *di)
{ {
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
struct packet_command cgc; struct packet_command cgc;
int ret, buflen; int ret, buflen;
@ -586,7 +587,7 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space)
int register_cdrom(struct cdrom_device_info *cdi) int register_cdrom(struct cdrom_device_info *cdi)
{ {
static char banner_printed; static char banner_printed;
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
int *change_capability = (int *)&cdo->capability; /* hack */ int *change_capability = (int *)&cdo->capability; /* hack */
cd_dbg(CD_OPEN, "entering register_cdrom\n"); cd_dbg(CD_OPEN, "entering register_cdrom\n");
@ -610,7 +611,6 @@ int register_cdrom(struct cdrom_device_info *cdi)
ENSURE(reset, CDC_RESET); ENSURE(reset, CDC_RESET);
ENSURE(generic_packet, CDC_GENERIC_PACKET); ENSURE(generic_packet, CDC_GENERIC_PACKET);
cdi->mc_flags = 0; cdi->mc_flags = 0;
cdo->n_minors = 0;
cdi->options = CDO_USE_FFLAGS; cdi->options = CDO_USE_FFLAGS;
if (autoclose == 1 && CDROM_CAN(CDC_CLOSE_TRAY)) if (autoclose == 1 && CDROM_CAN(CDC_CLOSE_TRAY))
@ -630,8 +630,7 @@ int register_cdrom(struct cdrom_device_info *cdi)
else else
cdi->cdda_method = CDDA_OLD; cdi->cdda_method = CDDA_OLD;
if (!cdo->generic_packet) WARN_ON(!cdo->generic_packet);
cdo->generic_packet = cdrom_dummy_generic_packet;
cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
mutex_lock(&cdrom_mutex); mutex_lock(&cdrom_mutex);
@ -652,7 +651,6 @@ void unregister_cdrom(struct cdrom_device_info *cdi)
if (cdi->exit) if (cdi->exit)
cdi->exit(cdi); cdi->exit(cdi);
cdi->ops->n_minors--;
cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name); cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name);
} }
@ -1036,7 +1034,7 @@ static
int open_for_data(struct cdrom_device_info *cdi) int open_for_data(struct cdrom_device_info *cdi)
{ {
int ret; int ret;
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
tracktype tracks; tracktype tracks;
cd_dbg(CD_OPEN, "entering open_for_data\n"); cd_dbg(CD_OPEN, "entering open_for_data\n");
/* Check if the driver can report drive status. If it can, we /* Check if the driver can report drive status. If it can, we
@ -1198,8 +1196,8 @@ err:
/* This code is similar to that in open_for_data. The routine is called /* This code is similar to that in open_for_data. The routine is called
whenever an audio play operation is requested. whenever an audio play operation is requested.
*/ */
static int check_for_audio_disc(struct cdrom_device_info * cdi, static int check_for_audio_disc(struct cdrom_device_info *cdi,
struct cdrom_device_ops * cdo) const struct cdrom_device_ops *cdo)
{ {
int ret; int ret;
tracktype tracks; tracktype tracks;
@ -1254,7 +1252,7 @@ static int check_for_audio_disc(struct cdrom_device_info * cdi,
void cdrom_release(struct cdrom_device_info *cdi, fmode_t mode) void cdrom_release(struct cdrom_device_info *cdi, fmode_t mode)
{ {
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
int opened_for_data; int opened_for_data;
cd_dbg(CD_CLOSE, "entering cdrom_release\n"); cd_dbg(CD_CLOSE, "entering cdrom_release\n");
@ -1294,7 +1292,7 @@ static int cdrom_read_mech_status(struct cdrom_device_info *cdi,
struct cdrom_changer_info *buf) struct cdrom_changer_info *buf)
{ {
struct packet_command cgc; struct packet_command cgc;
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
int length; int length;
/* /*
@ -1643,7 +1641,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
int ret; int ret;
u_char buf[20]; u_char buf[20];
struct packet_command cgc; struct packet_command cgc;
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
rpc_state_t rpc_state; rpc_state_t rpc_state;
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
@ -1791,7 +1789,7 @@ static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s,
{ {
unsigned char buf[21], *base; unsigned char buf[21], *base;
struct dvd_layer *layer; struct dvd_layer *layer;
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
int ret, layer_num = s->physical.layer_num; int ret, layer_num = s->physical.layer_num;
if (layer_num >= DVD_LAYERS) if (layer_num >= DVD_LAYERS)
@ -1842,7 +1840,7 @@ static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s,
{ {
int ret; int ret;
u_char buf[8]; u_char buf[8];
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
init_cdrom_command(cgc, buf, sizeof(buf), CGC_DATA_READ); init_cdrom_command(cgc, buf, sizeof(buf), CGC_DATA_READ);
cgc->cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc->cmd[0] = GPCMD_READ_DVD_STRUCTURE;
@ -1866,7 +1864,7 @@ static int dvd_read_disckey(struct cdrom_device_info *cdi, dvd_struct *s,
{ {
int ret, size; int ret, size;
u_char *buf; u_char *buf;
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
size = sizeof(s->disckey.value) + 4; size = sizeof(s->disckey.value) + 4;
@ -1894,7 +1892,7 @@ static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s,
{ {
int ret, size = 4 + 188; int ret, size = 4 + 188;
u_char *buf; u_char *buf;
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
buf = kmalloc(size, GFP_KERNEL); buf = kmalloc(size, GFP_KERNEL);
if (!buf) if (!buf)
@ -1928,7 +1926,7 @@ static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s,
{ {
int ret = 0, size; int ret = 0, size;
u_char *buf; u_char *buf;
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
size = sizeof(s->manufact.value) + 4; size = sizeof(s->manufact.value) + 4;
@ -1995,7 +1993,7 @@ int cdrom_mode_sense(struct cdrom_device_info *cdi,
struct packet_command *cgc, struct packet_command *cgc,
int page_code, int page_control) int page_code, int page_control)
{ {
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
memset(cgc->cmd, 0, sizeof(cgc->cmd)); memset(cgc->cmd, 0, sizeof(cgc->cmd));
@ -2010,7 +2008,7 @@ int cdrom_mode_sense(struct cdrom_device_info *cdi,
int cdrom_mode_select(struct cdrom_device_info *cdi, int cdrom_mode_select(struct cdrom_device_info *cdi,
struct packet_command *cgc) struct packet_command *cgc)
{ {
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
memset(cgc->cmd, 0, sizeof(cgc->cmd)); memset(cgc->cmd, 0, sizeof(cgc->cmd));
memset(cgc->buffer, 0, 2); memset(cgc->buffer, 0, 2);
@ -2025,7 +2023,7 @@ int cdrom_mode_select(struct cdrom_device_info *cdi,
static int cdrom_read_subchannel(struct cdrom_device_info *cdi, static int cdrom_read_subchannel(struct cdrom_device_info *cdi,
struct cdrom_subchnl *subchnl, int mcn) struct cdrom_subchnl *subchnl, int mcn)
{ {
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
struct packet_command cgc; struct packet_command cgc;
char buffer[32]; char buffer[32];
int ret; int ret;
@ -2073,7 +2071,7 @@ static int cdrom_read_cd(struct cdrom_device_info *cdi,
struct packet_command *cgc, int lba, struct packet_command *cgc, int lba,
int blocksize, int nblocks) int blocksize, int nblocks)
{ {
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
memset(&cgc->cmd, 0, sizeof(cgc->cmd)); memset(&cgc->cmd, 0, sizeof(cgc->cmd));
cgc->cmd[0] = GPCMD_READ_10; cgc->cmd[0] = GPCMD_READ_10;
@ -2093,7 +2091,7 @@ static int cdrom_read_block(struct cdrom_device_info *cdi,
struct packet_command *cgc, struct packet_command *cgc,
int lba, int nblocks, int format, int blksize) int lba, int nblocks, int format, int blksize)
{ {
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
memset(&cgc->cmd, 0, sizeof(cgc->cmd)); memset(&cgc->cmd, 0, sizeof(cgc->cmd));
cgc->cmd[0] = GPCMD_READ_CD; cgc->cmd[0] = GPCMD_READ_CD;
@ -2764,7 +2762,7 @@ static int cdrom_ioctl_audioctl(struct cdrom_device_info *cdi,
*/ */
static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size) static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size)
{ {
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
struct packet_command cgc; struct packet_command cgc;
struct modesel_head mh; struct modesel_head mh;
@ -2790,7 +2788,7 @@ static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size)
static int cdrom_get_track_info(struct cdrom_device_info *cdi, static int cdrom_get_track_info(struct cdrom_device_info *cdi,
__u16 track, __u8 type, track_information *ti) __u16 track, __u8 type, track_information *ti)
{ {
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
struct packet_command cgc; struct packet_command cgc;
int ret, buflen; int ret, buflen;
@ -3049,7 +3047,7 @@ static noinline int mmc_ioctl_cdrom_play_msf(struct cdrom_device_info *cdi,
void __user *arg, void __user *arg,
struct packet_command *cgc) struct packet_command *cgc)
{ {
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
struct cdrom_msf msf; struct cdrom_msf msf;
cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYMSF\n");
if (copy_from_user(&msf, (struct cdrom_msf __user *)arg, sizeof(msf))) if (copy_from_user(&msf, (struct cdrom_msf __user *)arg, sizeof(msf)))
@ -3069,7 +3067,7 @@ static noinline int mmc_ioctl_cdrom_play_blk(struct cdrom_device_info *cdi,
void __user *arg, void __user *arg,
struct packet_command *cgc) struct packet_command *cgc)
{ {
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
struct cdrom_blk blk; struct cdrom_blk blk;
cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYBLK\n"); cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYBLK\n");
if (copy_from_user(&blk, (struct cdrom_blk __user *)arg, sizeof(blk))) if (copy_from_user(&blk, (struct cdrom_blk __user *)arg, sizeof(blk)))
@ -3164,7 +3162,7 @@ static noinline int mmc_ioctl_cdrom_start_stop(struct cdrom_device_info *cdi,
struct packet_command *cgc, struct packet_command *cgc,
int cmd) int cmd)
{ {
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
cd_dbg(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n"); cd_dbg(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n");
cgc->cmd[0] = GPCMD_START_STOP_UNIT; cgc->cmd[0] = GPCMD_START_STOP_UNIT;
cgc->cmd[1] = 1; cgc->cmd[1] = 1;
@ -3177,7 +3175,7 @@ static noinline int mmc_ioctl_cdrom_pause_resume(struct cdrom_device_info *cdi,
struct packet_command *cgc, struct packet_command *cgc,
int cmd) int cmd)
{ {
struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
cd_dbg(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n"); cd_dbg(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n");
cgc->cmd[0] = GPCMD_PAUSE_RESUME; cgc->cmd[0] = GPCMD_PAUSE_RESUME;
cgc->cmd[8] = (cmd == CDROMRESUME) ? 1 : 0; cgc->cmd[8] = (cmd == CDROMRESUME) ? 1 : 0;

View File

@ -481,7 +481,7 @@ static int gdrom_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
return -EINVAL; return -EINVAL;
} }
static struct cdrom_device_ops gdrom_ops = { static const struct cdrom_device_ops gdrom_ops = {
.open = gdrom_open, .open = gdrom_open,
.release = gdrom_release, .release = gdrom_release,
.drive_status = gdrom_drivestatus, .drive_status = gdrom_drivestatus,
@ -489,9 +489,9 @@ static struct cdrom_device_ops gdrom_ops = {
.get_last_session = gdrom_get_last_session, .get_last_session = gdrom_get_last_session,
.reset = gdrom_hardreset, .reset = gdrom_hardreset,
.audio_ioctl = gdrom_audio_ioctl, .audio_ioctl = gdrom_audio_ioctl,
.generic_packet = cdrom_dummy_generic_packet,
.capability = CDC_MULTI_SESSION | CDC_MEDIA_CHANGED | .capability = CDC_MULTI_SESSION | CDC_MEDIA_CHANGED |
CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R, CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R,
.n_minors = 1,
}; };
static int gdrom_bdops_open(struct block_device *bdev, fmode_t mode) static int gdrom_bdops_open(struct block_device *bdev, fmode_t mode)

View File

@ -1166,7 +1166,7 @@ void ide_cdrom_update_speed(ide_drive_t *drive, u8 *buf)
CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_GENERIC_PACKET | \ CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_GENERIC_PACKET | \
CDC_MO_DRIVE | CDC_MRW | CDC_MRW_W | CDC_RAM) CDC_MO_DRIVE | CDC_MRW | CDC_MRW_W | CDC_RAM)
static struct cdrom_device_ops ide_cdrom_dops = { static const struct cdrom_device_ops ide_cdrom_dops = {
.open = ide_cdrom_open_real, .open = ide_cdrom_open_real,
.release = ide_cdrom_release_real, .release = ide_cdrom_release_real,
.drive_status = ide_cdrom_drive_status, .drive_status = ide_cdrom_drive_status,

View File

@ -117,7 +117,7 @@ static unsigned int sr_check_events(struct cdrom_device_info *cdi,
unsigned int clearing, int slot); unsigned int clearing, int slot);
static int sr_packet(struct cdrom_device_info *, struct packet_command *); static int sr_packet(struct cdrom_device_info *, struct packet_command *);
static struct cdrom_device_ops sr_dops = { static const struct cdrom_device_ops sr_dops = {
.open = sr_open, .open = sr_open,
.release = sr_release, .release = sr_release,
.drive_status = sr_drive_status, .drive_status = sr_drive_status,

View File

@ -36,7 +36,7 @@ struct packet_command
/* Uniform cdrom data structures for cdrom.c */ /* Uniform cdrom data structures for cdrom.c */
struct cdrom_device_info { struct cdrom_device_info {
struct cdrom_device_ops *ops; /* link to device_ops */ const struct cdrom_device_ops *ops; /* link to device_ops */
struct list_head list; /* linked list of all device_info */ struct list_head list; /* linked list of all device_info */
struct gendisk *disk; /* matching block layer disk */ struct gendisk *disk; /* matching block layer disk */
void *handle; /* driver-dependent data */ void *handle; /* driver-dependent data */
@ -87,7 +87,6 @@ struct cdrom_device_ops {
/* driver specifications */ /* driver specifications */
const int capability; /* capability flags */ const int capability; /* capability flags */
int n_minors; /* number of active minor devices */
/* handle uniform packets for scsi type devices (scsi,atapi) */ /* handle uniform packets for scsi type devices (scsi,atapi) */
int (*generic_packet) (struct cdrom_device_info *, int (*generic_packet) (struct cdrom_device_info *,
struct packet_command *); struct packet_command *);
@ -123,6 +122,8 @@ extern int cdrom_mode_sense(struct cdrom_device_info *cdi,
int page_code, int page_control); int page_code, int page_control);
extern void init_cdrom_command(struct packet_command *cgc, extern void init_cdrom_command(struct packet_command *cgc,
void *buffer, int len, int type); void *buffer, int len, int type);
extern int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi,
struct packet_command *cgc);
/* The SCSI spec says there could be 256 slots. */ /* The SCSI spec says there could be 256 slots. */
#define CDROM_MAX_SLOTS 256 #define CDROM_MAX_SLOTS 256