From 9b42af9326dbf34a7a657a7d4a2ea6d845c845e1 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Thu, 29 Dec 2011 22:18:59 -0500 Subject: [PATCH] Windows: protect merge status against dscp == scp If the directory status object is the same as the object for which status info is being merged, the object will refer to itself as its own parent. Do not permit that. Change-Id: I6f7b6416f4c875a30dd5b85ba679389484523b12 Reviewed-on: http://gerrit.openafs.org/6451 Tested-by: BuildBot Tested-by: Jeffrey Altman Reviewed-by: Jeffrey Altman --- src/WINNT/afsd/cm_scache.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/WINNT/afsd/cm_scache.c b/src/WINNT/afsd/cm_scache.c index d8caadc0e..c8a714a3e 100644 --- a/src/WINNT/afsd/cm_scache.c +++ b/src/WINNT/afsd/cm_scache.c @@ -1554,6 +1554,15 @@ void cm_SyncOpDone(cm_scache_t *scp, cm_buf_t *bufp, afs_uint32 flags) } } +static afs_uint32 +dv_diff(afs_uint64 dv1, afs_uint64 dv2) +{ + if ( dv1 - dv2 > 0x7FFFFFFF ) + return (afs_uint32)(dv2 - dv1); + else + return (afs_uint32)(dv1 - dv2); +} + /* merge in a response from an RPC. The scp must be locked, and the callback * is optional. * @@ -1648,7 +1657,7 @@ void cm_MergeStatus(cm_scache_t *dscp, scp->bufDataVersionLow = CM_SCACHE_VERSION_BAD; scp->fsLockCount = 0; - if (dscp) { + if (dscp && dscp != scp) { scp->parentVnode = dscp->fid.vnode; scp->parentUnique = dscp->fid.unique; } else { @@ -1678,6 +1687,7 @@ void cm_MergeStatus(cm_scache_t *dscp, scp->cbServerp->addr.sin_addr.s_addr, volp ? volp->namep : "(unknown)"); } + osi_Log3(afsd_logp, "Bad merge, scp 0x%p, scp dv %d, RPC dv %d", scp, scp->dataVersion, dataVersion); /* we have a number of data fetch/store operations running @@ -1762,9 +1772,10 @@ void cm_MergeStatus(cm_scache_t *dscp, cm_AddACLCache(scp, userp, statusp->CallerAccess); } - if (dataVersion != 0 && - (!(flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) && dataVersion != scp->dataVersion || - (flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) && dataVersion - scp->dataVersion > activeRPCs)) { + if (dataVersion != 0 && scp->dataVersion != CM_SCACHE_VERSION_BAD && + (!(flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) && (dataVersion != scp->dataVersion) || + (flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) && + (dv_diff(dataVersion, scp->dataVersion) > activeRPCs))) { /* * We now know that all of the data buffers that we have associated * with this scp are invalid. Subsequent operations will go faster @@ -1853,9 +1864,9 @@ void cm_MergeStatus(cm_scache_t *dscp, * merge status no longer has performance characteristics derived from * the size of the file. */ - if (((flags & CM_MERGEFLAG_STOREDATA) && dataVersion - scp->dataVersion > activeRPCs) || - (!(flags & CM_MERGEFLAG_STOREDATA) && scp->dataVersion != dataVersion) || - scp->bufDataVersionLow == 0) + if (((flags & (CM_MERGEFLAG_STOREDATA|CM_MERGEFLAG_DIROP)) && (dv_diff(dataVersion, scp->dataVersion) > activeRPCs)) || + (!(flags & (CM_MERGEFLAG_STOREDATA|CM_MERGEFLAG_DIROP)) && (scp->dataVersion != dataVersion)) || + scp->bufDataVersionLow == CM_SCACHE_VERSION_BAD) scp->bufDataVersionLow = dataVersion; if (RDR_Initialized) { @@ -1881,10 +1892,10 @@ void cm_MergeStatus(cm_scache_t *dscp, rdr_invalidate = 1; } else if (reqp->flags & CM_REQ_SOURCE_REDIR) { if (!(flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) && - (dataVersion - scp->dataVersion > activeRPCs - 1)) { + (dv_diff(dataVersion, scp->dataVersion) > activeRPCs - 1)) { rdr_invalidate = 1; } else if ((flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) && - dataVersion - scp->dataVersion > activeRPCs) { + dv_diff(dataVersion, scp->dataVersion) > activeRPCs) { rdr_invalidate = 1; } } -- 2.39.5