A common pattern is to initialize a local variable by calling another function (an +"initialization" function) with the address of the local variable as a pointer argument. That +function is then responsible for writing to the memory location referenced by the pointer.
+ +In some cases, the called function may not always write to the memory pointed to by the +pointer argument. In such cases, the function will typically return a "status" code, informing the +caller as to whether the initialization succeeded or not. If the caller does not check the status +code before reading the local variable, it may read uninitialized memory, which can result in +unexpected behavior.
+ +When using an initialization function that does not guarantee to initialize the memory pointed to +by the passed pointer, and returns a status code to indicate whether such initialization occurred, +the status code should be checked before reading from the local variable.
+ +In this hypothetical example we have code for managing a series of devices. The code
+includes a DeviceConfig struct that can represent properties about each device.
+The initDeviceConfig function can be called to initialize one of these structures, by
+providing a "device number", which can be used to look up the appropriate properties in some data
+store. If an invalid device number is provided, the function returns a status code of
+-1, and does not initialize the provided pointer.
In the first code sample below, the notify function calls the
+initDeviceConfig function with a pointer to the local variable config,
+which is then subsequently accessed to fetch properties of the device. However, the code does not
+check the return value from the function call to initDeviceConfig. If the
+device number passed to the notify function was invalid, the
+initDeviceConfig function will leave the config variable uninitialized,
+which will result in the notify function accessing uninitialized memory.
To fix this, the code needs to check that the return value of the call to
+initDeviceConfig is zero. If that is true, then the calling code can safely assume
+that the local variable has been initialized.
In low-level Windows kernel code, dereferencing a pointer originating from user mode is dangerous if the pointer has not been validated (probed).
+ An unvalidated pointer may point to privileged kernel memory or invalid addresses.
+ Using proper user-mode accessors such as ReadULongFromUser or probing via APIs such as ProbeForRead ensures that invalid or malicious user-supplied addresses do not compromise the kernel.
Before dereferencing pointers from user memory in kernel-mode code, always validate them.
+Reading user memory outside a try/catch block is discouraged, as unexpected exceptions can occur if untrusted code changes memory protections.
+Move all reads to user memory to inside a try-catch block.
+The following examples show scenarios where uncaught exceptions can occur.
+To correct the problem, transfer user mode memory use to inside a try-catch block.
+User mode memory should always be transferred to kernel memory before being read repeatedly, to avoid its content changing based on user actions ("double fetch" vulnerability).
+Transfer user mode memory to kernel memory.
+The following examples show scenarios where double fetch may occur.
+To correct the problem, be sure to read from user memory only once.
+A null pointer dereference can cause program crash or exit.
+Make sure to initialize all pointer fields before usage.
+The following examples show scenarios where a pointer is dereferenced without a null check.
+To correct the problem, check the pointer before dereferencing.
+