summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkrw <krw@openbsd.org>2010-12-24 02:45:33 +0000
committerkrw <krw@openbsd.org>2010-12-24 02:45:33 +0000
commit427418b6e37a307425ace187dff89b00520b45c4 (patch)
treeb7b735d9e3b16b27b6addf950be795bd95181e47
parentserver_kill_window can modify the RB tree so don't use RB_FOREACH, fixes (diff)
downloadwireguard-openbsd-427418b6e37a307425ace187dff89b00520b45c4.tar.xz
wireguard-openbsd-427418b6e37a307425ace187dff89b00520b45c4.zip
Have sd(4) devices check for and respect read-only information the
way st(4) does. Have both decline to open read-only devices for anything but read-only access. Suggestion to fail opens rather than individual i/o's from deraadt@. Problem USB device found and donated by chefren, who also tested diffs. Thanks! ok dlg@ marco@
-rw-r--r--sys/scsi/scsi_all.h5
-rw-r--r--sys/scsi/scsi_tape.h3
-rw-r--r--sys/scsi/scsiconf.h3
-rw-r--r--sys/scsi/sd.c35
-rw-r--r--sys/scsi/st.c22
5 files changed, 47 insertions, 21 deletions
diff --git a/sys/scsi/scsi_all.h b/sys/scsi/scsi_all.h
index bd3690bf6d8..f8399c40652 100644
--- a/sys/scsi/scsi_all.h
+++ b/sys/scsi/scsi_all.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsi_all.h,v 1.51 2010/09/02 11:54:44 dlg Exp $ */
+/* $OpenBSD: scsi_all.h,v 1.52 2010/12/24 02:45:33 krw Exp $ */
/* $NetBSD: scsi_all.h,v 1.10 1996/09/12 01:57:17 thorpej Exp $ */
/*
@@ -431,6 +431,9 @@ struct scsi_mode_header_big {
u_int8_t blk_desc_len[2];
};
+/* Both disks and tapes use dev_spec to report READONLY status. */
+#define SMH_DSP_WRITE_PROT 0x80
+
union scsi_mode_sense_buf {
struct scsi_mode_header hdr;
struct scsi_mode_header_big hdr_big;
diff --git a/sys/scsi/scsi_tape.h b/sys/scsi/scsi_tape.h
index cc6f8570f73..b80f8d95609 100644
--- a/sys/scsi/scsi_tape.h
+++ b/sys/scsi/scsi_tape.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsi_tape.h,v 1.7 1998/01/07 17:28:38 deraadt Exp $ */
+/* $OpenBSD: scsi_tape.h,v 1.8 2010/12/24 02:45:33 krw Exp $ */
/* $NetBSD: scsi_tape.h,v 1.9 1996/05/24 02:04:47 thorpej Exp $ */
/*
@@ -173,7 +173,6 @@ struct scsi_tape_dev_conf_page {
#define SMH_DSP_BUFF_MODE_OFF 0x00
#define SMH_DSP_BUFF_MODE_ON 0x10
#define SMH_DSP_BUFF_MODE_MLTI 0x20
-#define SMH_DSP_WRITE_PROT 0x80
/* A special for the CIPHER ST150S(old drive) */
struct block_desc_cipher {
diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h
index 3b98b3e50ad..73a67f13c19 100644
--- a/sys/scsi/scsiconf.h
+++ b/sys/scsi/scsiconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsiconf.h,v 1.141 2010/10/12 00:53:32 krw Exp $ */
+/* $OpenBSD: scsiconf.h,v 1.142 2010/12/24 02:45:33 krw Exp $ */
/* $NetBSD: scsiconf.h,v 1.35 1997/04/02 02:29:38 mycroft Exp $ */
/*
@@ -367,6 +367,7 @@ struct scsi_link {
u_int16_t flags; /* flags that all devices have */
#define SDEV_REMOVABLE 0x0001 /* media is removable */
#define SDEV_MEDIA_LOADED 0x0002 /* device figures are still valid */
+#define SDEV_READONLY 0x0004 /* device is read-only */
#define SDEV_OPEN 0x0008 /* at least 1 open session */
#define SDEV_DBX 0x00f0 /* debugging flags (scsi_debug.h) */
#define SDEV_EJECTING 0x0100 /* eject on device close */
diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c
index 74f6a87db2f..d83f33ff0d1 100644
--- a/sys/scsi/sd.c
+++ b/sys/scsi/sd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sd.c,v 1.218 2010/09/24 01:41:34 dlg Exp $ */
+/* $OpenBSD: sd.c,v 1.219 2010/12/24 02:45:33 krw Exp $ */
/* $NetBSD: sd.c,v 1.111 1997/04/02 02:29:41 mycroft Exp $ */
/*-
@@ -343,12 +343,17 @@ sdopen(dev_t dev, int flag, int fmt, struct proc *p)
sc = sdlookup(unit);
if (sc == NULL)
return (ENXIO);
+ sc_link = sc->sc_link;
+
if (sc->flags & SDF_DYING) {
device_unref(&sc->sc_dev);
return (ENXIO);
}
+ if (ISSET(flag, FWRITE) && ISSET(sc_link->flags, SDEV_READONLY)) {
+ device_unref(&sc->sc_dev);
+ return (EACCES);
+ }
- sc_link = sc->sc_link;
SC_DEBUG(sc_link, SDEV_DB1,
("sdopen: dev=0x%x (unit %d (of %d), partition %d)\n", dev, unit,
sd_cd.cd_ndevs, part));
@@ -1403,21 +1408,37 @@ sd_get_parms(struct sd_softc *sc, struct disk_parms *dp, int flags)
struct page_rigid_geometry *rigid = NULL;
struct page_flex_geometry *flex = NULL;
struct page_reduced_geometry *reduced = NULL;
+ u_char *page0 = NULL;
u_int32_t heads = 0, sectors = 0, cyls = 0, secsize = 0, sssecsize;
- int err = 0;
+ int err = 0, big;
dp->disksize = scsi_size(sc->sc_link, flags, &sssecsize);
+ buf = malloc(sizeof(*buf), M_TEMP, M_NOWAIT);
+ if (buf == NULL)
+ goto validate;
+
+ /*
+ * Ask for page 0 (vendor specific) mode sense data to find
+ * READONLY info. The only thing USB devices will ask for.
+ */
+ err = scsi_do_mode_sense(sc->sc_link, 0, buf, (void **)&page0,
+ NULL, NULL, NULL, 1, flags | SCSI_SILENT, &big);
+ if (err == 0) {
+ if (big && buf->hdr_big.dev_spec & SMH_DSP_WRITE_PROT)
+ SET(sc->sc_link->flags, SDEV_READONLY);
+ else if (!big && buf->hdr.dev_spec & SMH_DSP_WRITE_PROT)
+ SET(sc->sc_link->flags, SDEV_READONLY);
+ else
+ CLR(sc->sc_link->flags, SDEV_READONLY);
+ }
+
/*
* Many UMASS devices choke when asked about their geometry. Most
* don't have a meaningful geometry anyway, so just fake it if
* scsi_size() worked.
*/
if ((sc->sc_link->flags & SDEV_UMASS) && (dp->disksize > 0))
- goto validate; /* N.B. buf will be NULL at validate. */
-
- buf = malloc(sizeof(*buf), M_TEMP, M_NOWAIT);
- if (buf == NULL)
goto validate;
switch (sc->sc_link->inqdata.device & SID_TYPE) {
diff --git a/sys/scsi/st.c b/sys/scsi/st.c
index 219b4383338..f5323b61eb0 100644
--- a/sys/scsi/st.c
+++ b/sys/scsi/st.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: st.c,v 1.115 2010/10/13 02:14:52 krw Exp $ */
+/* $OpenBSD: st.c,v 1.116 2010/12/24 02:45:33 krw Exp $ */
/* $NetBSD: st.c,v 1.71 1997/02/21 23:03:49 thorpej Exp $ */
/*
@@ -262,7 +262,6 @@ struct cfdriver st_cd = {
#define ST_FIXEDBLOCKS 0x0008
#define ST_AT_FILEMARK 0x0010
#define ST_EIO_PENDING 0x0020 /* we couldn't report it then (had data) */
-#define ST_READONLY 0x0080 /* st_mode_sense says write protected */
#define ST_FM_WRITTEN 0x0100 /*
* EOF file mark written -- used with
* ~ST_WRITTEN to indicate that multiple file
@@ -276,9 +275,6 @@ struct cfdriver st_cd = {
#define ST_WAITING 0x2000
#define ST_PER_ACTION (ST_AT_FILEMARK | ST_EIO_PENDING | ST_BLANK_READ)
-#define ST_PER_MOUNT (ST_INFO_VALID | ST_BLOCK_SET | ST_WRITTEN | \
- ST_FIXEDBLOCKS | ST_READONLY | ST_FM_WRITTEN | \
- ST_2FM_AT_EOD | ST_PER_ACTION)
#define stlookup(unit) (struct st_softc *)device_lookup(&st_cd, (unit))
@@ -457,11 +453,16 @@ stopen(dev_t dev, int flags, int fmt, struct proc *p)
st = stlookup(STUNIT(dev));
if (st == NULL)
return (ENXIO);
+ sc_link = st->sc_link;
+
if (st->flags & ST_DYING) {
error = ENXIO;
goto done;
}
- sc_link = st->sc_link;
+ if (ISSET(flags, FWRITE) && ISSET(sc_link->flags, SDEV_READONLY)) {
+ error = EACCES;
+ goto done;
+ }
SC_DEBUG(sc_link, SDEV_DB1, ("open: dev=0x%x (unit %d (of %d))\n", dev,
STUNIT(dev), st_cd.cd_ndevs));
@@ -836,6 +837,7 @@ ststrategy(struct buf *bp)
bp->b_error = ENXIO;
goto bad;
}
+
sc_link = st->sc_link;
SC_DEBUG(sc_link, SDEV_DB2, ("ststrategy: %ld bytes @ blk %d\n",
@@ -1205,7 +1207,7 @@ stioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
g->mt_density = st->density;
g->mt_mblksiz = st->modes.blksize;
g->mt_mdensity = st->modes.density;
- if (st->flags & ST_READONLY)
+ if (st->sc_link->flags & SDEV_READONLY)
g->mt_dsreg |= MT_DS_RDONLY;
if (st->flags & ST_MOUNTED)
g->mt_dsreg |= MT_DS_MOUNTED;
@@ -1483,9 +1485,9 @@ st_mode_sense(struct st_softc *st, int flags)
dev_spec = data->hdr.dev_spec;
if (dev_spec & SMH_DSP_WRITE_PROT)
- st->flags |= ST_READONLY;
+ SET(sc_link->flags, SDEV_READONLY);
else
- st->flags &= ~ST_READONLY;
+ CLR(sc_link->flags, SDEV_READONLY);
st->numblks = block_count;
st->media_blksize = block_size;
@@ -1494,7 +1496,7 @@ st_mode_sense(struct st_softc *st, int flags)
SC_DEBUG(sc_link, SDEV_DB3,
("density code 0x%x, %d-byte blocks, write-%s, ",
st->media_density, st->media_blksize,
- st->flags & ST_READONLY ? "protected" : "enabled"));
+ sc_link->flags & SDEV_READONLY ? "protected" : "enabled"));
SC_DEBUGN(sc_link, SDEV_DB3,
("%sbuffered\n", dev_spec & SMH_DSP_BUFF_MODE ? "" : "un"));