CWE ID: 591
Name: Sensitive Data Storage in Improperly Locked Memory
Das Produkt speichert sensible Daten im nicht gesicherten Speicher oder in Speicher, der fehlerhaft gesichert wurde. Dies kann dazu führen, dass der virtuelle Speichermanager diese Daten auf die Auslagerungsdatei auf der Festplatte schreibt. Dies kann die Daten für externe Akteure zugänglicher machen.
Unter Windows-Systemen kann die VirtualLock-Funktion eine Speicherseite sperren, um sicherzustellen, dass sie im Speicher verbleibt und nicht auf die Festplatte ausgelagert wird. Bei älteren Windows-Versionen wie 95, 98 oder Me ist die VirtualLock()-Funktion jedoch lediglich ein Stub und bietet keinen Schutz. Unter POSIX-Systemen stellt der mlock()-Aufruf sicher, dass eine Seite im Speicher verbleibt, garantiert aber nicht, dass die Seite nicht in der Swap-Datei erscheint. Daher ist er ungeeignet als Schutzmechanismus für sensible Daten. Einige Plattformen, insbesondere Linux, geben zwar die Garantie, dass die Seite nicht ausgelagert wird, dies ist jedoch nicht standardisiert und nicht portabel. Auch mlock()-Aufrufe erfordern Supervisor-Privilegien. Die Rückgabewerte beider Aufrufe müssen überprüft werden, um sicherzustellen, dass die Sperroperation tatsächlich erfolgreich war.
Effektivität: Unknown
Beschreibung: Okay, let’s break down how to identify data needing protection from swapping and select appropriate platform-appropriate mechanisms. Here’s a structured approach, combining identification and selection:
1. Identifying Data Requiring Protection from Swapping
The first step is to determine what data absolutely cannot be swapped to disk. This isn’t a blanket “everything” situation; it’s about identifying specific data categories. Consider these criteria:
Examples of Data to Protect:
2. Selecting Platform-Appropriate Protection Mechanisms
Now, let’s look at how to protect this data, considering different operating systems. The goal is to prevent the OS from swapping the memory pages containing this data.
A. Windows
VirtualLock()
(with caveats): As the original text mentions, VirtualLock()
should prevent swapping. However, its reliability is questionable on older Windows versions. On modern Windows, it’s generally the preferred method.
VirtualAlloc()
with MEM_LOCK
and then call VirtualLock()
.B. POSIX (Linux, macOS, Unix-like systems)
mlock()
: The standard POSIX mechanism. It attempts to lock a region of memory into RAM.
mlock()
after allocating memory with malloc()
or mmap()
.MCL_CURRENT
flag is often used to lock the currently resident pages. MCL_FUTURE
attempts to lock pages that will be brought into memory later.madvise()
with MADV_DONTDUMP
: This suggests to the OS that the memory should not be included in core dumps. While not a guarantee against swapping, it’s a helpful complementary measure.VirtualLock()
, mlock()
is subject to system memory constraints. The OS can still swap pages if absolutely necessary, although it will try to avoid it.C. General Best Practices (Across Platforms)
VirtualLock()
, mlock()
, and related functions. If the lock operation fails, handle the error gracefully (e.g., log the error, attempt to re-allocate memory, or take alternative action).Example (Illustrative - Linux/C)
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <errno.h>
int main() {
size_t data_size = 1024 * 1024; // 1MB
void *data = malloc(data_size);
if (data == NULL) {
perror("malloc failed");
return 1;
}
// Attempt to lock the memory
if (mlock(data, data_size, MCL_CURRENT | MCL_FUTURE) == -1) {
perror("mlock failed");
free(data);
return 1;
}
printf("Memory locked successfully.\n");
// ... Use the data ...
munlock(data); // Unlock the memory when done
free(data);
return 0;
}
Important Disclaimer: Memory protection is a complex topic. The information provided here is for general guidance only. Always consult the official documentation for your specific operating system and hardware platform. Thorough testing and security audits are essential to ensure the effectiveness of your memory protection strategies.
Effektivität: Unknown
Beschreibung: You are absolutely correct to emphasize the importance of checking return values. It’s a critical, often overlooked, aspect of implementing memory protection. Let’s expand on that and provide more detailed examples of how to handle return values correctly.
Why Checking Return Values is Essential
VirtualLock()
, mlock()
) are not guaranteed to succeed. System resources (physical memory, available address space) are finite. The OS might refuse to lock memory if it’s under severe pressure.Detailed Examples of Return Value Checking
Let’s revisit the previous examples and incorporate robust return value checking.
1. Windows (using VirtualLock
)
#include <windows.h>
#include <iostream>
int main() {
size_t data_size = 1024 * 1024; // 1MB
void* data = VirtualAlloc(NULL, data_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (data == NULL) {
std::cerr << "VirtualAlloc failed: " << GetLastError() << std::endl;
return 1;
}
// Attempt to lock the memory
DWORD result = VirtualLock(data, data_size);
if (result == 0) {
std::cerr << "VirtualLock failed: " << GetLastError() << std::endl;
VirtualFree(data, 0, MEM_RELEASE); // Clean up allocated memory
return 1;
}
std::cout << "Memory locked successfully." << std::endl;
// ... Use the data ...
VirtualFree(data, 0, MEM_RELEASE); // Release the memory
return 0;
}
GetLastError()
: Windows functions often set the last error code if they fail. GetLastError()
retrieves this code, providing more information about the cause of the failure.VirtualFree()
: If VirtualLock()
fails, it’s crucial to release the memory allocated by VirtualAlloc()
to avoid memory leaks.2. Linux (using mlock
)
#include <iostream>
#include <sys/mman.h>
#include <cerrno>
int main() {
size_t data_size = 1024 * 1024; // 1MB
void* data = malloc(data_size);
if (data == NULL) {
std::cerr << "malloc failed: " << strerror(errno) << std::endl;
return 1;
}
// Attempt to lock the memory
if (mlock(data, data_size, MCL_CURRENT | MCL_FUTURE) == -1) {
std::cerr << "mlock failed: " << strerror(errno) << std::endl;
free(data);
return 1;
}
std::cout << "Memory locked successfully." << std::endl;
// ... Use the data ...
munlock(data); // Unlock the memory when done
free(data);
return 0;
}
strerror(errno)
: Linux functions often set the errno
global variable to indicate an error. strerror(errno)
converts this error code into a human-readable error message.munlock()
: Corresponding to mlock()
, munlock()
releases the locked memory. It’s essential to unlock memory when it’s no longer needed.General Best Practices for Return Value Checking
assert(result != 0);
)By consistently incorporating these practices, you can significantly improve the reliability and security of your memory protection strategies. Remember that error handling is not an optional extra; it’s a fundamental requirement for robust software development.