linux
Failing to preserve invariant causes buffer overflow
Function add_uevent_var() shall guarantee that env->buflen > 0 when it succeeds (i.e. returns 0). However, if !HOTPLUG this function behaves incorrectly, succeeding but not writing anything to env->buf so env->buflen == 0. A subsequent call to input_add_uevent_modalias_var() after the env was initialized executes env->buf[env->buflen - 1] = 'x'. The array index is -1, since env->buflen == 0, and this statement overwrites env->envp_idx which is located right before env->buf in the stack.
Bug fixed by commit 60e233a5660
| Type | BufferOverflow |
| Config | "!HOTPLUG" (1st degree) |
| Fix-in | code |
| Location | drivers/ |
#include <errno.h>
#include <stdio.h>
#define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */
static char buf[UEVENT_BUFFER_SIZE];
static int buflen = 0;
#if defined(CONFIG_HOTPLUG)
int add_uevent_var()
{
int len = sprintf(&buf[buflen], "MODALIAS=");
buflen += len + 1;
return 0;
}
#else
int add_uevent_var()
{ return 0; } // (2)
#endif
int input_add_uevent_modalias_var()
{
if (add_uevent_var())
return -ENOMEM;
buf[buflen - 1] = 'x'; // ERROR: buflen == 0, so buf[-1] is written.
return 0;
}
int main(int argc, char** argv)
{
input_add_uevent_modalias_var(); // (1)
return 0;
}
diff --git a/simple/60e233a.c b/simple/60e233a.c
--- a/simple/60e233a.c
+++ b/simple/60e233a.c
@@ -16,7 +16,7 @@
}
#else
int add_uevent_var()
-{ return 0; }
+{ return -ENOMEM; }
#endif
int input_add_uevent_modalias_var()
#include <errno.h>
#include <stdio.h>
#define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */
static char buf[UEVENT_BUFFER_SIZE];
static int buflen = 0;
int main(int argc, char** argv)
{
// input_add_uevent_modalias_var();
int r;
#if defined(CONFIG_HOTPLUG)
int len = sprintf(&buf[buflen], "MODALIAS=");
buflen += len + 1;
r = 0;
#else
r = 0;
#endif
if (r)
return -ENOMEM;
buf[buflen - 1] = 'x'; // ERROR: buflen == 0, so buf[-1] is written.
return 0;
}
. call drivers/base/core.c:310:show_uevent() . 336: env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); . 341: retval = kset->uevent_ops->uevent(kset, &dev->kobj, env); .. dyn-call drivers/base/core.c:243:dev_uevent() .. 246: struct device *dev = kobj_to_dev(kobj); .. 294: retval = dev->type->uevent(dev, env); ... dyn-call drivers/input/input.c:1485:input_dev_uevent() ... 1519: INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev); .... call drivers/input/input.c:1446:input_add_uevent_modalias_var() .... 1451: if (add_uevent_var(env, "MODALIAS=")) ...... call include/linux/kobject.h:225:add_uevent_var() ...... 227: return 0; .... ERROR 1454: len = input_print_modalias(&env->buf[env->buflen - 1],