0

Is RAM wiped before use in another LXC container?

 1 year ago
source link: https://security.stackexchange.com/questions/269507/is-ram-wiped-before-use-in-another-lxc-container
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

4 Answers

This isn't how memory allocation in linux works, so your scenario is not right.

The linux kernel maintains a pool of free pages and quickly freeable pages (which includes cached disk blocks and process pages already written to swap but still in ram). Of these pages, it also keeps a pool of pre-zeroed pages (the size of this pool is adjustable). When a process needs a new memory page, it is pulled from this pool.

When a process asks for a new page, it will get a zeroed page, and won't get a page with data from another process. Generally, a process can't access another process's memory, but there are many exceptions (see a partial list below).

While new pages will arrive from the kernel zeroed, some memory management libraries may reuse memory rather than releasing freed pages to the OS, and these might not be zeroed (depending on the library and API call used), containing old data from the heap and stack from its previous use within the process. This sometimes can be a security risk and source of bugs from reading uninitialized variables, but zeroing them is also considered a performance issue, especially if the code using the memory will immediately initialize it anyway.

Overprovisioning doesn't mean ram is given to both programs. It means it is given to neither of them until the last second.

So, let's say program A and B both have 1G of memory allocated to them. The system has 8G. Now both A and B (simultaneously or sequentially) ask for 5G. With overprovisioning, we can grant that request, but not actually give either one the memory -- just the address space.

The system still has 6G of memory in the free pool. A and B have "requested" a total of 6G each, but are each only using 1G and only have that 1G assigned to them. But they each have page table entries (with no assigned pages) for another 5G.

So the first time one of them writes to one of the newly requested pages, it gets a soft page fault, which causes a (pre-zeroed) page to be pulled from the free pool and assigned to that page table entry, and then the soft faulted write is allowed to continue with a real memory page assigned to it.

If the two programs allocate and use memory slowly, and perhaps never use everything they requested, this all works fine. If you have some swap, possibly some unused or infrequently pages in the program get written to virtual memory (swap) and returned to the free pool.

However, if both of them end up with a combined working set of used pages greater than the system physical memory, then either one or both of them will get killed with an OOM error (out of memory) (if you don't have enough swap to cover it), or the system will start thrashing as it tries to constantly swap pages between physical ram and virtual memory.

The alternative to overprovisioning is to immediately deny the memory request if there isn't enough virtual memory to cover it. Many programs are not written to handle this denial and will crash due to bugs, or just crash because they can't continue without the memory. So frequently, at worst, overprovisioning delays the program's death (or makes the system thrash), and at best, it avoids some possible nasty bugs and allows programs that request memory they might not actually use to continue running as if they got it anyway.

Adding containers to this does not change it at all. When you provision the container, you don't assign memory to the container (loading the container and running it does that live, as needed), it assigns memory limits to the container. When enough actual pages are assigned to the things in the container to exhaust those assigned limits, then the things in the container will get an OOM kill just like above.

If you've overprovisioned the containers and they try to reach those limits all at once, you'll get either thrashing or the OOM kill when the system's memory is exhausted, before the container's memory limit is reached.

It is also possible to tweak the container memory allocations so that one container can thrash while other containers perform normally.

Here is a partial list of cases where a process can see another process's memory:

  • Immediately after a fork, the parent and child share all memory pages. The linux kernel marks these as copy on write (with a reference counter) so these pages are shared read only, and the first write by either process clones the page so it is no longer shared.
  • A process can clone itself, sort of like fork, but with more control over which parts of the process are shared writable and which parts are COW cloned (as with fork). If almost nothing is cloned, it acts like a thread or light weight process.
  • A process can explicitly share a page to another process through multiple mechanisms, and this can have full bidirectional write for both processes. (The oldest form of this is SysV shared memory which is all but obsoleted by other more flexible methods.)
  • A process can debug (ptrace) another process and get full access to its memory and execution flow. However, since this is such a huge security risk, this is generally only allowed for root or for for a parent process to debug its child; The main use is for a debugger (like gdb) to start a process to debug. However, programs like strace and ltrace can do this without root access. And this can be relaxed via kernel option so gdb can attach to any running process a user owns.
  • A program can transfer a page of memory to another process via pipe or socket, but this acts more like a copy than a real sharing, especially if the receiving program doesn't try to read it with the same page/byte alignment.
  • The shared library system is entirely based on multiple processes sharing read only pages of libraries, and obviously, the executables of processes are also shared this way.

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK