Scudo는 동적 사용자 모드 메모리 할당자 또는 힙 할당자로, 힙 관련 취약점(예: 힙 기반 버퍼 오버플로, use after free, double free)에 대비한 복원력을 갖춘 동시에 성능도 유지할 수 있도록 설계되었습니다. 표준 C 할당 및 할당 해제 프리미티브(예: malloc 및 free)뿐만 아니라 C++ 프리미티브(예: new 및 delete)도 제공합니다.
Android 11 출시부터는 모든 네이티브 코드에 Scudo가 사용됩니다(메모리 용량이 낮은 기기는 예외이며 계속 jemalloc이 사용됨). 런타임 시 모든 네이티브 힙 할당 및 할당 해제가 Scudo에서 모든 실행 파일 및 파일의 라이브러리 종속 항목에 제공되며 힙에서 손상이나 의심스러운 동작이 감지되면 프로세스가 중단됩니다.
아래에 설명된 옵션을 사용하여 Scudo 내에서 추가 완화를 사용 설정하거나 사용 중지할 수 있습니다.
맞춤설정
할당자의 일부 매개변수는 다음과 같은 여러 방법을 통해 프로세스별로 정의할 수 있습니다.
정적: 파싱할 옵션 문자열을 반환하는 __scudo_default_options 함수를 프로그램에 정의합니다. 이 함수에는 extern "C" const char
*__scudo_default_options() 프로토타입이 있어야 합니다.
동적: 파싱할 옵션 문자열을 포함하는 SCUDO_OPTIONS 환경 변수를 사용합니다. 이 방식으로 정의된 옵션은 __scudo_default_options를 통해 만들어진 모든 정의보다 우선합니다.
사용할 수 있는 옵션은 다음과 같습니다.
옵션
64비트 기본값
32비트 기본값
설명
QuarantineSizeKb
256
64
청크의 실제 할당 해제를 지연하는 데 사용되는 격리 저장소의 크기(KB)입니다. 값이 낮을수록 메모리 사용량은 줄지만 완화 효과가 감소할 수 있습니다. 음수 값은 기본값으로 대체됩니다. 이 값과 ThreadLocalQuarantineSizeKb를 0으로 설정하면 격리 저장소가 완전히 사용 중지됩니다.
QuarantineChunksUpToSize
2048
512
청크를 격리할 수 있는 최대 크기(바이트)입니다.
ThreadLocalQuarantineSizeKb
64
16
전역 격리 저장소를 오프로드하는 데 사용하는 스레드당 캐시 크기(KB)입니다.
값이 낮을수록 메모리 사용량은 줄지만 전역 격리 저장소에서의 경합이 증가할 수 있습니다. 이 값과 QuarantineSizeKb를 0으로 설정하면 격리 저장소가 완전히 사용 중지됩니다.
DeallocationTypeMismatch
false
false
malloc/delete, new/free, new/delete[] 오류 신고를 사용 설정합니다.
DeleteSizeMismatch
true
true
new와 delete의 크기 불일치 오류 신고를 사용 설정합니다.
ZeroContents
false
false
할당 및 할당 해제 시 제로 청크 콘텐츠를 사용 설정합니다.
allocator_may_return_null
false
false
복구가 가능한 오류가 발생할 때 프로세스를 종료하는 대신 할당자가 null을 반환할 수 있도록 지정합니다.
hard_rss_limit_mb
0
0
프로세스의 RSS가 이 한도에 도달하면 프로세스가 종료됩니다.
soft_rss_limit_mb
0
0
프로세스의 RSS가 이 한도에 도달하면 다시 새로운 할당을 허용할 때까지 allocator_may_return_null의 값에 따라 추가 할당이 실패하거나 null을 반환합니다.
allocator_release_to_os_interval_ms
5000
N/A
64비트 할당자에만 영향을 줍니다. 이 옵션을 설정하면 사용되지 않는 메모리를 OS로 릴리스하려고 시도하지만 이 간격(밀리초)보다 더 짧은 간격으로 시도하지는 않습니다.
값이 음수이면 메모리가 OS로 릴리스되지 않습니다.
abort_on_error
true
true
이 옵션을 설정하면 도구에서 오류 메시지를 출력한 후 _exit() 대신 abort()를 호출합니다.
유효성 검사
현재 Scudo 전용 CTS 테스트는 없습니다. 그 대신 특정 바이너리에서 Scudo의 사용 설정 여부와 상관없이 CTS 테스트를 통과하도록 하여 Scudo가 기기에 영향을 주지 않음을 검증합니다.
문제 해결
복구할 수 없는 문제가 감지되면 할당자는 표준 오류 설명자에 오류 메시지를 표시한 다음 프로세스를 종료합니다.
종료를 초래한 스택 트레이스가 시스템 로그에 추가됩니다.
출력은 일반적으로 Scudo ERROR:로 시작되며 이어서 포인터와 함께 문제가 간략하게 요약된 내용이 나옵니다.
다음은 현재 오류 메시지와 그 잠재적 원인에 대한 설명입니다.
corrupted chunk header: 청크 헤더의 체크섬 검증에 실패했습니다. 헤더가 부분적으로 또는 완전히 덮어쓰였거나 함수에 전달된 포인터가 청크가 아니기 때문일 수 있습니다.
race on chunk header: 두 개의 다른 스레드가 같은 헤더를 동시에 조작하려고 합니다. 이는 대개 청크에서 작업을 실행할 때 경합 상태이거나 전반적으로 잠금이 없다는 것을 의미합니다.
invalid chunk state: 청크가 특정 작업에 필요한 상태가 아닙니다. 예를 들어 청크를 해제하려고 할 때 할당된 상태가 아니거나, 청크를 재활용하려고 할 때 격리된 상태가 아닙니다. double free가 이 오류의 일반적인 원인입니다.
misaligned pointer: 기본 정렬 요구사항이 강력하게 적용됩니다. 32비트 플랫폼에서는 8바이트, 64비트 플랫폼에서는 16바이트입니다.
함수에 전달된 포인터가 요구사항에 맞지 않으면 함수 중 하나에 전달된 포인터가 정렬되지 않습니다.
allocation type mismatch: 이 옵션을 사용하면 청크에서 호출되는 할당 해제 함수는 할당을 위해 호출된 함수의 유형과 일치해야 합니다.
이러한 유형의 불일치는 보안 문제를 일으킬 수 있습니다.
invalid sized delete: C++14로 크기가 조정된 delete 연산자를 사용하고 선택적 검사를 사용 설정하면 청크를 할당 해제할 때 전달된 크기와 할당할 때 요청된 크기 간의 불일치가 발생합니다.
이러한 불일치는 일반적으로 컴파일러에 문제가 있기 때문이거나 할당 해제되는 객체 유형의 혼동으로 인해 발생합니다.
RSS limit exhausted: 선택적으로 지정한 RSS의 최댓값을 초과했습니다.
OS 자체에서 비정상 종료를 디버그하는 경우 HWASan OS 빌드를 사용할 수 있습니다. 앱에서 비정상 종료를 디버그하는 경우 역시 HWASan 앱 빌드를 사용할 수 있습니다.
이 페이지에 나와 있는 콘텐츠와 코드 샘플에는 콘텐츠 라이선스에서 설명하는 라이선스가 적용됩니다. 자바 및 OpenJDK는 Oracle 및 Oracle 계열사의 상표 또는 등록 상표입니다.
최종 업데이트: 2025-07-27(UTC)
[[["이해하기 쉬움","easyToUnderstand","thumb-up"],["문제가 해결됨","solvedMyProblem","thumb-up"],["기타","otherUp","thumb-up"]],[["필요한 정보가 없음","missingTheInformationINeed","thumb-down"],["너무 복잡함/단계 수가 너무 많음","tooComplicatedTooManySteps","thumb-down"],["오래됨","outOfDate","thumb-down"],["번역 문제","translationIssue","thumb-down"],["샘플/코드 문제","samplesCodeIssue","thumb-down"],["기타","otherDown","thumb-down"]],["최종 업데이트: 2025-07-27(UTC)"],[],[],null,["# Scudo is a dynamic user-mode memory allocator, or *heap* allocator, designed\nto be resilient against heap-related vulnerabilities (such as [heap-based buffer\noverflow](https://cwe.mitre.org/data/definitions/122.html), [use after free](https://cwe.mitre.org/data/definitions/416.html),\nand [double free](https://cwe.mitre.org/data/definitions/415.html))\nwhile maintaining performance. It provides the standard C allocation and\ndeallocation primitives (such as [malloc](http://pubs.opengroup.org/onlinepubs/009695399/functions/malloc.html) and free), as well as the C++ primitives (such as new and delete).\n\nScudo is more of a mitigation than a fully fledged memory error\ndetector like [AddressSanitizer (ASan)](/docs/security/test/sanitizers#addresssanitizer).\n\nSince the Android 11 release, scudo is used for all native code\n(except on low-memory devices, where jemalloc is still used). At runtime, all native heap\nallocations and deallocations are serviced by Scudo for all executables and their library\ndependencies, and the process is aborted if a corruption or suspicious\nbehavior is detected in the heap.\n\nScudo is [open source](https://github.com/llvm/llvm-project/tree/main/compiler-rt/lib/scudo) and part of LLVM's compiler-rt project. Documentation is\navailable at \u003chttps://llvm.org/docs/ScudoHardenedAllocator.html\u003e. The Scudo runtime ships\nas part of the Android toolchain and support was added to [Soong and Make](https://android.googlesource.com/platform/build/soong/)\nto allow for easy enabling of the allocator in a binary.\n\nYou can enable or disable extra mitigation within\nthe allocator using the options described below.\n\nCustomization\n-------------\n\nSome parameters of the allocator can be defined on a per-process basis\nthrough several ways:\n\n- **Statically:** Define a `__scudo_default_options` function in the program that returns the options string to be parsed. This function must have the following prototype: `extern \"C\" const char\n *__scudo_default_options()`.\n- **Dynamically:** Use the environment variable `SCUDO_OPTIONS` containing the options string to be parsed. Options defined this way override any definition made through `__scudo_default_options`.\n\nThe following options are available.\n| **Note:** Frontend options have a different name format than backend options.\n\n| Option | 64-bit default | 32-bit default | Description |\n|---------------------------------------|----------------|----------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `QuarantineSizeKb` | `256` | `64` | The size (in KB) of quarantine used to delay the actual deallocation of chunks. A lower value may reduce memory usage but decrease the effectiveness of the mitigation; a negative value falls back to the defaults. Setting both this and `ThreadLocalQuarantineSizeKb` to zero disables the quarantine entirely. |\n| `QuarantineChunksUpToSize` | `2048` | `512` | The size (in bytes) up to which chunks can be quarantined. |\n| `ThreadLocalQuarantineSizeKb` | `64` | `16` | The size (in KB) of per-thread cache use to offload the global quarantine. A lower value may reduce memory usage but might increase contention on the global quarantine. Setting both this and `QuarantineSizeKb` to zero disables the quarantine entirely. |\n| `DeallocationTypeMismatch` | `false` | `false` | Enables error reporting on malloc/delete, new/free, new/delete\\[\\] |\n| `DeleteSizeMismatch` | `true` | `true` | Enables error reporting on mismatch between sizes of new and delete. |\n| `ZeroContents` | `false` | `false` | Enables zero chunk contents on allocation and deallocation. |\n| `allocator_may_return_null` | `false` | `false` | Specifies that the allocator can return null when a recoverable error occurs, instead of terminating the process. |\n| `hard_rss_limit_mb` | `0` | `0` | When the process's RSS reaches this limit, the process terminates. |\n| `soft_rss_limit_mb` | `0` | `0` | When the process's RSS reaches this limit, further allocations fail or return `null` (depending on the value of `allocator_may_return_null`), until the RSS goes back down to allow for new allocations. |\n| `allocator_release_to_os_interval_ms` | `5000` | N/A | Only affects a 64-bit allocator. If set, tries to release unused memory to the OS, but not more often than this interval (in milliseconds). If the value is negative, memory isn't released to the OS. |\n| `abort_on_error` | `true` | `true` | If set, the tool calls `abort()` instead of `_exit()` after printing the error message. |\n\nValidation\n----------\n\nCurrently, there are no CTS tests specifically for Scudo. Instead, make sure\nthat CTS tests pass with or without Scudo enabled for a given binary to verify\nthat it doesn't impact the device.\n\nTroubleshooting\n---------------\n\nIf a non-recoverable issue is detected, the allocator\ndisplays an error message to the standard error descriptor and then terminates the process.\nStack traces that lead to the termination are added in the system log.\nThe output usually starts with `Scudo ERROR:` followed by a\nshort summary of the problem along with any pointers.\n| **Note:** Again, Scudo is meant to be a mitigation. Consider using ASan to determine the root cause of the issue.\n\nHere is a list of the current error messages and their potential\ncauses:\n\n- `corrupted chunk header`: The checksum verification of the chunk header has failed. This is likely due to one of two things: the header was overwritten (partially or totally), or the pointer passed to the function is not a chunk.\n- `race on chunk header`: Two different threads are attempting to manipulate the same header at the same time. This is usually symptomatic of a race-condition or general lack of locking when performing operations on that chunk.\n- `invalid chunk state`: The chunk isn't in the expected state for a given operation, for example, it's not allocated when trying to free it, or it's not quarantined when trying to recycle it. A double free is the typical reason for this error.\n- `misaligned pointer`: Basic alignment requirements are strongly enforced: 8 bytes on 32-bit platforms and 16 bytes on 64-bit platforms. If a pointer passed to our functions does not fit those, the pointer passed to one of the functions is out of alignment.\n- `allocation type mismatch`: When this option is enabled, a deallocation function called on a chunk has to match the type of function that was called to allocate it. This type of mismatch can introduce security issues.\n- `invalid sized delete`: When the C++14 sized delete operator is used, and the optional check is enabled, there's a mismatch between the size that was passed when deallocating a chunk and the size that was requested when allocating it. This is typically a compiler issue or a [type confusion](https://cwe.mitre.org/data/definitions/843.html) on the object being deallocated.\n- `RSS limit exhausted`: The maximum RSS optionally specified has been exceeded.\n\n\nIf you're debugging a crash in the OS itself, you can use a\n[HWASan OS build](/devices/tech/debug/hwasan). If you're\ndebugging a crash in an app, it's possible to use a\n[HWASan app build](https://developer.android.com/ndk/guides/hwasan) too."]]