/// <summary> /// take a hash of the current full contents of the block, including unreadable areas /// but not uncommitted areas /// </summary> /// <exception cref="InvalidOperationException"> /// <see cref="MemoryBlock.Active"/> is <see langword="false"/> or failed to make memory read-only /// </exception> public byte[] FullHash() { if (!Active) { throw new InvalidOperationException("Not active"); } // temporarily switch the committed parts to `R` so we can read them if (CommittedSize > 0) { _pal.Protect(Start, CommittedSize, Protection.R); } var ret = WaterboxUtils.Hash(GetStream(Start, CommittedSize, false)); ProtectAll(); return(ret); }
/// <summary>restore all recorded protections</summary> private void ProtectAll() { if (CommittedSize == 0) { return; } int ps = 0; int pageLimit = (int)(CommittedSize >> WaterboxUtils.PageShift); for (int i = 0; i < pageLimit; i++) { if (i == pageLimit - 1 || _pageData[i] != _pageData[i + 1] || _dirtydata[i] != _dirtydata[i + 1]) { ulong zstart = GetStartAddr(ps); ulong zend = GetStartAddr(i + 1); var prot = _pageData[i]; // adjust frontend notion of prot to the PAL layer's expectation if (prot == Protection.RW_Stack) { if (!_sealed) { // don't activate this protection yet prot = Protection.RW; } else { var didChange = (_dirtydata[i] & WriteDetectionStatus.DidChange) != 0; if (didChange) { // don't needlessly retrigger prot = Protection.RW; } } } else if (prot == Protection.RW_Invisible) { // this never matters to the backend prot = Protection.RW; } else if (_sealed && prot == Protection.RW) { var didChange = (_dirtydata[i] & WriteDetectionStatus.DidChange) != 0; if (!didChange) { // set to trigger if we have not before prot = Protection.R; } } _pal.Protect(zstart, zend - zstart, prot); ps = i + 1; } } }
/// <summary>set r/w/x protection on a portion of memory. rounded to encompassing pages</summary> /// <exception cref="InvalidOperationException">failed to protect memory</exception> public void Protect(ulong start, ulong length, Protection prot) { if (length == 0) { return; } // Note: asking for prot.none on memory that was not previously committed, commits it var computedStart = WaterboxUtils.AlignDown(start); var computedEnd = WaterboxUtils.AlignUp(start + length); var computedLength = computedEnd - computedStart; _pal.Protect(computedStart, computedLength, prot); }
/// <summary>restore all recorded protections</summary> private void ProtectAll() { if (CommittedSize == 0) { return; } int ps = 0; int pageLimit = (int)(CommittedSize >> WaterboxUtils.PageShift); for (int i = 0; i < pageLimit; i++) { if (i == pageLimit - 1 || _pageData[i] != _pageData[i + 1]) { ulong zstart = GetStartAddr(ps); ulong zend = GetStartAddr(i + 1); var prot = _pageData[i]; _pal.Protect(zstart, zend - zstart, prot); ps = i + 1; } } }