summaryrefslogtreecommitdiffstats
path: root/sys/netsmb/smb_dev.c
diff options
context:
space:
mode:
authordavide <davide@FreeBSD.org>2012-10-31 03:34:07 +0000
committerdavide <davide@FreeBSD.org>2012-10-31 03:34:07 +0000
commit793cdde76e978e65ad5e743e35dbe3a92b381e90 (patch)
tree0c92e4f2f9c4d973dcd0bbeb244ef685f1342ee1 /sys/netsmb/smb_dev.c
parenta7cdc19e4b4ea767e597c3017133326b0697bd0d (diff)
downloadFreeBSD-src-793cdde76e978e65ad5e743e35dbe3a92b381e90.zip
FreeBSD-src-793cdde76e978e65ad5e743e35dbe3a92b381e90.tar.gz
Fix panic due to page faults while in kernel mode, under conditions of
VM pressure. The reason is that in some codepaths pointers to stack variables were passed from one thread to another. In collaboration with: pho Reported by: pho's stress2 suite Sponsored by: iXsystems inc.
Diffstat (limited to 'sys/netsmb/smb_dev.c')
-rw-r--r--sys/netsmb/smb_dev.c98
1 files changed, 61 insertions, 37 deletions
diff --git a/sys/netsmb/smb_dev.c b/sys/netsmb/smb_dev.c
index 86b2753..dfedd88 100644
--- a/sys/netsmb/smb_dev.c
+++ b/sys/netsmb/smb_dev.c
@@ -157,22 +157,24 @@ nsmb_dev_close(struct cdev *dev, int flag, int fmt, struct thread *td)
struct smb_dev *sdp;
struct smb_vc *vcp;
struct smb_share *ssp;
- struct smb_cred scred;
+ struct smb_cred *scred;
int s;
+ scred = malloc(sizeof(struct smb_cred), M_NSMBDEV, M_WAITOK);
SMB_CHECKMINOR(dev);
s = splimp();
if ((sdp->sd_flags & NSMBFL_OPEN) == 0) {
splx(s);
+ free(scred, M_NSMBDEV);
return EBADF;
}
- smb_makescred(&scred, td, NULL);
+ smb_makescred(scred, td, NULL);
ssp = sdp->sd_share;
if (ssp != NULL)
- smb_share_rele(ssp, &scred);
+ smb_share_rele(ssp, scred);
vcp = sdp->sd_vc;
if (vcp != NULL)
- smb_vc_rele(vcp, &scred);
+ smb_vc_rele(vcp, scred);
/*
smb_flushq(&sdp->sd_rqlist);
smb_flushq(&sdp->sd_rplist);
@@ -181,6 +183,7 @@ nsmb_dev_close(struct cdev *dev, int flag, int fmt, struct thread *td)
free(sdp, M_NSMBDEV);
destroy_dev_sched(dev);
splx(s);
+ free(scred, M_NSMBDEV);
return 0;
}
@@ -191,20 +194,23 @@ nsmb_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thre
struct smb_dev *sdp;
struct smb_vc *vcp;
struct smb_share *ssp;
- struct smb_cred scred;
+ struct smb_cred *scred;
int error = 0;
SMB_CHECKMINOR(dev);
if ((sdp->sd_flags & NSMBFL_OPEN) == 0)
return EBADF;
- smb_makescred(&scred, td, NULL);
+ scred = malloc(sizeof(struct smb_cred), M_NSMBDEV, M_WAITOK);
+ smb_makescred(scred, td, NULL);
switch (cmd) {
case SMBIOC_OPENSESSION:
- if (sdp->sd_vc)
- return EISCONN;
+ if (sdp->sd_vc) {
+ error = EISCONN;
+ goto out;
+ }
error = smb_usr_opensession((struct smbioc_ossn*)data,
- &scred, &vcp);
+ scred, &vcp);
if (error)
break;
sdp->sd_vc = vcp;
@@ -212,12 +218,16 @@ nsmb_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thre
sdp->sd_level = SMBL_VC;
break;
case SMBIOC_OPENSHARE:
- if (sdp->sd_share)
- return EISCONN;
- if (sdp->sd_vc == NULL)
- return ENOTCONN;
+ if (sdp->sd_share) {
+ error = EISCONN;
+ goto out;
+ }
+ if (sdp->sd_vc == NULL) {
+ error = ENOTCONN;
+ goto out;
+ }
error = smb_usr_openshare(sdp->sd_vc,
- (struct smbioc_oshare*)data, &scred, &ssp);
+ (struct smbioc_oshare*)data, scred, &ssp);
if (error)
break;
sdp->sd_share = ssp;
@@ -225,16 +235,20 @@ nsmb_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thre
sdp->sd_level = SMBL_SHARE;
break;
case SMBIOC_REQUEST:
- if (sdp->sd_share == NULL)
- return ENOTCONN;
+ if (sdp->sd_share == NULL) {
+ error = ENOTCONN;
+ goto out;
+ }
error = smb_usr_simplerequest(sdp->sd_share,
- (struct smbioc_rq*)data, &scred);
+ (struct smbioc_rq*)data, scred);
break;
case SMBIOC_T2RQ:
- if (sdp->sd_share == NULL)
- return ENOTCONN;
+ if (sdp->sd_share == NULL) {
+ error = ENOTCONN;
+ goto out;
+ }
error = smb_usr_t2request(sdp->sd_share,
- (struct smbioc_t2rq*)data, &scred);
+ (struct smbioc_t2rq*)data, scred);
break;
case SMBIOC_SETFLAGS: {
struct smbioc_flags *fl = (struct smbioc_flags*)data;
@@ -243,9 +257,11 @@ nsmb_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thre
if (fl->ioc_level == SMBL_VC) {
if (fl->ioc_mask & SMBV_PERMANENT) {
on = fl->ioc_flags & SMBV_PERMANENT;
- if ((vcp = sdp->sd_vc) == NULL)
- return ENOTCONN;
- error = smb_vc_get(vcp, LK_EXCLUSIVE, &scred);
+ if ((vcp = sdp->sd_vc) == NULL) {
+ error = ENOTCONN;
+ goto out;
+ }
+ error = smb_vc_get(vcp, LK_EXCLUSIVE, scred);
if (error)
break;
if (on && (vcp->obj.co_flags & SMBV_PERMANENT) == 0) {
@@ -253,17 +269,19 @@ nsmb_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thre
smb_vc_ref(vcp);
} else if (!on && (vcp->obj.co_flags & SMBV_PERMANENT)) {
vcp->obj.co_flags &= ~SMBV_PERMANENT;
- smb_vc_rele(vcp, &scred);
+ smb_vc_rele(vcp, scred);
}
- smb_vc_put(vcp, &scred);
+ smb_vc_put(vcp, scred);
} else
error = EINVAL;
} else if (fl->ioc_level == SMBL_SHARE) {
if (fl->ioc_mask & SMBS_PERMANENT) {
on = fl->ioc_flags & SMBS_PERMANENT;
- if ((ssp = sdp->sd_share) == NULL)
- return ENOTCONN;
- error = smb_share_get(ssp, LK_EXCLUSIVE, &scred);
+ if ((ssp = sdp->sd_share) == NULL) {
+ error = ENOTCONN;
+ goto out;
+ }
+ error = smb_share_get(ssp, LK_EXCLUSIVE, scred);
if (error)
break;
if (on && (ssp->obj.co_flags & SMBS_PERMANENT) == 0) {
@@ -271,9 +289,9 @@ nsmb_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thre
smb_share_ref(ssp);
} else if (!on && (ssp->obj.co_flags & SMBS_PERMANENT)) {
ssp->obj.co_flags &= ~SMBS_PERMANENT;
- smb_share_rele(ssp, &scred);
+ smb_share_rele(ssp, scred);
}
- smb_share_put(ssp, &scred);
+ smb_share_put(ssp, scred);
} else
error = EINVAL;
break;
@@ -282,11 +300,13 @@ nsmb_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thre
break;
}
case SMBIOC_LOOKUP:
- if (sdp->sd_vc || sdp->sd_share)
- return EISCONN;
+ if (sdp->sd_vc || sdp->sd_share) {
+ error = EISCONN;
+ goto out;
+ }
vcp = NULL;
ssp = NULL;
- error = smb_usr_lookup((struct smbioc_lookup*)data, &scred, &vcp, &ssp);
+ error = smb_usr_lookup((struct smbioc_lookup*)data, scred, &vcp, &ssp);
if (error)
break;
if (vcp) {
@@ -305,8 +325,10 @@ nsmb_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thre
struct uio auio;
struct iovec iov;
- if ((ssp = sdp->sd_share) == NULL)
- return ENOTCONN;
+ if ((ssp = sdp->sd_share) == NULL) {
+ error = ENOTCONN;
+ goto out;
+ }
iov.iov_base = rwrq->ioc_base;
iov.iov_len = rwrq->ioc_cnt;
auio.uio_iov = &iov;
@@ -317,15 +339,17 @@ nsmb_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thre
auio.uio_rw = (cmd == SMBIOC_READ) ? UIO_READ : UIO_WRITE;
auio.uio_td = td;
if (cmd == SMBIOC_READ)
- error = smb_read(ssp, rwrq->ioc_fh, &auio, &scred);
+ error = smb_read(ssp, rwrq->ioc_fh, &auio, scred);
else
- error = smb_write(ssp, rwrq->ioc_fh, &auio, &scred);
+ error = smb_write(ssp, rwrq->ioc_fh, &auio, scred);
rwrq->ioc_cnt -= auio.uio_resid;
break;
}
default:
error = ENODEV;
}
+out:
+ free(scred, M_NSMBDEV);
return error;
}
OpenPOWER on IntegriCloud