svn commit: r260541 - in head/sys/cam: . scsi
Alexander Motin
mav at FreeBSD.org
Sat Jan 11 13:35:37 UTC 2014
Author: mav
Date: Sat Jan 11 13:35:36 2014
New Revision: 260541
URL: http://svnweb.freebsd.org/changeset/base/260541
Log:
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.
Modified:
head/sys/cam/cam_periph.c
head/sys/cam/cam_periph.h
head/sys/cam/cam_xpt.c
head/sys/cam/scsi/scsi_xpt.c
Modified: head/sys/cam/cam_periph.c
==============================================================================
--- head/sys/cam/cam_periph.c Sat Jan 11 09:44:00 2014 (r260540)
+++ head/sys/cam/cam_periph.c Sat Jan 11 13:35:36 2014 (r260541)
@@ -376,6 +376,17 @@ cam_periph_acquire(struct cam_periph *pe
}
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)
{
Modified: head/sys/cam/cam_periph.h
==============================================================================
--- head/sys/cam/cam_periph.h Sat Jan 11 09:44:00 2014 (r260540)
+++ head/sys/cam/cam_periph.h Sat Jan 11 13:35:36 2014 (r260541)
@@ -152,6 +152,7 @@ cam_status cam_periph_alloc(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);
Modified: head/sys/cam/cam_xpt.c
==============================================================================
--- head/sys/cam/cam_xpt.c Sat Jan 11 09:44:00 2014 (r260540)
+++ head/sys/cam/cam_xpt.c Sat Jan 11 13:35:36 2014 (r260541)
@@ -3156,9 +3156,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);
Modified: head/sys/cam/scsi/scsi_xpt.c
==============================================================================
--- head/sys/cam/scsi/scsi_xpt.c Sat Jan 11 09:44:00 2014 (r260540)
+++ head/sys/cam/scsi/scsi_xpt.c Sat Jan 11 13:35:36 2014 (r260541)
@@ -888,12 +888,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;
}
@@ -919,14 +921,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:
{
@@ -959,19 +954,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);
}
@@ -1122,6 +1111,7 @@ probedone(struct cam_periph *periph, uni
out:
/* Drop freeze taken due to CAM_DEV_QFREEZE */
cam_release_devq(path, 0, 0, 0, FALSE);
+ cam_periph_release_locked(periph);
return;
}
else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
@@ -1697,6 +1687,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 {
More information about the svn-src-all
mailing list