diff --git a/Cargo.toml b/Cargo.toml
index fd0dc3b1ab3f94b05b7cbb9da0f90b3f034937c2..edf0cba3e1c9b8e9dbf07442e74bfa16940cb2a1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,6 +16,7 @@ crypto = { path = "libraries/crypto" }
 byteorder = { version = "1", default-features = false }
 arrayref = "0.3.6"
 subtle = { version = "2.2", default-features = false, features = ["nightly"] }
+linked_list_allocator = { version = "0.8.1", default-features = false }
 
 [features]
 #debug_allocations = ["libtock/debug_allocations"]
diff --git a/src/allocator.rs b/src/allocator.rs
new file mode 100644
index 0000000000000000000000000000000000000000..05e96695999c90d21aa7799a3ea774a4b263a173
--- /dev/null
+++ b/src/allocator.rs
@@ -0,0 +1,40 @@
+use core::alloc::GlobalAlloc;
+use core::alloc::Layout;
+use core::ptr;
+use core::ptr::NonNull;
+use linked_list_allocator::Heap;
+
+pub static mut HEAP: Heap = Heap::empty();
+
+struct TockAllocator;
+
+unsafe impl GlobalAlloc for TockAllocator {
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        HEAP.allocate_first_fit(layout)
+            .ok()
+            .map_or(ptr::null_mut(), NonNull::as_ptr)
+    }
+
+    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+        HEAP.deallocate(NonNull::new_unchecked(ptr), layout)
+    }
+}
+
+#[global_allocator]
+static ALLOCATOR: TockAllocator = TockAllocator;
+
+#[cfg(not(feature = "custom_alloc_error_handler"))]
+#[alloc_error_handler]
+unsafe fn alloc_error_handler(_: Layout) -> ! {
+    use crate::syscalls;
+
+    // Print 0x01 using the LowLevelDebug capsule (if available).
+    let _ = syscalls::command1_insecure(8, 2, 0x01);
+
+    // Signal a panic using the LowLevelDebug capsule (if available).
+    let _ = syscalls::command1_insecure(8, 1, 0x01);
+
+    loop {
+        syscalls::raw::yieldk();
+    }
+}
diff --git a/src/main.rs b/src/main.rs
index 661ecf841dd9fcdff8fd383da2175de590c41689..2819f81ee92e0f938111a8257f27945ec27c8ff9 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -30,6 +30,7 @@ extern crate crypto;
 
 mod ctap;
 mod usb_ctap_hid;
+mod allocator;
 
 use core::cell::Cell;
 #[cfg(feature = "debug_ctap")]
@@ -410,4 +411,4 @@ fn check_user_presence(cid: ChannelID) -> Result<(), Ctap2StatusCode> {
     } else {
         Err(Ctap2StatusCode::CTAP2_ERR_USER_ACTION_TIMEOUT)
     }
-}
\ No newline at end of file
+}