コード例 #1
0
        private static INativeMemory AllocateWithoutDataPopulation(int cb, PoisonPagePlacement placement)
        {
            //
            // PRECONDITION CHECKS
            //

            if (cb < 0)
            {
                throw new ArgumentOutOfRangeException(
                          message: "Number of bytes to allocate must be non-negative.",
                          paramName: nameof(cb));
            }

            if (placement != PoisonPagePlacement.BeforeSpan && placement != PoisonPagePlacement.AfterSpan)
            {
                throw new ArgumentOutOfRangeException(
                          message: "Invalid enum value.",
                          paramName: nameof(placement));
            }

            //
            // PROCESSING
            //

            return((Environment.OSVersion.Platform == PlatformID.Win32NT)
                ? AllocateWithoutDataPopulationWindows(cb, placement) /* Windows-specific code */
                : AllocateWithoutDataPopulationDefault(cb) /* non-Windows-specific code */);
        }
コード例 #2
0
        /// <summary>
        /// Allocates a new <see cref="NativeMemory"/> region which is immediately preceded by
        /// or immediately followed by a poison (MEM_NOACCESS) page. If <paramref name="placement"/>
        /// is <see cref="PoisonPagePlacement.BeforeSpan"/>, then attempting to read the memory
        /// immediately before the returned <see cref="NativeMemory"/> will result in an AV.
        /// If <paramref name="placement"/> is <see cref="PoisonPagePlacement.AfterSpan"/>, then
        /// attempting to read the memory immediately after the returned <see cref="NativeMemory"/>
        /// will result in AV.
        /// </summary>
        /// <remarks>
        /// The newly-allocated memory will be populated with random data.
        /// </remarks>
        public static INativeMemory Allocate(int cb, PoisonPagePlacement placement)
        {
            var retVal = AllocateWithoutDataPopulation(cb, placement);

            new Random().NextBytes(retVal.Span); // doesn't need to be cryptographically strong
            return(retVal);
        }
コード例 #3
0
        private static INativeMemory AllocateWithoutDataPopulationWindows(int cb, PoisonPagePlacement placement)
        {
            long totalBytesToAllocate = cb;

            checked
            {
                // We only need to round cb up if it's not an exact multiple
                // of the system page size.

                var leftoverBytes = cb % SystemPageSize;
                if (leftoverBytes != 0)
                {
                    totalBytesToAllocate += SystemPageSize - leftoverBytes;
                }

                // Finally, account for the poison pages at the front and back.

                totalBytesToAllocate += 2 * SystemPageSize;
            }

            // Reserve and commit the entire range as NOACCESS.

            var handle = UnsafeNativeMethods.VirtualAlloc(
                lpAddress: IntPtr.Zero,
                dwSize: (IntPtr)totalBytesToAllocate /* cast throws OverflowException if out of range */,
                flAllocationType: VirtualAllocAllocationType.MEM_RESERVE | VirtualAllocAllocationType.MEM_COMMIT,
                flProtect: VirtualAllocProtection.PAGE_NOACCESS);

            if (handle == null || handle.IsInvalid)
            {
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
                throw new InvalidOperationException("VirtualAlloc failed unexpectedly.");
            }

            // Done allocating! Now carve out a READWRITE section bookended by the NOACCESS
            // pages and return that carved-out section to the caller. Since memory protection
            // flags only apply at page-level granularity, we need to "left-align" or "right-
            // align" the section we carve out so that it's guaranteed adjacent to one of
            // the NOACCESS bookend pages.

            return(new VirtualAllocWrapper(
                       handle: handle,
                       offset: (placement == PoisonPagePlacement.BeforeSpan)
                    ? SystemPageSize /* just after leading poison page */
                    : checked ((int)(totalBytesToAllocate - SystemPageSize - cb)) /* just before trailing poison page */,
                       length: cb)
            {
                Protection = VirtualAllocProtection.PAGE_READWRITE
            });
        }
コード例 #4
0
        /// <summary>
        /// Allocates a new <see cref="BoundedMemory{T}"/> region which is immediately preceded by
        /// or immediately followed by a poison (MEM_NOACCESS) page. If <paramref name="placement"/>
        /// is <see cref="PoisonPagePlacement.Before"/>, then attempting to read the memory
        /// immediately before the returned <see cref="BoundedMemory{T}"/> will result in an AV.
        /// If <paramref name="placement"/> is <see cref="PoisonPagePlacement.After"/>, then
        /// attempting to read the memory immediately after the returned <see cref="BoundedMemory{T}"/>
        /// will result in AV.
        /// </summary>
        /// <remarks>
        /// The newly-allocated memory will be populated with random data.
        /// </remarks>
        public static BoundedMemory <T> Allocate <T>(int elementCount, PoisonPagePlacement placement = PoisonPagePlacement.After) where T : unmanaged
        {
            if (elementCount < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(elementCount));
            }
            if (placement != PoisonPagePlacement.Before && placement != PoisonPagePlacement.After)
            {
                throw new ArgumentOutOfRangeException(nameof(placement));
            }

            var retVal = AllocateWithoutDataPopulation <T>(elementCount, placement);

            FillRandom(MemoryMarshal.AsBytes(retVal.Span));
            return(retVal);
        }
コード例 #5
0
        private static UnixImplementation <T> AllocateWithoutDataPopulation <T>(int elementCount, PoisonPagePlacement placement) where T : unmanaged
        {
            // On non-Windows platforms, we don't yet have support for changing the permissions of individual pages.

            return(new UnixImplementation <T>(elementCount));
        }
コード例 #6
0
 public BoundedUtf8Span(ReadOnlySpan <byte> utf8Data, PoisonPagePlacement placement = PoisonPagePlacement.After)
 {
     _boundedMemory = BoundedMemory.AllocateFromExistingData(utf8Data, placement);
 }
コード例 #7
0
 public BoundedUtf8Span(ReadOnlySpan <char> utf16Data, PoisonPagePlacement placement = PoisonPagePlacement.After)
     : this(u8(utf16Data.ToString()).AsBytes(), placement)
 {
 }
コード例 #8
0
 /// <summary>
 /// Similar to <see cref="Allocate(int, PoisonPagePlacement)"/>, but populates the allocated
 /// native memory block from existing data rather than using random data.
 /// </summary>
 public static BoundedMemory <T> AllocateFromExistingData <T>(T[] data, PoisonPagePlacement placement = PoisonPagePlacement.After) where T : unmanaged
 {
     return(AllocateFromExistingData(new ReadOnlySpan <T>(data), placement));
 }
コード例 #9
0
        /// <summary>
        /// Similar to <see cref="Allocate(int, PoisonPagePlacement)"/>, but populates the allocated
        /// native memory block from existing data rather than using random data.
        /// </summary>
        public static BoundedMemory <T> AllocateFromExistingData <T>(ReadOnlySpan <T> data, PoisonPagePlacement placement = PoisonPagePlacement.After) where T : unmanaged
        {
            if (placement != PoisonPagePlacement.Before && placement != PoisonPagePlacement.After)
            {
                throw new ArgumentOutOfRangeException(nameof(placement));
            }

            var retVal = AllocateWithoutDataPopulation <T>(data.Length, placement);

            data.CopyTo(retVal.Span);
            return(retVal);
        }
コード例 #10
0
ファイル: BoundedMemory.Unix.cs プロジェクト: z77ma/runtime
        private static UnixImplementation <T> AllocateWithoutDataPopulationUnix <T>(int elementCount, PoisonPagePlacement placement) where T : unmanaged
        {
            // On non-Windows platforms, we don't yet have support for changing the permissions of individual pages.
            // We'll instead use AllocHGlobal / FreeHGlobal to carve out a r+w section of unmanaged memory.

            return(new UnixImplementation <T>(elementCount));
        }
コード例 #11
0
        /// <summary>
        /// Similar to <see cref="Allocate(int, PoisonPagePlacement)"/>, but populates the allocated
        /// native memory block from existing data rather than using random data.
        /// </summary>
        public static INativeMemory AllocateFromExistingData(ReadOnlySpan <byte> data, PoisonPagePlacement placement)
        {
            var retVal = AllocateWithoutDataPopulation(data.Length, placement);

            data.CopyTo(retVal.Span);
            return(retVal);
        }
コード例 #12
0
 private static BoundedMemory <T> AllocateWithoutDataPopulation <T>(int elementCount, PoisonPagePlacement placement) where T : unmanaged
 {
     if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
     {
         return(AllocateWithoutDataPopulationWindows <T>(elementCount, placement));
     }
     else
     {
         return(AllocateWithoutDataPopulationUnix <T>(elementCount, placement));
     }
 }
コード例 #13
0
 public BoundedUtf8Span(string utf16Data, PoisonPagePlacement placement = PoisonPagePlacement.After)
     : this(utf16Data.AsSpan(), placement)
 {
 }