A Survey of Techniques for Improving Security of GPUs <s> Buffer overflow attack <s> We present a preliminary study of buffer overflow vulnerabilities in CUDA software running on GPUs. We show how an attacker can overrun a buffer to corrupt sensitive data or steer the execution flow by overwriting function pointers, e.g., manipulating the virtual table of a C++ object. In view of a potential mass market diffusion of GPU accelerated software this may be a major concern. <s> BIB001 </s> A Survey of Techniques for Improving Security of GPUs <s> Buffer overflow attack <s> GPU-accelerated computing gains rapidly-growing popularity in many areas such as scientific computing, database systems, and cloud environments. However, there are less investigations on the security implications of concurrently running GPU applications. In this paper, we explore security vulnerabilities of CUDA from multiple dimensions. In particular, we first present a study on GPU stack, and reveal that stack overflow of CUDA can affect the execution of other threads by manipulating different memory spaces. Then, we show that the heap of CUDA is organized in a way that allows threads from the same warp or different blocks or even kernels to overwrite each other’s content, which indicates a high risk of corrupting data or steering the execution flow by overwriting function pointers. Furthermore, we verify that integer overflow and function pointer overflow in struct also can be exploited on GPUs. But other attacks against format string and exception handler seems not feasible due to the design choices of CUDA runtime and programming language features. Finally, we propose potential solutions of preventing the presented vulnerabilities for CUDA. <s> BIB002 </s> A Survey of Techniques for Improving Security of GPUs <s> Buffer overflow attack <s> Buffer overflows are a common source of program crashes, data corruption, and security problems. In this work, we demonstrate that GPU-based workloads can also cause buffer overflows, a problem that was traditionally ignored because CPUs and GPUs had separate memory spaces. Modern GPUs share virtual, and sometimes physical, memory with CPUs, meaning that GPU-based buffer overflows are capable of producing the same program crashes, data corruption, and security problems as CPU-based overflows. While there are many tools to find buffer overflows in CPU-based applications, the shift towards GPU-enhanced programs has expanded the problem beyond their capabilities. This paper describes a tool that uses canaries to detect buffer overflows caused by GPGPU kernels. It wraps OpenCL API calls and alerts users to any kernel that writes outside of a memory buffer. We study a variety of optimizations, including using the GPU to perform the canary checks, which allow our tool to run at near application speeds. The resulting runtime overhead, which scales with the number of buffers used by the kernel, is 14% across 175 applications in 16 GPU benchmark suites. In these same suites, we found 13 buffer overflows in 7 benchmarks. <s> BIB003
In the absence of memory-access protection mechanisms, an adversary can read/write memory regions to either leak or destroy data. Miele BIB001 and Di et al. BIB002 discuss strategies for launching buffer-overflow attacks, their impact and limitations. Erb et al. BIB003 propose the use of canaries to mitigate buffer-overflow attacks. Miele BIB001 discusses ways of causing stack and heap overflows for corrupting sensitive data or changing the execution flow. They discuss two attacks. In the first attack, a function pointer in static memory is overwritten to cause undefined behavior. They consider an array with a certain starting address and a predefined maximum length. It is assumed that the address of the function to be executed is stored in the address after the last possible element in the array. If the malicious user can overwrite beyond the length of the array, causing the buffer (or array) to overflow, the address of the function to be executed can be replaced by a different value, such as the address of a malicious function. Through this, execution can be made to jump to any address in the code memory. However, they note that simple injected code execution was found to be infeasible as the code and data address spaces are separated. Similarly, overwriting "return address" was also infeasible, since the storage location of function return address is not known. The second attack is demonstrated on a dynamically allocated object. They observe that addresses of dynamically allocated memory blocks are predictable and address of the virtual table (vtable), which contains addresses of virtual functions defined in the class, can be easily obtained from a dynamically allocated object. By utilizing this, the vtable address of the object can be overwritten. Using this, a malicious function can be called. Although the attacks discussed by them do not pose an explicit threat, their work highlights the possible loopholes in GPU software. Di et al. BIB002 study buffer overflow vulnerabilities in CUDA-based GPUs. By causing a stack overflow, the address of a function pointer can be changed. Using this, execution can be directed to a malicious function. They illustrate this attack in CUDA and confirm that current GPUs do not have a mechanism to mitigate stack overflow. By causing overflow in GlM, the attack launched from a thread can be targeted to other threads. As for heap, since heap memory of different kernels/threads is allocated in contiguous locations, an overflow in the local buffer of a thread can corrupt the heap of another thread. Also, for a globally-visible heap pointer, the memory pointed by it can be accessed by threads which did not originally allocate it. This shows lack of proper access-control in GPUs. Since heap-pointer addresses can be guessed, an adversary can easily launch an attack. Similarly, two kernels that run simultaneously can corrupt the heap memory of each other. Also, for two kernels that run sequentially, the data of the first kernel remains unchanged in memory and since the pointer-address assigned to the second kernel is same as that of the first kernel, the first kernel can force the second kernel to access garbage data. Further, under/over-flows in integer arithmetic operations and function pointer overflows in struct are also possible in CUDA. However, due to features of CUDA, exception handling and format string vulnerabilities cannot be exploited. Erb et al. BIB003 present a technique for detecting runtime buffer overflows in OpenCL GPU applications. Figure 7 (a) shows a snapshot of memory, where the return address is located right after the buffer. Figure  7 (b) illustrates overwriting of the return-address by copying excessive amount of data. Their tool adds canary regions outside buffers, as shown in Figure 7 (c). After kernel execution, the canary region is checked to see if the kernel wrote beyond the limits of its memory regions. Any buffer overflow is reported to the user. The tool wraps OpenCL API calls using LD_PRELOAD mechanism. It monitors overflows in global cl mem, coarse-grained and fine-grained shared virtual memory (SVM) buffers by expanding requested buffer size to include canary regions. It does the same for global cl mem images by expanding each dimension of an image with canary regions and sub-buffers by creating shadow copies. In cases where the previously allocated CPU memory is allowed to be used as a buffer, a shadow copy is used to avoid the arduous task of updating the users' pointers. However, for images, the canaries are read into a one-dimensional array, which in turn is fed into a checker along with a buffer containing the end point for each image. SVM buffer overflows are detected using a single buffer containing pointers to the beginning of the canaries in all the SVM buffers. They note that when the number of buffers is small, the data transfer size is also small. Hence, it is preferable to perform checking of cl_mem buffers on CPU since the kernel invocation overhead of GPU cannot be amortized. However, with increasing number of buffers, a single GPU routine can check multiple canary regions in parallel and hence, using GPU checker is preferable. For SVM buffers and images, CPU checking always incurs higher overhead due to the need for performing data transfers. They show that their tool can detect even those overflows, which are not detected by other tools. A limitation of their technique is that canaries are checked only after completion of the kernel. Hence, before the canaries are checked, a garbage value may get consumed, and the canaries can be reset which avoids detection of overflow. Further, an adversary who knows the canary size can overwrite beyond it. Thus, their tool does not fully guarantee security. Also, the use of canaries wastes memory capacity.