4

I am involved in both macOS and Linux.

Linux automatically erases every freed memory in order to prevent leakage of information left in freed memory, and also to prevent attacks that seek or rely on information left in freed memory (e.g. uninitialized variable attacks, use-after-free attacks, reuse attacks, stack content exposures, and heap content exposures) (https://www.kernel.org/doc/html/v4.18/security/self-protection.html). I like this feature of Linux, and I am wondering if macOS has this feature as well.

  1. Does macOS automatically erase every freed memory?

  2. (Assuming #1 is positive) Since which version of MacOSX, OSX or macOS, has it been equipped with this feature of automatic erasure of freed memory?

When you answer, try to point out an official Apple document (either at developer.apple.com or support.apple.com but NOT forum.apple.com) that supports your answer.

By the way, Linux Kernel Self-Protection includes "memory poisoning", which does more than "memory erasure". "Memory Poisoning" fills the freed memory with a special signature in order to identify bad or corrupted memory data and warn the system when this bad data is eventually read (https://patents.google.com/patent/US20140006879A1/en).

  • 2
    “Linux automatically erases every freed memory” No it doesn't, not without a third-party kernel patch (and I'm not aware of one that's currently maintained and freely available: it's a part of Grsecurity). – Gilles 'SO- stop being evil' Aug 17 '21 at 10:10
  • @Gilles'SO-stopbeingevil', it's been part of mainline Linux for a while (Kernel Hacking -> Memory Debugging -> Poison pages after freeing), but because of the performance impact, it's not always enabled. – Mark Aug 17 '21 at 20:31
  • Please clarify. What do you mean by 'freed memory'? Could mean memory released to kernel pools (as first answer) or physical memory released to free list (less popular answer). If the former, I will delete my answer. – Gilby Aug 17 '21 at 23:19

2 Answers2

13

Your question is a bit vague and therefore hard to answer.

Contrary to what you write, Linux does not automatically erase every bit of freed memory on the system. To answer your question #1, macOS does not do this either.

I think your misconception about Linux comes from the fact that Linux can clear freed kernel memory, if configured to do so. On normal systems that is only a small fraction of the total system memory.

If you look at user space applications on macOS, the developer can set it up so that memory is cleared or poisoned on free. For performance reasons, this is mostly done with parts of memory where secrets can be leaked (such as for example cryptographic keys).

If you're interesting purely in the kernel itself, then the macOS kernel also has features related to zeroing and poisoning freed memory. The kernel includes a zone allocator, where zones can be setup to be zeroed, poisoned (i.e. 0xdeadbeef written all over) or merely canaried (i.e. a canary - specific data bytes - is written to the start and end of the allocation - primarily to catch bugs).

The kernel by default enables instant poisoning for very small alloocations (up to the size of the CPU's cache line size - depends on the CPU, but could for example be 64 bytes). For larger allocations, freed memory is periodically poisoned with a frequency depending on the size of the allocation. Instant poisoning of very large allocations comes with a performance impact, so this reduces or at least spreads out that impact.

You can find the source code for the zone allocator here:

https://github.com/apple/darwin-xnu/blob/main/osfmk/kern/zalloc.c

Looking back at the version history, I can see that memory poisoning was included as an option back in 2009 - this would place it just before Mac OS X Snow Leopard.

As far as I know, memory poisoning was included in iOS 2 (at the time called iPhone OS), which means that it was probably implemented by Apple in 2008. The public source dump for the macOS kernel includes this in 2009. It seems to me that it was introduced as a feature in Linux in 2009 in this patch:

https://lwn.net/Articles/321595/

In addition to the generic VM feature, the macOS kernel also features a system similar to the Linux Kernel Address Sanitizer (KASAN) that also does memory poisoning. As far as I know, it was introduced in 2017.

You can find the source code for the feature here:

https://github.com/apple/darwin-xnu/tree/main/san

jksoegaard
  • 77,783
  • Correct me if I am wrong, but isn't your answer about virtual memory allocation (e.g. kernel zones are from kernel virtual memory)? I took the OP's question to be at the physical level and whether physical pages are zeroed on allocation. And would https://github.com/apple/darwin-xnu/tree/main/osfmk/vm be the relevant code? – Gilby Aug 17 '21 at 12:20
  • I suspect you might apply a slightly different semantics to the word "virtual" than others here. What do you mean exactly when you say "virtual memory"? (just checking to be sure we're actually talking about the same thing before I explain further) – jksoegaard Aug 17 '21 at 12:22
  • Forgot to ping you in the previous comment @Gilby. Note that I'm just asking because I often see that many use the word "virtual memory" to mean something different when used casually. – jksoegaard Aug 17 '21 at 12:36
  • I have asked the OP to clarify his question. Yes, I was a bit loose with 'virtual'. Lets say logical address space as in https://developer.apple.com/library/archive/documentation/Performance/Conceptual/ManagingMemory/Articles/AboutMemory.html compared with the physical pages in free list, etc. – Gilby Aug 17 '21 at 23:28
  • @Gilby In that case, what you're saying does not make sense, no. Why would it be about "the physical level"? (i.e. do you have some argument or idea?) - it's not what Linux does, it wouldn't give the same protection against the types of exploits named in the question, and it wouldn't have any benefits in comparison. – jksoegaard Aug 18 '21 at 17:42
-3

In answer to your questions:

  1. Yes
  2. Since 1985, though that needs some explanation.

macOS uses a hybrid kernel (XNU) based on Mach and BSD. The Mach component manages processes and threads, interprocess communication and memory management. Whilst Apple have added refinements, Mach remans the basis for the innermost parts of the XNU kernel.

We can go back to the 1985 for origins of Mach running on a DEC VAX. This paper Mach: A New Kernel Foundation For UNIX Development includes "Mach provides some basic paging services inside the kernel. Memory with no pager is automatically zero filled, and page-out is done to a default pager."

So from 1985 memory was automatically zero filled in projects/products based on Mach. That includes and all versions of macOS and OS X.

For current documentation from Apple, read Mach Overview which includes: "The default pager handles nonpersistent memory, known as anonymous memory. Anonymous memory is zero-initialized,...". This really is carried over directly from Mac and confirms that memory is zero-initialised.

For further reading:

  • From Apple developer documentation Kernel Programming Guide
  • If you have kernel programming skills or interest see darwin-xnu which is part of Apple's open source code.
  • For an in depth discussion of internals, you can't do better than the *OS Internals books from Jonathan Levin.
  • There are numerous macOS (OS X) memory management questions (though not your specific question) in Ask Different. You might want to start here.

I must point out that whilst I have always had an interest in kernels and operating systems, I lack programming skills for operating system programming since about 1980.

Gilby
  • 10,852
  • This answer is incorrect - as it concern the situation when allocating memory, whereas the question is about freeing memory. – jksoegaard Aug 17 '21 at 09:51
  • @jksoegaard I might argue that you are splitting hairs. It is a matter of timing. If you don't agree present the opposing case. – Gilby Aug 17 '21 at 09:55
  • 5
    The whole point of the feature is to do at free time, as there you get the advantages described in the question. You do not get those advantages by doing zeroing at allocation time. It's definitely not a case of splitting hairs. – jksoegaard Aug 17 '21 at 09:58
  • @jksoegaard I follow what you are saying. Interesting that the Linux kernel link in the question also refers to initialisation "Memory copied to userspace must always be fully initialized." And this is not at the kernel memory management level - rather when moving to user space. I await the OP's comments. – Gilby Aug 17 '21 at 10:07
  • 2
    Well, it is not really a matter of opinion - freed memory is poisoned for very specific reasons that cannot be done just as well by poisoning it at allocation time. Regarding your quote, this line referes to a separate feature of the Linux kernel, where it ensures that memory copied from the kernel to userspace is always fully initialized (i.e. either real data is written or it is zeroed). – jksoegaard Aug 17 '21 at 10:11
  • Note that the feature you quote is not implemented by the kernel as such, instead it is a feature of the C compiler. I.e. if you declare a structure and do not initialize every part of it, the compiler can warn you of this. Note that even though the kernel has these features we're talking of here, they might not actually be enabled. The "memory initialization" feature has almost no performance impact, whereas instant poisoning on free has a much larger performance impact. Some will only one of these features. Also it is possible for memory to be re-used within the kernel [...] – jksoegaard Aug 17 '21 at 10:16
  • without being freed in between. The "memory initialization" feature helps in these case, as memory poisoning on free won't come into play there. – jksoegaard Aug 17 '21 at 10:17
  • The feature I quote is part of Mach, not a warning in the C compiler. – Gilby Aug 17 '21 at 11:43
  • No it is not. By the feature you quote, I mean this quote in your comment: "Memory copied to userspace must always be fully initialized." that came from the link in the question. – jksoegaard Aug 17 '21 at 12:06
  • The question mentions zeroing memory on free to help protect against use-after-free attacks. I'm not sure how what's described in this answer helps with that? As in, very often after some memory is freed, it's not returned to the kernel, so kernel-based memory zeroing won't help there, right? – psmears Aug 17 '21 at 15:24
  • @psmears What's described in this answer definitely doesn't help with that - as it is basically something completely different than what the question is about. You're absolutely right that when you talk about user space programs, then freed memory is often not returned to the kernel right away. I'm pretty sure the question here is really only about kernel space, as the kernel features described in the question focus on the kernel itself - and not user space programs. – jksoegaard Aug 17 '21 at 17:47