aboutsummaryrefslogtreecommitdiff
path: root/sys/netsmb
diff options
context:
space:
mode:
authorDavide Italiano <davide@FreeBSD.org>2012-10-31 03:34:07 +0000
committerDavide Italiano <davide@FreeBSD.org>2012-10-31 03:34:07 +0000
commitafe097512cf87cd78c2fe47f1e18d0bb4d27b356 (patch)
tree0c92e4f2f9c4d973dcd0bbeb244ef685f1342ee1 /sys/netsmb
parent994f027fbcac9f9edf43df8f58cf884d2f9b63f8 (diff)
downloadsrc-afe097512cf87cd78c2fe47f1e18d0bb4d27b356.tar.gz
src-afe097512cf87cd78c2fe47f1e18d0bb4d27b356.zip
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.
Notes
Notes: svn path=/head/; revision=242386
Diffstat (limited to 'sys/netsmb')
-rw-r--r--sys/netsmb/smb_conn.c3
-rw-r--r--sys/netsmb/smb_dev.c98
-rw-r--r--sys/netsmb/smb_trantcp.c23
-rw-r--r--sys/netsmb/smb_usr.c20
4 files changed, 93 insertions, 51 deletions
diff --git a/sys/netsmb/smb_conn.c b/sys/netsmb/smb_conn.c
index 2ee851bd4aec..aee090f915b6 100644
--- a/sys/netsmb/smb_conn.c
+++ b/sys/netsmb/smb_conn.c
@@ -868,8 +868,6 @@ smb_share_getinfo(struct smb_share *ssp, struct smb_share_info *sip)
static int
smb_sysctl_treedump(SYSCTL_HANDLER_ARGS)
{
- struct thread *td = req->td;
- struct smb_cred scred;
struct smb_connobj *scp1, *scp2;
struct smb_vc *vcp;
struct smb_share *ssp;
@@ -877,7 +875,6 @@ smb_sysctl_treedump(SYSCTL_HANDLER_ARGS)
struct smb_share_info ssi;
int error, itype;
- smb_makescred(&scred, td, td->td_ucred);
error = sysctl_wire_old_buffer(req, 0);
if (error)
return (error);
diff --git a/sys/netsmb/smb_dev.c b/sys/netsmb/smb_dev.c
index 86b27533f213..dfedd8898a27 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;
}
diff --git a/sys/netsmb/smb_trantcp.c b/sys/netsmb/smb_trantcp.c
index ce52544da62c..a7c7e05b351d 100644
--- a/sys/netsmb/smb_trantcp.c
+++ b/sys/netsmb/smb_trantcp.c
@@ -192,8 +192,8 @@ bad:
static int
nbssn_rq_request(struct nbpcb *nbp, struct thread *td)
{
- struct mbchain mb, *mbp = &mb;
- struct mdchain md, *mdp = &md;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
struct mbuf *m0;
struct timeval tv;
struct sockaddr_in sin;
@@ -201,9 +201,14 @@ nbssn_rq_request(struct nbpcb *nbp, struct thread *td)
u_int8_t rpcode;
int error, rplen;
+ mbp = malloc(sizeof(struct mbchain), M_NBDATA, M_WAITOK);
+ mdp = malloc(sizeof(struct mbchain), M_NBDATA, M_WAITOK);
error = mb_init(mbp);
- if (error)
+ if (error) {
+ free(mbp, M_NBDATA);
+ free(mdp, M_NBDATA);
return error;
+ }
mb_put_uint32le(mbp, 0);
nb_put_name(mbp, nbp->nbp_paddr);
nb_put_name(mbp, nbp->nbp_laddr);
@@ -214,19 +219,26 @@ nbssn_rq_request(struct nbpcb *nbp, struct thread *td)
}
mb_detach(mbp);
mb_done(mbp);
- if (error)
+ free(mbp, M_NBDATA);
+ if (error) {
+ free(mdp, M_NBDATA);
return error;
+ }
TIMESPEC_TO_TIMEVAL(&tv, &nbp->nbp_timo);
error = selsocket(nbp->nbp_tso, POLLIN, &tv, td);
if (error == EWOULDBLOCK) { /* Timeout */
NBDEBUG("initial request timeout\n");
+ free(mdp, M_NBDATA);
return ETIMEDOUT;
}
- if (error) /* restart or interrupt */
+ if (error) { /* restart or interrupt */
+ free(mdp, M_NBDATA);
return error;
+ }
error = nbssn_recv(nbp, &m0, &rplen, &rpcode, td);
if (error) {
NBDEBUG("recv() error %d\n", error);
+ free(mdp, M_NBDATA);
return error;
}
/*
@@ -264,6 +276,7 @@ nbssn_rq_request(struct nbpcb *nbp, struct thread *td)
} while(0);
if (m0)
md_done(mdp);
+ free(mdp, M_NBDATA);
return error;
}
diff --git a/sys/netsmb/smb_usr.c b/sys/netsmb/smb_usr.c
index b5388079052c..6c3e6b1f8358 100644
--- a/sys/netsmb/smb_usr.c
+++ b/sys/netsmb/smb_usr.c
@@ -127,8 +127,8 @@ smb_usr_lookup(struct smbioc_lookup *dp, struct smb_cred *scred,
struct smb_vc **vcpp, struct smb_share **sspp)
{
struct smb_vc *vcp = NULL;
- struct smb_vcspec vspec;
- struct smb_sharespec sspec, *sspecp = NULL;
+ struct smb_vcspec vspec; /* XXX */
+ struct smb_sharespec sspec, *sspecp = NULL; /* XXX */
int error;
if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE)
@@ -212,7 +212,7 @@ int
smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *dp,
struct smb_cred *scred)
{
- struct smb_rq rq, *rqp = &rq;
+ struct smb_rq *rqp;
struct mbchain *mbp;
struct mdchain *mdp;
u_int8_t wc;
@@ -231,9 +231,12 @@ smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *dp,
case SMB_COM_TREE_CONNECT_ANDX:
return EPERM;
}
+ rqp = malloc(sizeof(struct smb_rq), M_SMBTEMP, M_WAITOK);
error = smb_rq_init(rqp, SSTOCP(ssp), dp->ioc_cmd, scred);
- if (error)
+ if (error) {
+ free(rqp, M_SMBTEMP);
return error;
+ }
mbp = &rqp->sr_rq;
smb_rq_wstart(rqp);
error = mb_put_mem(mbp, dp->ioc_twords, dp->ioc_twc * 2, MB_MUSER);
@@ -271,6 +274,7 @@ bad:
dp->ioc_serror = rqp->sr_serror;
dp->ioc_error = rqp->sr_error;
smb_rq_done(rqp);
+ free(rqp, M_SMBTEMP);
return error;
}
@@ -292,15 +296,18 @@ int
smb_usr_t2request(struct smb_share *ssp, struct smbioc_t2rq *dp,
struct smb_cred *scred)
{
- struct smb_t2rq t2, *t2p = &t2;
+ struct smb_t2rq *t2p;
struct mdchain *mdp;
int error, len;
if (dp->ioc_setupcnt > 3)
return EINVAL;
+ t2p = malloc(sizeof(struct smb_t2rq), M_SMBTEMP, M_WAITOK);
error = smb_t2_init(t2p, SSTOCP(ssp), dp->ioc_setup[0], scred);
- if (error)
+ if (error) {
+ free(t2p, M_SMBTEMP);
return error;
+ }
len = t2p->t2_setupcount = dp->ioc_setupcnt;
if (len > 1)
t2p->t2_setupdata = dp->ioc_setup;
@@ -351,5 +358,6 @@ bad:
if (t2p->t_name)
smb_strfree(t2p->t_name);
smb_t2_done(t2p);
+ free(t2p, M_SMBTEMP);
return error;
}