// ----------------------------- // ---- PAL layer ends here ---- // ----------------------------- private void EnsureCapacity(int capacity) { // Make sure the requested capacity doesn't exceed SecureString's defined limit if (capacity > MaxLength) { throw new ArgumentOutOfRangeException("capacity", SR.ArgumentOutOfRange_Capacity); } // If we already have enough space allocated, we're done if (_buffer != null && (capacity * sizeof(char)) <= (int)_buffer.ByteLength) { return; } // We need more space, so allocate a new buffer, copy all our data into it, // and then swap the new for the old. ProtectedBuffer newBuffer = ProtectedBuffer.Allocate(capacity * sizeof(char)); if (_buffer != null) { using (_buffer.Unprotect()) ProtectedBuffer.Copy(_buffer, newBuffer, _buffer.ByteLength); newBuffer.Protect(); _buffer.Dispose(); } _buffer = newBuffer; }
internal static unsafe void Copy(ProtectedBuffer source, ProtectedBuffer destination, ulong bytesLength) { if (bytesLength == 0) { return; } byte *srcPtr = null, dstPtr = null; try { source.AcquirePointer(ref srcPtr); destination.AcquirePointer(ref dstPtr); Buffer.MemoryCopy(srcPtr, dstPtr, destination.ByteLength, bytesLength); } finally { if (dstPtr != null) { destination.ReleasePointer(); } if (srcPtr != null) { source.ReleasePointer(); } } }
[System.Security.SecuritySafeCritical] // auto-generated private void DisposeCore() { if (_buffer != null && !_buffer.IsInvalid) { _buffer.Dispose(); _buffer = null; } }
internal static ProtectedBuffer Allocate(int bytes) { Debug.Assert(bytes >= 0); // Round the number of bytes up to the next page size boundary. mmap // is going to allocate pages, anyway, and we lock/protect entire pages, // so we might as well benefit from being able to use all of that space, // rather than allocating it and having it be unusable. As a SecureString // grows, this will significantly help in avoiding unnecessary recreations // of the buffer. Debug.Assert(s_pageSize > 0); ulong nativeBytes = RoundUpToPageSize(bytes); Debug.Assert((long)nativeBytes % s_pageSize == 0); ProtectedBuffer buffer = new ProtectedBuffer(); IntPtr ptr = IntPtr.Zero; try { // Allocate the page(s) for the buffer. ptr = Interop.Sys.MMap( IntPtr.Zero, nativeBytes, Interop.Sys.MemoryMappedProtections.PROT_READ | Interop.Sys.MemoryMappedProtections.PROT_WRITE, Interop.Sys.MemoryMappedFlags.MAP_ANONYMOUS | Interop.Sys.MemoryMappedFlags.MAP_PRIVATE, 0, 0); if (ptr == IntPtr.Zero) // note that shim uses null pointer, not non-null MAP_FAILED sentinel { throw CreateExceptionFromErrno(); } // Lock the pages into memory to minimize the chances that the pages get // swapped out, making the contents available on disk. if (Interop.Sys.MLock(ptr, nativeBytes) != 0) { throw CreateExceptionFromErrno(); } } catch { // Something failed; release the allocation if (ptr != IntPtr.Zero) { Interop.Sys.MUnmap(ptr, nativeBytes); // ignore any errors } throw; } // The memory was allocated; initialize the buffer with it. buffer.SetHandle(ptr); buffer.Initialize((ulong)bytes); return(buffer); }
[System.Security.SecurityCritical] // auto-generated internal unsafe IntPtr ToUniStrCore() { int length = _decryptedLength; byte * bufferPtr = null; IntPtr stringPtr = IntPtr.Zero, result = IntPtr.Zero; try { // Allocate space for the string to be returned, including space for a null terminator if ((stringPtr = Marshal.AllocCoTaskMem((length + 1) * sizeof(char))) == IntPtr.Zero) { throw new OutOfMemoryException(); } _buffer.AcquirePointer(ref bufferPtr); // Copy all of our data into it using (_buffer.Unprotect()) Buffer.MemoryCopy( source: bufferPtr, destination: (byte *)stringPtr.ToPointer(), destinationSizeInBytes: ((length + 1) * sizeof(char)), sourceBytesToCopy: length * sizeof(char)); // Add the null termination *(length + (char *)stringPtr.ToPointer()) = '\0'; // Finally store the string pointer into our result. We maintain // a separate result variable to make clean up in the finally easier. result = stringPtr; } finally { // If there was a failure, such that result isn't initialized, // release the string if we had one. if (stringPtr != IntPtr.Zero && result == IntPtr.Zero) { ProtectedBuffer.ZeroMemory((byte *)stringPtr, (ulong)(length * sizeof(char))); Marshal.FreeCoTaskMem(stringPtr); } if (bufferPtr != null) { _buffer.ReleasePointer(); } } return(result); }
[System.Security.SecurityCritical] // auto-generated internal unsafe SecureString(SecureString str) { // Allocate enough space to store the provided string EnsureCapacity(str._decryptedLength); _decryptedLength = str._decryptedLength; // Copy the string into the newly allocated space if (_decryptedLength > 0) { using (str._buffer.Unprotect()) ProtectedBuffer.Copy(str._buffer, _buffer, (ulong)(str._decryptedLength * sizeof(char))); } // Protect the buffer _buffer.Protect(); }
internal ProtectOnDispose(ProtectedBuffer buffer) { Debug.Assert(buffer != null); _buffer = buffer; }
internal static unsafe void Copy(ProtectedBuffer source, ProtectedBuffer destination, ulong bytesLength) { if (bytesLength == 0) return; byte* srcPtr = null, dstPtr = null; try { source.AcquirePointer(ref srcPtr); destination.AcquirePointer(ref dstPtr); Buffer.MemoryCopy(srcPtr, dstPtr, destination.ByteLength, bytesLength); } finally { if (dstPtr != null) destination.ReleasePointer(); if (srcPtr != null) source.ReleasePointer(); } }
internal static ProtectedBuffer Allocate(int bytes) { Debug.Assert(bytes >= 0); // Round the number of bytes up to the next page size boundary. mmap // is going to allocate pages, anyway, and we lock/protect entire pages, // so we might as well benefit from being able to use all of that space, // rather than allocating it and having it be unusable. As a SecureString // grows, this will significantly help in avoiding unnecessary recreations // of the buffer. Debug.Assert(s_pageSize > 0); ulong nativeBytes = RoundUpToPageSize(bytes); Debug.Assert((long)nativeBytes % s_pageSize == 0); ProtectedBuffer buffer = new ProtectedBuffer(); IntPtr ptr = IntPtr.Zero; try { // Allocate the page(s) for the buffer. ptr = Interop.Sys.MMap( IntPtr.Zero, nativeBytes, Interop.Sys.MemoryMappedProtections.PROT_READ | Interop.Sys.MemoryMappedProtections.PROT_WRITE, Interop.Sys.MemoryMappedFlags.MAP_ANONYMOUS | Interop.Sys.MemoryMappedFlags.MAP_PRIVATE, 0, 0); if (ptr == IntPtr.Zero) // note that shim uses null pointer, not non-null MAP_FAILED sentinel throw CreateExceptionFromErrno(); // Lock the pages into memory to minimize the chances that the pages get // swapped out, making the contents available on disk. if (Interop.Sys.MLock(ptr, nativeBytes) != 0) throw CreateExceptionFromErrno(); } catch { // Something failed; release the allocation if (ptr != IntPtr.Zero) Interop.Sys.MUnmap(ptr, nativeBytes); // ignore any errors throw; } // The memory was allocated; initialize the buffer with it. buffer.SetHandle(ptr); buffer.Initialize((ulong)bytes); return buffer; }
// ----------------------------- // ---- PAL layer ends here ---- // ----------------------------- private void EnsureCapacity(int capacity) { // Make sure the requested capacity doesn't exceed SecureString's defined limit if (capacity > MaxLength) throw new ArgumentOutOfRangeException("capacity", SR.ArgumentOutOfRange_Capacity); // If we already have enough space allocated, we're done if (_buffer != null && (capacity * sizeof(char)) <= (int)_buffer.ByteLength) return; // We need more space, so allocate a new buffer, copy all our data into it, // and then swap the new for the old. ProtectedBuffer newBuffer = ProtectedBuffer.Allocate(capacity * sizeof(char)); if (_buffer != null) { using (_buffer.Unprotect()) ProtectedBuffer.Copy(_buffer, newBuffer, _buffer.ByteLength); newBuffer.Protect(); _buffer.Dispose(); } _buffer = newBuffer; }