Counterfeit storage devices, such as USB flash drives and SSDs with modified controller firmware that report false capacities, rely on address wrapping: writes beyond physical memory silently overwrite earlier blocks modulo the actual capacity.
With increased interest in home AI labs, one could imagine similar practices to start appearing in the second-hand GPU market. While physical PCI configuration registers report the Base Address Register (BAR) window, verifying actual silicon framebuffer integrity requires filling the advertised VRAM with distinct, non-repeating data patterns and reading all bytes back sequentially.
Here’s a Python script that validates VRAM integrity for CUDA GPUs under Linux:
import ctypesimport sys# Load the NVIDIA CUDA Driver API shared library (bypasses CUDA Toolkit / PyTorch requirements)try: cuda = ctypes.CDLL("libcuda.so.1")except OSError: print("Error: NVIDIA CUDA driver library (libcuda.so.1) not found.") sys.exit(1)def check(status, function_name): """CUDA Driver API functions return 0 (CUDA_SUCCESS) on success.""" if status != 0: print(f"CUDA Error {status} encountered in {function_name}()") sys.exit(1)# 1. Initialize the CUDA Driver API subsystemcheck(cuda.cuInit(0), "cuInit")# 2. Get a handle to the primary GPU (Device index 0)device = ctypes.c_int()check(cuda.cuDeviceGet(ctypes.byref(device), 0), "cuDeviceGet")# 3. Create an execution context on the GPU (equivalent to creating a runtime session)context = ctypes.c_void_p()check(cuda.cuCtxCreate_v2(ctypes.byref(context), 0, device), "cuCtxCreate")# 4. Query total and free VRAM reported by the driverfree_mem = ctypes.c_size_t()total_mem = ctypes.c_size_t()check(cuda.cuMemGetInfo_v2(ctypes.byref(free_mem), ctypes.byref(total_mem)), "cuMemGetInfo")total_gb = total_mem.value / (1024**3)free_gb = free_mem.value / (1024**3)print(f"Reported VRAM: {total_gb:.2f} GB Total | {free_gb:.2f} GB Available")# Test parametersCHUNK_SIZE = 1024 * 1024 * 1024 # 1 GiB per allocationNUM_CHUNKS = int(free_gb) - 1 # Leave 1 GB margin for driver structuresallocations = []print(f"\n[Phase 1] Allocating and writing unique byte patterns across {NUM_CHUNKS} GB...")for i in range(NUM_CHUNKS): dptr = ctypes.c_uint64() # cuMemAlloc allocates linear physical memory on the GPU device check(cuda.cuMemAlloc_v2(ctypes.byref(dptr), CHUNK_SIZE), f"cuMemAlloc Chunk {i+1}") # Generate an offset-shifted pattern unique to this specific 1 GB chunk pattern_block = bytes([(x + i * 17) & 0xFF for x in range(1024 * 1024)]) host_data = pattern_block * 1024 # cuMemcpyHtoD copies raw bytes from Host (RAM) to Device (VRAM) check(cuda.cuMemcpyHtoD_v2(dptr, host_data, CHUNK_SIZE), f"cuMemcpyHtoD Chunk {i+1}") allocations.append((dptr, pattern_block)) print(f" -> Written Chunk {i+1:02d}/{NUM_CHUNKS} ({(i+1)} GB mapped)")print("\n[Phase 2] Reading back all chunks to detect address wrapping or corruption...")all_passed = True# Pre-allocate a contiguous C-compatible character buffer to receive DMA dataread_buf = (ctypes.c_char * CHUNK_SIZE)()for i, (dptr, pattern_block) in enumerate(allocations): # cuMemcpyDtoH copies raw bytes from Device (VRAM) back to Host (RAM) check(cuda.cuMemcpyDtoH_v2(read_buf, dptr, CHUNK_SIZE), f"cuMemcpyDtoH Chunk {i+1}") expected_data = pattern_block * 1024 if bytes(read_buf) == expected_data: print(f" -> Chunk {i+1:02d}/{NUM_CHUNKS}: PASS") else: print(f" -> Chunk {i+1:02d}/{NUM_CHUNKS}: FAIL (Address wrapping detected)") all_passed = False break# 5. Free GPU device memory pointers and destroy the driver contextfor dptr, _ in allocations: cuda.cuMemFree_v2(dptr)cuda.cuCtxDestroy_v2(context)if all_passed: print(f"\n[VERDICT] PASS: All {NUM_CHUNKS} GB verified as unique physical VRAM.")else: print("\n[VERDICT] FAIL: Framebuffer mismatch or data corruption detected.")
Verification Logic
- Allocation phase: Commits physical memory in 1 GiB blocks via
cuMemAlloc_v2. If the GPU has fewer physical chips than claimed, the driver or kernel will fail allocation before reachingNUM_CHUNKS. - Pattern ingestion: Every chunk receives a unique bit pattern derived from its index.
- Full-Sweep readback: No data is verified until all chunks have been written. If a card possesses only 8 GB of physical RAM but claims 24 GB, Chunk 9 will overwrite chunk 1 in physical silicon; verifying chunk 1 at the end exposes the address wrap.