geom_disk / scsi_da: deny opening write-protected disks for writing
Ths change consists of two parts. geom_disk: deny opening a disk for writing if it's marked as write-protected. A new disk(9) flag is added to mark write protected disks. A possible alternative could be to add another parameter to d_open, so that the open mode could be passed to it and the disk drivers could make the decision internally, but the flag required less churn. scsi_da: add a new phase of disk probing to query the all pages mode sense page. We can determine if the disk is write protected using bit 7 of the device specific field in the mode parameter header returned by MODE SENSE. PR: 224037 Reviewed by: mav MFC after: 4 weeks Differential Revision: https://reviews.freebsd.org/D13360
This commit is contained in:
parent
a826eb5a41
commit
6ce374aa94
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=327996
@ -81,6 +81,7 @@ __FBSDID("$FreeBSD$");
|
||||
* ATA -> LOGDIR -> IDDIR -> SUP -> ATA_ZONE
|
||||
*/
|
||||
typedef enum {
|
||||
DA_STATE_PROBE_WP,
|
||||
DA_STATE_PROBE_RC,
|
||||
DA_STATE_PROBE_RC16,
|
||||
DA_STATE_PROBE_LBP,
|
||||
@ -157,6 +158,7 @@ typedef enum {
|
||||
DA_CCB_PROBE_ATA_IDDIR = 0x0F,
|
||||
DA_CCB_PROBE_ATA_SUP = 0x10,
|
||||
DA_CCB_PROBE_ATA_ZONE = 0x11,
|
||||
DA_CCB_PROBE_WP = 0x12,
|
||||
DA_CCB_TYPE_MASK = 0x1F,
|
||||
DA_CCB_RETRY_UA = 0x20
|
||||
} da_ccb_state;
|
||||
@ -2427,7 +2429,7 @@ daregister(struct cam_periph *periph, void *arg)
|
||||
}
|
||||
|
||||
LIST_INIT(&softc->pending_ccbs);
|
||||
softc->state = DA_STATE_PROBE_RC;
|
||||
softc->state = DA_STATE_PROBE_WP;
|
||||
bioq_init(&softc->delete_run_queue);
|
||||
if (SID_IS_REMOVABLE(&cgd->inq_data))
|
||||
softc->flags |= DA_FLAG_PACK_REMOVABLE;
|
||||
@ -2526,7 +2528,6 @@ daregister(struct cam_periph *periph, void *arg)
|
||||
if (SID_ANSI_REV(&cgd->inq_data) >= SCSI_REV_SPC3 &&
|
||||
(softc->quirks & DA_Q_NO_RC16) == 0) {
|
||||
softc->flags |= DA_FLAG_CAN_RC16;
|
||||
softc->state = DA_STATE_PROBE_RC16;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3095,6 +3096,36 @@ dastart(struct cam_periph *periph, union ccb *start_ccb)
|
||||
daschedule(periph);
|
||||
break;
|
||||
}
|
||||
case DA_STATE_PROBE_WP:
|
||||
{
|
||||
void *mode_buf;
|
||||
int mode_buf_len;
|
||||
|
||||
mode_buf_len = 192;
|
||||
mode_buf = malloc(mode_buf_len, M_SCSIDA, M_NOWAIT);
|
||||
if (mode_buf == NULL) {
|
||||
xpt_print(periph->path, "Unable to send mode sense - "
|
||||
"malloc failure\n");
|
||||
softc->state = DA_STATE_PROBE_RC;
|
||||
goto skipstate;
|
||||
}
|
||||
scsi_mode_sense_len(&start_ccb->csio,
|
||||
/*retries*/ da_retry_count,
|
||||
/*cbfcnp*/ dadone,
|
||||
/*tag_action*/ MSG_SIMPLE_Q_TAG,
|
||||
/*dbd*/ FALSE,
|
||||
/*pc*/ SMS_PAGE_CTRL_CURRENT,
|
||||
/*page*/ SMS_ALL_PAGES_PAGE,
|
||||
/*param_buf*/ mode_buf,
|
||||
/*param_len*/ mode_buf_len,
|
||||
/*minimum_cmd_size*/ softc->minimum_cmd_size,
|
||||
/*sense_len*/ SSD_FULL_SIZE,
|
||||
/*timeout*/ da_default_timeout * 1000);
|
||||
start_ccb->ccb_h.ccb_bp = NULL;
|
||||
start_ccb->ccb_h.ccb_state = DA_CCB_PROBE_WP;
|
||||
xpt_action(start_ccb);
|
||||
break;
|
||||
}
|
||||
case DA_STATE_PROBE_RC:
|
||||
{
|
||||
struct scsi_read_capacity_data *rcap;
|
||||
@ -4255,6 +4286,52 @@ dadone(struct cam_periph *periph, union ccb *done_ccb)
|
||||
biodone(bp);
|
||||
return;
|
||||
}
|
||||
case DA_CCB_PROBE_WP:
|
||||
{
|
||||
struct scsi_mode_header_6 *mode_hdr6;
|
||||
struct scsi_mode_header_10 *mode_hdr10;
|
||||
uint8_t dev_spec;
|
||||
|
||||
if (softc->minimum_cmd_size > 6) {
|
||||
mode_hdr10 = (struct scsi_mode_header_10 *)csio->data_ptr;
|
||||
dev_spec = mode_hdr10->dev_spec;
|
||||
} else {
|
||||
mode_hdr6 = (struct scsi_mode_header_6 *)csio->data_ptr;
|
||||
dev_spec = mode_hdr6->dev_spec;
|
||||
}
|
||||
if (cam_ccb_status(done_ccb) == CAM_REQ_CMP) {
|
||||
if ((dev_spec & 0x80) != 0)
|
||||
softc->disk->d_flags |= DISKFLAG_WRITE_PROTECT;
|
||||
else
|
||||
softc->disk->d_flags &= ~DISKFLAG_WRITE_PROTECT;
|
||||
} else {
|
||||
int error;
|
||||
|
||||
error = daerror(done_ccb, CAM_RETRY_SELTO,
|
||||
SF_RETRY_UA|SF_NO_PRINT);
|
||||
if (error == ERESTART)
|
||||
return;
|
||||
else if (error != 0) {
|
||||
if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
|
||||
/* Don't wedge this device's queue */
|
||||
cam_release_devq(done_ccb->ccb_h.path,
|
||||
/*relsim_flags*/0,
|
||||
/*reduction*/0,
|
||||
/*timeout*/0,
|
||||
/*getcount_only*/0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(csio->data_ptr, M_SCSIDA);
|
||||
xpt_release_ccb(done_ccb);
|
||||
if ((softc->flags & DA_FLAG_CAN_RC16) != 0)
|
||||
softc->state = DA_STATE_PROBE_RC16;
|
||||
else
|
||||
softc->state = DA_STATE_PROBE_RC;
|
||||
xpt_schedule(periph, priority);
|
||||
return;
|
||||
}
|
||||
case DA_CCB_PROBE_RC:
|
||||
case DA_CCB_PROBE_RC16:
|
||||
{
|
||||
@ -5340,11 +5417,7 @@ dareprobe(struct cam_periph *periph)
|
||||
KASSERT(status == CAM_REQ_CMP,
|
||||
("dareprobe: cam_periph_acquire failed"));
|
||||
|
||||
if (softc->flags & DA_FLAG_CAN_RC16)
|
||||
softc->state = DA_STATE_PROBE_RC16;
|
||||
else
|
||||
softc->state = DA_STATE_PROBE_RC;
|
||||
|
||||
softc->state = DA_STATE_PROBE_WP;
|
||||
xpt_schedule(periph, CAM_PRIORITY_DEV);
|
||||
}
|
||||
|
||||
|
@ -122,14 +122,18 @@ g_disk_access(struct g_provider *pp, int r, int w, int e)
|
||||
e += pp->ace;
|
||||
error = 0;
|
||||
if ((pp->acr + pp->acw + pp->ace) == 0 && (r + w + e) > 0) {
|
||||
if (dp->d_open != NULL) {
|
||||
/*
|
||||
* It would be better to defer this decision to d_open if
|
||||
* it was able to take flags.
|
||||
*/
|
||||
if (w > 0 && (dp->d_flags & DISKFLAG_WRITE_PROTECT) != 0)
|
||||
error = EROFS;
|
||||
if (error == 0 && dp->d_open != NULL)
|
||||
error = dp->d_open(dp);
|
||||
if (bootverbose && error != 0)
|
||||
printf("Opened disk %s -> %d\n",
|
||||
pp->name, error);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
}
|
||||
if (bootverbose && error != 0)
|
||||
printf("Opened disk %s -> %d\n", pp->name, error);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
pp->sectorsize = dp->d_sectorsize;
|
||||
if (dp->d_maxsize == 0) {
|
||||
printf("WARNING: Disk drive %s%d has no d_maxsize\n",
|
||||
@ -1043,7 +1047,8 @@ g_disk_sysctl_flags(SYSCTL_HANDLER_ARGS)
|
||||
"\4CANFLUSHCACHE"
|
||||
"\5UNMAPPEDBIO"
|
||||
"\6DIRECTCOMPLETION"
|
||||
"\10CANZONE");
|
||||
"\10CANZONE"
|
||||
"\11WRITEPROTECT");
|
||||
|
||||
sbuf_finish(sb);
|
||||
error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1);
|
||||
|
@ -126,13 +126,14 @@ struct disk {
|
||||
LIST_HEAD(,disk_alias) d_aliases;
|
||||
};
|
||||
|
||||
#define DISKFLAG_RESERVED 0x1 /* Was NEEDSGIANT */
|
||||
#define DISKFLAG_OPEN 0x2
|
||||
#define DISKFLAG_CANDELETE 0x4
|
||||
#define DISKFLAG_CANFLUSHCACHE 0x8
|
||||
#define DISKFLAG_UNMAPPED_BIO 0x10
|
||||
#define DISKFLAG_DIRECT_COMPLETION 0x20
|
||||
#define DISKFLAG_CANZONE 0x80
|
||||
#define DISKFLAG_RESERVED 0x0001 /* Was NEEDSGIANT */
|
||||
#define DISKFLAG_OPEN 0x0002
|
||||
#define DISKFLAG_CANDELETE 0x0004
|
||||
#define DISKFLAG_CANFLUSHCACHE 0x0008
|
||||
#define DISKFLAG_UNMAPPED_BIO 0x0010
|
||||
#define DISKFLAG_DIRECT_COMPLETION 0x0020
|
||||
#define DISKFLAG_CANZONE 0x0080
|
||||
#define DISKFLAG_WRITE_PROTECT 0x0100
|
||||
|
||||
struct disk *disk_alloc(void);
|
||||
void disk_create(struct disk *disk, int version);
|
||||
|
Loading…
Reference in New Issue
Block a user