Author: avg
Date: Thu Feb 15 15:33:17 2018
New Revision: 329316
URL: https://svnweb.freebsd.org/changeset/base/329316

Log:
  MFC r327996: 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

Modified:
  stable/11/sys/cam/scsi/scsi_da.c
  stable/11/sys/geom/geom_disk.c
  stable/11/sys/geom/geom_disk.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/cam/scsi/scsi_da.c
==============================================================================
--- stable/11/sys/cam/scsi/scsi_da.c    Thu Feb 15 15:01:07 2018        
(r329315)
+++ stable/11/sys/cam/scsi/scsi_da.c    Thu Feb 15 15:33:17 2018        
(r329316)
@@ -79,6 +79,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,
@@ -155,6 +156,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;
@@ -2402,7 +2404,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;
@@ -2506,7 +2508,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;
        }
 
        /*
@@ -3070,6 +3071,36 @@ out:
                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;
@@ -4219,6 +4250,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:
        {
@@ -5286,11 +5363,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);
 }
 

Modified: stable/11/sys/geom/geom_disk.c
==============================================================================
--- stable/11/sys/geom/geom_disk.c      Thu Feb 15 15:01:07 2018        
(r329315)
+++ stable/11/sys/geom/geom_disk.c      Thu Feb 15 15:33:17 2018        
(r329316)
@@ -118,14 +118,18 @@ g_disk_access(struct g_provider *pp, int r, int w, int
        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",

Modified: stable/11/sys/geom/geom_disk.h
==============================================================================
--- stable/11/sys/geom/geom_disk.h      Thu Feb 15 15:01:07 2018        
(r329315)
+++ stable/11/sys/geom/geom_disk.h      Thu Feb 15 15:33:17 2018        
(r329316)
@@ -116,13 +116,14 @@ struct disk {
        void                    *d_drv1;
 };
 
-#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);
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to