From 8e3b67b9537097928b4fc13844db09d429ac9bed Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Thu, 12 Feb 2009 21:44:47 +0000 Subject: [PATCH] windows-smb-fidp-scp-race-20090212 LICENSE MIT FIXES 124293 As evident in a crash dump, there is a race surrounding access to the scp field of the smb_fid_t object. Not all access was protected by the smb_fid_t mx and the cm_scache_t object was not always being reference counted within the accessing function. This patch ensures that all initial references to the scp object are performed under the smb_fid_t mx mutex and that the cm_scache_t is prevented from being recycled by obtaining a local reference. Finally, CM_ERROR_BADFD is returned as an error if a request begins after the smb_fid_t scp field has already been cleared by a smb_CloseFID() call as part of a concurrent request. --- src/WINNT/afsd/smb.c | 226 +++++++++++++++++++++++++++--------------- src/WINNT/afsd/smb3.c | 120 ++++++++++++++-------- 2 files changed, 225 insertions(+), 121 deletions(-) diff --git a/src/WINNT/afsd/smb.c b/src/WINNT/afsd/smb.c index 0e0cdc413..7b00fd5e2 100644 --- a/src/WINNT/afsd/smb.c +++ b/src/WINNT/afsd/smb.c @@ -929,7 +929,6 @@ static int smb_Is8Dot3StarMask(clientchar_t *maskp) static int smb_IsStarMask(clientchar_t *maskp) { - int i; clientchar_t tc; while (*maskp) { @@ -1624,8 +1623,13 @@ smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp) lock_ObtainWrite(&smb_rctLock); for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) { if (scp == fidp->scp) { - fidp->refCount++; - break; + lock_ObtainMutex(&fidp->mx); + if (scp == fidp->scp) { + fidp->refCount++; + lock_ReleaseMutex(&fidp->mx); + break; + } + lock_ReleaseMutex(&fidp->mx); } } #ifdef DEBUG_SMB_REFCOUNT @@ -3437,13 +3441,14 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp if (!fidp) goto send1; + lock_ObtainMutex(&fidp->mx); if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) { + lock_ReleaseMutex(&fidp->mx); smb_CloseFID(vcp, fidp, NULL, 0); code = CM_ERROR_NOSUCHFILE; goto send1a; } - pid = smbp->pid; { LARGE_INTEGER LOffset, LLength; @@ -3461,6 +3466,7 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp lock_ReleaseWrite(&fidp->scp->rw); } if (code) { + lock_ReleaseMutex(&fidp->mx); goto send1a; } @@ -3471,13 +3477,13 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp smb_RawBufs = *(char **)smb_RawBufs; } lock_ReleaseMutex(&smb_RawBufLock); - if (!rawBuf) + if (!rawBuf) { + lock_ReleaseMutex(&fidp->mx); goto send1a; + } - lock_ObtainMutex(&fidp->mx); if (fidp->flags & SMB_FID_IOCTL) { - lock_ReleaseMutex(&fidp->mx); rc = smb_IoctlReadRaw(fidp, vcp, inp, outp); if (rawBuf) { /* Give back raw buffer */ @@ -5554,17 +5560,6 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE); osi_assertx(fidp, "null smb_fid_t"); - /* save a pointer to the vnode */ - fidp->scp = scp; - osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp); - lock_ObtainWrite(&scp->rw); - scp->flags |= CM_SCACHEFLAG_SMB_FID; - lock_ReleaseWrite(&scp->rw); - - /* and the user */ - cm_HoldUser(userp); - fidp->userp = userp; - lock_ObtainMutex(&fidp->mx); if ((share & 0xf) == 0) fidp->flags |= SMB_FID_OPENREAD_LISTDIR; @@ -5572,9 +5567,17 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) fidp->flags |= SMB_FID_OPENWRITE; else fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE); - lock_ReleaseMutex(&fidp->mx); - lock_ObtainRead(&scp->rw); + /* save the user */ + cm_HoldUser(userp); + fidp->userp = userp; + + /* and a pointer to the vnode */ + fidp->scp = scp; + osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp); + lock_ObtainWrite(&scp->rw); + scp->flags |= CM_SCACHEFLAG_SMB_FID; + smb_SetSMBParm(outp, 0, fidp->fid); smb_SetSMBParm(outp, 1, smb_Attributes(scp)); smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime); @@ -5585,6 +5588,7 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) /* pass the open mode back; XXXX add access checks */ smb_SetSMBParm(outp, 6, (share & 0xf)); smb_SetSMBDataLength(outp, 0); + lock_ReleaseMutex(&fidp->mx); lock_ReleaseRead(&scp->rw); /* notify open */ @@ -6456,40 +6460,39 @@ long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) fid = smb_ChainFID(fid, inp); fidp = smb_FindFID(vcp, fid, 0); if (!fidp) - return CM_ERROR_BADFD; + return CM_ERROR_BADFD; + userp = smb_GetUserFromVCP(vcp, inp); + + lock_ObtainMutex(&fidp->mx); if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) { + lock_ReleaseMutex(&fidp->mx); + cm_ReleaseUser(userp); smb_CloseFID(vcp, fidp, NULL, 0); smb_ReleaseFID(fidp); return CM_ERROR_NOSUCHFILE; } - lock_ObtainMutex(&fidp->mx); if (fidp->flags & SMB_FID_IOCTL) { - lock_ReleaseMutex(&fidp->mx); - smb_ReleaseFID(fidp); + cm_ReleaseUser(userp); + lock_ReleaseMutex(&fidp->mx); + smb_ReleaseFID(fidp); return CM_ERROR_BADFD; } - lock_ReleaseMutex(&fidp->mx); - - userp = smb_GetUserFromVCP(vcp, inp); - lock_ObtainMutex(&fidp->mx); - if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) { - cm_scache_t * scp = fidp->scp; - cm_HoldSCache(scp); - lock_ReleaseMutex(&fidp->mx); + if (fidp->scp && (fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) { + cm_scache_t * scp = fidp->scp; + cm_HoldSCache(scp); + lock_ReleaseMutex(&fidp->mx); code = cm_FSync(scp, userp, &req); - cm_ReleaseSCache(scp); + cm_ReleaseSCache(scp); } else { + lock_ReleaseMutex(&fidp->mx); code = 0; - lock_ReleaseMutex(&fidp->mx); } - smb_ReleaseFID(fidp); - cm_ReleaseUser(userp); - + smb_ReleaseFID(fidp); return code; } @@ -6586,26 +6589,25 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp, lock_ObtainWrite(&smb_rctLock); if (fidp->deleteOk) { - osi_Log0(smb_logp, " Fid already closed."); - lock_ReleaseWrite(&smb_rctLock); - return CM_ERROR_BADFD; + osi_Log0(smb_logp, " Fid already closed."); + lock_ReleaseWrite(&smb_rctLock); + return CM_ERROR_BADFD; } fidp->deleteOk = 1; lock_ReleaseWrite(&smb_rctLock); lock_ObtainMutex(&fidp->mx); if (fidp->NTopen_dscp) { - dscp = fidp->NTopen_dscp; - cm_HoldSCache(dscp); + dscp = fidp->NTopen_dscp; + cm_HoldSCache(dscp); } - if (fidp->NTopen_pathp) { - pathp = cm_ClientStrDup(fidp->NTopen_pathp); - } + if (fidp->NTopen_pathp) + pathp = cm_ClientStrDup(fidp->NTopen_pathp); if (fidp->scp) { - scp = fidp->scp; - cm_HoldSCache(scp); + scp = fidp->scp; + cm_HoldSCache(scp); } /* Don't jump the gun on an async raw write */ @@ -6623,7 +6625,7 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp, scp->mask |= CM_SCACHEMASK_CLIENTMODTIME; /* This fixes defect 10958 */ CompensateForSmbClientLastWriteTimeBugs(&dosTime); - smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime); + smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime); } if (smb_AsyncStore != 2) { lock_ReleaseMutex(&fidp->mx); @@ -6640,10 +6642,10 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp, cm_key_t key; long tcode; - lock_ReleaseMutex(&fidp->mx); + lock_ReleaseMutex(&fidp->mx); - /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass - in zero. */ + /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass + * in zero. */ key = cm_GenerateKey(vcp->vcID, 0, fidp->fid); lock_ObtainWrite(&scp->rw); @@ -6744,16 +6746,16 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp, } if (scp) { - lock_ObtainWrite(&scp->rw); + lock_ObtainWrite(&scp->rw); if (nullcreator && scp->creator == userp) scp->creator = NULL; - scp->flags &= ~CM_SCACHEFLAG_SMB_FID; - lock_ReleaseWrite(&scp->rw); - cm_ReleaseSCache(scp); + scp->flags &= ~CM_SCACHEFLAG_SMB_FID; + lock_ReleaseWrite(&scp->rw); + cm_ReleaseSCache(scp); } if (pathp) - free(pathp); + free(pathp); return code; } @@ -6821,7 +6823,13 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char code = CM_ERROR_BADFDOP; goto done2; } - + + if (!fidp->scp) { + lock_ReleaseMutex(&fidp->mx); + code = CM_ERROR_BADFD; + goto done2; + } + smb_InitReq(&req); bufferp = NULL; @@ -7229,6 +7237,7 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) smb_t* smbp = (smb_t*) inp; long code = 0; cm_user_t *userp; + cm_scache_t *scp; cm_attr_t truncAttr; /* attribute struct used for truncating file */ char *op; int inDataBlockCount; @@ -7252,13 +7261,14 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) return CM_ERROR_BADFD; } + lock_ObtainMutex(&fidp->mx); if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) { + lock_ReleaseMutex(&fidp->mx); smb_CloseFID(vcp, fidp, NULL, 0); smb_ReleaseFID(fidp); return CM_ERROR_NOSUCHFILE; } - lock_ObtainMutex(&fidp->mx); if (fidp->flags & SMB_FID_IOCTL) { lock_ReleaseMutex(&fidp->mx); code = smb_IoctlWrite(fidp, vcp, inp, outp); @@ -7266,6 +7276,15 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code); return code; } + + if (!fidp->scp) { + lock_ReleaseMutex(&fidp->mx); + smb_ReleaseFID(fidp); + return CM_ERROR_BADFD; + } + + scp = fidp->scp; + cm_HoldSCache(scp); lock_ReleaseMutex(&fidp->mx); userp = smb_GetUserFromVCP(vcp, inp); @@ -7282,9 +7301,9 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) LLength.HighPart = 0; LLength.LowPart = count; - lock_ObtainWrite(&fidp->scp->rw); - code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key); - lock_ReleaseWrite(&fidp->scp->rw); + lock_ObtainWrite(&scp->rw); + code = cm_LockCheckWrite(scp, LOffset, LLength, key); + lock_ReleaseWrite(&scp->rw); if (code) { osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code); @@ -7356,6 +7375,7 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) done: smb_ReleaseFID(fidp); cm_ReleaseUser(userp); + cm_ReleaseSCache(scp); return code; } @@ -7373,12 +7393,15 @@ void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, fd = smb_GetSMBParm(inp, 0); fidp = smb_FindFID(vcp, fd, 0); + lock_ObtainMutex(&fidp->mx); if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) { + lock_ReleaseMutex(&fidp->mx); smb_CloseFID(vcp, fidp, NULL, 0); smb_ReleaseFID(fidp); return; } - + lock_ReleaseMutex(&fidp->mx); + osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x", rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count); @@ -7432,6 +7455,7 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out smb_t *smbp = (smb_t*) inp; long code = 0; cm_user_t *userp; + cm_scache_t *scp; char *op; unsigned short writeMode; char *rawBuf; @@ -7479,16 +7503,26 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out fd = smb_ChainFID(fd, inp); fidp = smb_FindFID(vcp, fd, 0); - if (!fidp) { + if (!fidp) return CM_ERROR_BADFD; - } + lock_ObtainMutex(&fidp->mx); if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) { + lock_ReleaseMutex(&fidp->mx); smb_CloseFID(vcp, fidp, NULL, 0); smb_ReleaseFID(fidp); return CM_ERROR_NOSUCHFILE; } + if (!fidp->scp) { + lock_ReleaseMutex(&fidp->mx); + smb_ReleaseFID(fidp); + return CM_ERROR_BADFDOP; + } + scp = fidp->scp; + cm_HoldSCache(scp); + lock_ReleaseMutex(&fidp->mx); + { unsigned pid; cm_key_t key; @@ -7503,11 +7537,12 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out LLength.HighPart = 0; LLength.LowPart = count; - lock_ObtainWrite(&fidp->scp->rw); - code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key); - lock_ReleaseWrite(&fidp->scp->rw); + lock_ObtainWrite(&scp->rw); + code = cm_LockCheckWrite(scp, LOffset, LLength, key); + lock_ReleaseWrite(&scp->rw); if (code) { + cm_ReleaseSCache(scp); smb_ReleaseFID(fidp); return code; } @@ -7571,6 +7606,7 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out smb_ReleaseFID(fidp); cm_ReleaseUser(userp); + cm_ReleaseSCache(scp); if (code) { smb_SetSMBParm(outp, 0, total_written); @@ -7611,6 +7647,7 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) smb_t *smbp = (smb_t*) inp; long code = 0; cm_user_t *userp; + cm_scache_t *scp; char *op; fd = smb_GetSMBParm(inp, 0); @@ -7625,20 +7662,29 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) fidp = smb_FindFID(vcp, fd, 0); if (!fidp) return CM_ERROR_BADFD; - + + lock_ObtainMutex(&fidp->mx); if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) { + lock_ReleaseMutex(&fidp->mx); smb_CloseFID(vcp, fidp, NULL, 0); smb_ReleaseFID(fidp); return CM_ERROR_NOSUCHFILE; } - lock_ObtainMutex(&fidp->mx); if (fidp->flags & SMB_FID_IOCTL) { lock_ReleaseMutex(&fidp->mx); code = smb_IoctlRead(fidp, vcp, inp, outp); smb_ReleaseFID(fidp); return code; } + + if (!fidp->scp) { + lock_ReleaseMutex(&fidp->mx); + smb_ReleaseFID(fidp); + return CM_ERROR_BADFDOP; + } + scp = fidp->scp; + cm_HoldSCache(scp); lock_ReleaseMutex(&fidp->mx); { @@ -7653,11 +7699,12 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) LLength.HighPart = 0; LLength.LowPart = count; - lock_ObtainWrite(&fidp->scp->rw); - code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key); - lock_ReleaseWrite(&fidp->scp->rw); + lock_ObtainWrite(&scp->rw); + code = cm_LockCheckRead(scp, LOffset, LLength, key); + lock_ReleaseWrite(&scp->rw); } if (code) { + cm_ReleaseSCache(scp); smb_ReleaseFID(fidp); return code; } @@ -7695,6 +7742,7 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) smb_ReleaseFID(fidp); cm_ReleaseUser(userp); + cm_ReleaseSCache(scp); return code; } @@ -8057,21 +8105,29 @@ long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) fidp = smb_FindFID(vcp, fd, 0); if (!fidp) return CM_ERROR_BADFD; - + + lock_ObtainMutex(&fidp->mx); if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) { + lock_ReleaseMutex(&fidp->mx); smb_CloseFID(vcp, fidp, NULL, 0); smb_ReleaseFID(fidp); return CM_ERROR_NOSUCHFILE; } - lock_ObtainMutex(&fidp->mx); if (fidp->flags & SMB_FID_IOCTL) { lock_ReleaseMutex(&fidp->mx); smb_ReleaseFID(fidp); return CM_ERROR_BADFD; } + + if (!fidp->scp) { + lock_ReleaseMutex(&fidp->mx); + smb_ReleaseFID(fidp); + return CM_ERROR_BADFDOP; + } + lock_ReleaseMutex(&fidp->mx); - + userp = smb_GetUserFromVCP(vcp, inp); lock_ObtainMutex(&fidp->mx); @@ -8235,13 +8291,16 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, smb_LookupTIDPath(vcp,((smb_t *)inp)->tid, &treepath); fidp = smb_FindFID(vcp, inp->fid, 0); - if (fidp && fidp->NTopen_pathp) - pathname = fidp->NTopen_pathp; - else if (inp->stringsp->wdata) - pathname = inp->stringsp->wdata; - - if (fidp && fidp->scp) - afid = fidp->scp->fid; + if (fidp) { + lock_ObtainMutex(&fidp->mx); + if (fidp->NTopen_pathp) + pathname = fidp->NTopen_pathp; + if (fidp->scp) + afid = fidp->scp->fid; + } else { + if (inp->stringsp->wdata) + pathname = inp->stringsp->wdata; + } afsi_log("Request %s duration %d ms user %S tid \"%S\" path? \"%S\" afid (%d.%d.%d.%d)", opName, newTime - oldTime, @@ -8250,6 +8309,9 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, pathname, afid.cell, afid.volume, afid.vnode, afid.unique); + if (fidp) + lock_ReleaseMutex(&fidp->mx); + if (uidp) smb_ReleaseUID(uidp); if (fidp) diff --git a/src/WINNT/afsd/smb3.c b/src/WINNT/afsd/smb3.c index 4463f6e31..b2c615ffe 100644 --- a/src/WINNT/afsd/smb3.c +++ b/src/WINNT/afsd/smb3.c @@ -2222,13 +2222,16 @@ long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) smb_LookupTIDPath(vcp, asp->tid, &treepath); fidp = smb_FindFID(vcp, inp->fid, 0); - if (fidp && fidp->NTopen_pathp) - pathname = fidp->NTopen_pathp; - else if (inp->stringsp->wdata) - pathname = inp->stringsp->wdata; - - if (fidp && fidp->scp) - afid = fidp->scp->fid; + if (fidp) { + lock_ObtainMutex(&fidp->mx); + if (fidp->NTopen_pathp) + pathname = fidp->NTopen_pathp; + if (fidp->scp) + afid = fidp->scp->fid; + } else { + if (inp->stringsp->wdata) + pathname = inp->stringsp->wdata; + } afsi_log("Request %s duration %d ms user %S tid \"%S\" path? \"%S\" afid (%d.%d.%d.%d)", myCrt_2Dispatch(asp->opcode), newTime - oldTime, @@ -2237,6 +2240,9 @@ long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) pathname, afid.cell, afid.volume, afid.vnode, afid.unique); + if (fidp) + lock_ReleaseMutex(&fidp->mx); + if (uidp) smb_ReleaseUID(uidp); if (fidp) @@ -3460,12 +3466,15 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t return 0; } + lock_ObtainMutex(&fidp->mx); if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) { + lock_ReleaseMutex(&fidp->mx); smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE); smb_CloseFID(vcp, fidp, NULL, 0); smb_ReleaseFID(fidp); return 0; } + lock_ReleaseMutex(&fidp->mx); infoLevel = p->parmsp[1]; if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) @@ -3603,13 +3612,6 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet return 0; } - if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) { - smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE); - smb_CloseFID(vcp, fidp, NULL, 0); - smb_ReleaseFID(fidp); - return 0; - } - infoLevel = p->parmsp[1]; osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid); if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) { @@ -3621,6 +3623,14 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet } lock_ObtainMutex(&fidp->mx); + if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) { + lock_ReleaseMutex(&fidp->mx); + smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE); + smb_CloseFID(vcp, fidp, NULL, 0); + smb_ReleaseFID(fidp); + return 0; + } + if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) { osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x", @@ -6021,13 +6031,14 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) if (!fidp) return CM_ERROR_BADFD; + lock_ObtainMutex(&fidp->mx); if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) { + lock_ReleaseMutex(&fidp->mx); smb_CloseFID(vcp, fidp, NULL, 0); smb_ReleaseFID(fidp); return CM_ERROR_NOSUCHFILE; } - lock_ObtainMutex(&fidp->mx); if (fidp->flags & SMB_FID_IOCTL) { osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD"); lock_ReleaseMutex(&fidp->mx); @@ -6044,7 +6055,6 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) userp = smb_GetUserFromVCP(vcp, inp); - lock_ObtainWrite(&scp->rw); code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_NEEDCALLBACK @@ -6307,13 +6317,14 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t * if (!fidp) return CM_ERROR_BADFD; + lock_ObtainMutex(&fidp->mx); if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) { + lock_ReleaseMutex(&fidp->mx); smb_CloseFID(vcp, fidp, NULL, 0); smb_ReleaseFID(fidp); return CM_ERROR_NOSUCHFILE; } - lock_ObtainMutex(&fidp->mx); if (fidp->flags & SMB_FID_IOCTL) { lock_ReleaseMutex(&fidp->mx); smb_ReleaseFID(fidp); @@ -6397,13 +6408,14 @@ long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t * if (!fidp) return CM_ERROR_BADFD; + lock_ObtainMutex(&fidp->mx); if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) { + lock_ReleaseMutex(&fidp->mx); smb_CloseFID(vcp, fidp, NULL, 0); smb_ReleaseFID(fidp); return CM_ERROR_NOSUCHFILE; } - lock_ObtainMutex(&fidp->mx); if (fidp->flags & SMB_FID_IOCTL) { lock_ReleaseMutex(&fidp->mx); smb_ReleaseFID(fidp); @@ -6416,7 +6428,6 @@ long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t * userp = smb_GetUserFromVCP(vcp, inp); - /* now prepare to call cm_setattr. This message only sets various times, * and AFS only implements mtime, and we'll set the mtime if that's * requested. The others we'll ignore. @@ -6455,6 +6466,7 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) smb_fid_t *fidp; smb_t *smbp = (smb_t*) inp; long code = 0; + cm_scache_t *scp; cm_user_t *userp; char *op; int inDataBlockCount; @@ -6491,20 +6503,31 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) if (!fidp) return CM_ERROR_BADFD; + lock_ObtainMutex(&fidp->mx); if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) { + lock_ReleaseMutex(&fidp->mx); smb_CloseFID(vcp, fidp, NULL, 0); smb_ReleaseFID(fidp); return CM_ERROR_NOSUCHFILE; } - lock_ObtainMutex(&fidp->mx); if (fidp->flags & SMB_FID_IOCTL) { lock_ReleaseMutex(&fidp->mx); code = smb_IoctlV3Write(fidp, vcp, inp, outp); smb_ReleaseFID(fidp); return code; } + + if (!fidp->scp) { + lock_ReleaseMutex(&fidp->mx); + smb_ReleaseFID(fidp); + return CM_ERROR_BADFDOP; + } + + scp = fidp->scp; + cm_HoldSCache(scp); lock_ReleaseMutex(&fidp->mx); + userp = smb_GetUserFromVCP(vcp, inp); /* special case: 0 bytes transferred means there is no data @@ -6516,7 +6539,6 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) cm_key_t key; LARGE_INTEGER LOffset; LARGE_INTEGER LLength; - cm_scache_t * scp; pid = smbp->pid; key = cm_GenerateKey(vcp->vcID, pid, fd); @@ -6526,7 +6548,6 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) LLength.HighPart = 0; LLength.LowPart = count; - scp = fidp->scp; lock_ObtainWrite(&scp->rw); code = cm_LockCheckWrite(scp, LOffset, LLength, key); lock_ReleaseWrite(&scp->rw); @@ -6547,8 +6568,8 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) */ lock_ObtainMutex(&fidp->mx); if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) { - fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME; - fidp->scp->clientModTime = time(NULL); + scp->mask |= CM_SCACHEMASK_CLIENTMODTIME; + scp->clientModTime = time(NULL); } lock_ReleaseMutex(&fidp->mx); @@ -6574,6 +6595,8 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) smb_SetSMBDataLength(outp, 0); done: + + cm_ReleaseSCache(scp); cm_ReleaseUser(userp); smb_ReleaseFID(fidp); @@ -6591,6 +6614,7 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) smb_fid_t *fidp; smb_t *smbp = (smb_t*) inp; long code = 0; + cm_scache_t *scp; cm_user_t *userp; cm_key_t key; char *op; @@ -6630,28 +6654,39 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) return CM_ERROR_BADFD; } + lock_ObtainMutex(&fidp->mx); if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) { + lock_ReleaseMutex(&fidp->mx); smb_CloseFID(vcp, fidp, NULL, 0); smb_ReleaseFID(fidp); return CM_ERROR_NOSUCHFILE; } + if (!fidp->scp) { + lock_ReleaseMutex(&fidp->mx); + smb_ReleaseFID(fidp); + return CM_ERROR_BADFDOP; + } + + scp = fidp->scp; + cm_HoldSCache(scp); + lock_ReleaseMutex(&fidp->mx); + pid = smbp->pid; key = cm_GenerateKey(vcp->vcID, pid, fd); { LARGE_INTEGER LOffset, LLength; - cm_scache_t *scp; LOffset.HighPart = offset.HighPart; LOffset.LowPart = offset.LowPart; LLength.HighPart = 0; LLength.LowPart = count; - scp = fidp->scp; lock_ObtainWrite(&scp->rw); code = cm_LockCheckRead(scp, LOffset, LLength, key); lock_ReleaseWrite(&scp->rw); } + cm_ReleaseSCache(scp); if (code) { smb_ReleaseFID(fidp); @@ -7571,15 +7606,15 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) smb_SetSMBDataLength(outp, 0); if ((fidp->flags & SMB_FID_EXECUTABLE) && - LargeIntegerGreaterThanZero(fidp->scp->length) && + LargeIntegerGreaterThanZero(scp->length) && !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) { prefetch = 1; } lock_ReleaseRead(&scp->rw); if (prefetch) - cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0, - fidp->scp->length.LowPart, fidp->scp->length.HighPart, + cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0, + scp->length.LowPart, scp->length.HighPart, userp); @@ -8334,15 +8369,15 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out } if ((fidp->flags & SMB_FID_EXECUTABLE) && - LargeIntegerGreaterThanZero(fidp->scp->length) && + LargeIntegerGreaterThanZero(scp->length) && !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) { prefetch = 1; } lock_ReleaseRead(&scp->rw); if (prefetch) - cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0, - fidp->scp->length.LowPart, fidp->scp->length.HighPart, + cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0, + scp->length.LowPart, scp->length.HighPart, userp); osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid); @@ -8376,11 +8411,16 @@ long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp, return CM_ERROR_BADFD; } + lock_ObtainMutex(&fidp->mx); if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) { + lock_ReleaseMutex(&fidp->mx); smb_CloseFID(vcp, fidp, NULL, 0); smb_ReleaseFID(fidp); return CM_ERROR_NOSUCHFILE; } + scp = fidp->scp; + cm_HoldSCache(scp); + lock_ReleaseMutex(&fidp->mx); /* Create a copy of the Directory Watch Packet to use when sending the * notification if in the future a matching change is detected. @@ -8399,7 +8439,6 @@ long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp, smb_Directory_Watches = savedPacketp; lock_ReleaseMutex(&smb_Dir_Watch_Lock); - scp = fidp->scp; osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"", fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp)); osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d", @@ -8435,6 +8474,7 @@ long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp, else scp->flags |= CM_SCACHEFLAG_WATCHED; lock_ReleaseWrite(&scp->rw); + cm_ReleaseSCache(scp); smb_ReleaseFID(fidp); outp->flags |= SMB_PACKETFLAG_NOSEND; @@ -8832,12 +8872,14 @@ long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) scp = fidp->scp; osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp); - lock_ObtainWrite(&scp->rw); - if (watchtree) - scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE; - else - scp->flags &= ~CM_SCACHEFLAG_WATCHED; - lock_ReleaseWrite(&scp->rw); + if (scp) { + lock_ObtainWrite(&scp->rw); + if (watchtree) + scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE; + else + scp->flags &= ~CM_SCACHEFLAG_WATCHED; + lock_ReleaseWrite(&scp->rw); + } smb_ReleaseFID(fidp); } else { osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp); -- 2.39.5