MFC r260541, r260547:
Take additional reference on SCSI probe periph to cover its freeze count. Otherwise periph may be invalidated and freed before single-stepping freeze is dropped, causing use after free panic.
This commit is contained in:
parent
a7224392fd
commit
204096a62c
@ -375,6 +375,17 @@ cam_periph_acquire(struct cam_periph *periph)
|
||||
return (status);
|
||||
}
|
||||
|
||||
void
|
||||
cam_periph_doacquire(struct cam_periph *periph)
|
||||
{
|
||||
|
||||
xpt_lock_buses();
|
||||
KASSERT(periph->refcount >= 1,
|
||||
("cam_periph_doacquire() with refcount == %d", periph->refcount));
|
||||
periph->refcount++;
|
||||
xpt_unlock_buses();
|
||||
}
|
||||
|
||||
void
|
||||
cam_periph_release_locked_buses(struct cam_periph *periph)
|
||||
{
|
||||
|
@ -152,6 +152,7 @@ cam_status cam_periph_alloc(periph_ctor_t *periph_ctor,
|
||||
struct cam_periph *cam_periph_find(struct cam_path *path, char *name);
|
||||
int cam_periph_list(struct cam_path *, struct sbuf *);
|
||||
cam_status cam_periph_acquire(struct cam_periph *periph);
|
||||
void cam_periph_doacquire(struct cam_periph *periph);
|
||||
void cam_periph_release(struct cam_periph *periph);
|
||||
void cam_periph_release_locked(struct cam_periph *periph);
|
||||
void cam_periph_release_locked_buses(struct cam_periph *periph);
|
||||
|
@ -3154,9 +3154,7 @@ restart:
|
||||
}
|
||||
if (periph->flags & CAM_PERIPH_RUN_TASK)
|
||||
break;
|
||||
xpt_lock_buses();
|
||||
periph->refcount++; /* Unconditionally acquire */
|
||||
xpt_unlock_buses();
|
||||
cam_periph_doacquire(periph);
|
||||
periph->flags |= CAM_PERIPH_RUN_TASK;
|
||||
taskqueue_enqueue(xsoftc.xpt_taskq,
|
||||
&periph->periph_run_task);
|
||||
|
@ -890,12 +890,14 @@ again:
|
||||
/*timeout*/60 * 1000);
|
||||
break;
|
||||
}
|
||||
done:
|
||||
/*
|
||||
* We'll have to do without, let our probedone
|
||||
* routine finish up for us.
|
||||
*/
|
||||
start_ccb->csio.data_ptr = NULL;
|
||||
cam_freeze_devq(periph->path);
|
||||
cam_periph_doacquire(periph);
|
||||
probedone(periph, start_ccb);
|
||||
return;
|
||||
}
|
||||
@ -921,14 +923,7 @@ again:
|
||||
/*timeout*/60 * 1000);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* We'll have to do without, let our probedone
|
||||
* routine finish up for us.
|
||||
*/
|
||||
start_ccb->csio.data_ptr = NULL;
|
||||
cam_freeze_devq(periph->path);
|
||||
probedone(periph, start_ccb);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
case PROBE_SERIAL_NUM:
|
||||
{
|
||||
@ -961,19 +956,13 @@ again:
|
||||
/*timeout*/60 * 1000);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* We'll have to do without, let our probedone
|
||||
* routine finish up for us.
|
||||
*/
|
||||
start_ccb->csio.data_ptr = NULL;
|
||||
cam_freeze_devq(periph->path);
|
||||
probedone(periph, start_ccb);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
default:
|
||||
panic("probestart: invalid action state 0x%x\n", softc->action);
|
||||
}
|
||||
start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
|
||||
cam_periph_doacquire(periph);
|
||||
xpt_action(start_ccb);
|
||||
}
|
||||
|
||||
@ -1121,7 +1110,7 @@ probedone(struct cam_periph *periph, union ccb *done_ccb)
|
||||
|
||||
if (cam_periph_error(done_ccb, 0,
|
||||
SF_NO_PRINT, NULL) == ERESTART) {
|
||||
out:
|
||||
outr:
|
||||
/* Drop freeze taken due to CAM_DEV_QFREEZE */
|
||||
cam_release_devq(path, 0, 0, 0, FALSE);
|
||||
return;
|
||||
@ -1135,7 +1124,11 @@ out:
|
||||
PROBE_SET_ACTION(softc, PROBE_INQUIRY);
|
||||
xpt_release_ccb(done_ccb);
|
||||
xpt_schedule(periph, priority);
|
||||
goto out;
|
||||
out:
|
||||
/* Drop freeze taken due to CAM_DEV_QFREEZE and release. */
|
||||
cam_release_devq(path, 0, 0, 0, FALSE);
|
||||
cam_periph_release_locked(periph);
|
||||
return;
|
||||
}
|
||||
case PROBE_INQUIRY:
|
||||
case PROBE_FULL_INQUIRY:
|
||||
@ -1222,7 +1215,7 @@ out:
|
||||
? SF_RETRY_UA|SF_QUIET_IR
|
||||
: SF_RETRY_UA,
|
||||
&softc->saved_ccb) == ERESTART) {
|
||||
goto out;
|
||||
goto outr;
|
||||
} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
|
||||
/* Don't wedge the queue */
|
||||
xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
|
||||
@ -1263,7 +1256,7 @@ out:
|
||||
done_ccb->ccb_h.target_lun > 0 ?
|
||||
SF_RETRY_UA|SF_QUIET_IR : SF_RETRY_UA,
|
||||
&softc->saved_ccb) == ERESTART) {
|
||||
goto out;
|
||||
goto outr;
|
||||
}
|
||||
if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
|
||||
xpt_release_devq(done_ccb->ccb_h.path, 1,
|
||||
@ -1373,7 +1366,7 @@ out:
|
||||
} else if (cam_periph_error(done_ccb, 0,
|
||||
SF_RETRY_UA|SF_NO_PRINT,
|
||||
&softc->saved_ccb) == ERESTART) {
|
||||
goto out;
|
||||
goto outr;
|
||||
} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
|
||||
/* Don't wedge the queue */
|
||||
xpt_release_devq(done_ccb->ccb_h.path,
|
||||
@ -1416,7 +1409,7 @@ out:
|
||||
} else if (cam_periph_error(done_ccb, 0,
|
||||
SF_RETRY_UA|SF_NO_PRINT,
|
||||
&softc->saved_ccb) == ERESTART) {
|
||||
goto out;
|
||||
goto outr;
|
||||
} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
|
||||
/* Don't wedge the queue */
|
||||
xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
|
||||
@ -1461,7 +1454,7 @@ out:
|
||||
} else if (cam_periph_error(done_ccb, 0,
|
||||
SF_RETRY_UA,
|
||||
&softc->saved_ccb) == ERESTART) {
|
||||
goto out;
|
||||
goto outr;
|
||||
} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
|
||||
/* Don't wedge the queue */
|
||||
xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
|
||||
@ -1516,7 +1509,7 @@ probe_device_check:
|
||||
} else if (cam_periph_error(done_ccb, 0,
|
||||
SF_RETRY_UA|SF_NO_PRINT,
|
||||
&softc->saved_ccb) == ERESTART) {
|
||||
goto out;
|
||||
goto outr;
|
||||
} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
|
||||
/* Don't wedge the queue */
|
||||
xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
|
||||
@ -1699,6 +1692,7 @@ probe_device_check:
|
||||
CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe completed\n"));
|
||||
/* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */
|
||||
cam_release_devq(path, 0, 0, 0, FALSE);
|
||||
cam_periph_release_locked(periph);
|
||||
cam_periph_invalidate(periph);
|
||||
cam_periph_release_locked(periph);
|
||||
} else {
|
||||
|
Loading…
x
Reference in New Issue
Block a user