CVE-2013-0178 (C, published 2019-11-01T19:15Z)
Description: value: Insecure temporary file vulnerability in Redis before 2.6 related to /tmp/redis-%p.vm.
Severity: LOW (CVSS v3 base score: 5.5)
Weakness: CWE-20 \u2014 Improper Input Validation
The product receives input or data, but it does
        not validate or incorrectly validates that the input has the
        properties that are required to process the data safely and
        correctly.
Repository: https://github.com/antirez/redis
Files changed:
src/diskstore.c
src/networking.c
src/redis.c
src/redis.h
Commit message: initial changes needed to turn the current VM code into a cache system. Tons of work to do still.


Vulnerable code:
 * The actaul implementation of this disk store is highly related to the
 * filesystem implementation. This implementation may be replaced by
    char *path = server.diskstore_path;
    redisAssert(!server.vm_enabled || obj->storage == REDIS_VM_MEMORY);
        redisAssert(server.vm_enabled);
        server.vm_blocked_clients--;
    /* Swap a few keys on disk if we are over the memory limit and VM
     * is enbled. Try to free objects from the free list first. */
    if (vmCanSwapOut()) {
        while (server.vm_enabled && zmalloc_used_memory() >
                server.vm_max_memory)
        {
            int retval = (server.vm_max_threads == 0) ?
                        vmSwapOneObjectBlocking() :
                        vmSwapOneObjectThreaded();
            if (retval == REDIS_ERR && !(loops % 300) &&
                zmalloc_used_memory() >
                (server.vm_max_memory+server.vm_max_memory/10))
            {
                redisLog(REDIS_WARNING,"WARNING: vm-max-memory limit exceeded by more than 10%% but unable to swap more objects out!");
            }
            /* Note that when using threade I/O we free just one object,
             * because anyway when the I/O thread in charge to swap this
             * object out will finish, the handler of completed jobs
             * will try to swap more objects if we are still out of memory. */
            if (retval == REDIS_ERR || server.vm_max_threads > 0) break;
        }
    /* Awake clients that got all the swapped keys they requested */
    if (server.vm_enabled && listLength(server.io_ready_clients)) {
            server.vm_blocked_clients--;
    server.vm_enabled = 0;
    server.vm_swap_file = zstrdup("/tmp/redis-%p.vm");
    server.vm_page_size = 256;          /* 256 bytes per page */
    server.vm_pages = 1024*1024*100;    /* 104 millions of pages */
    server.vm_max_memory = 1024LL*1024*1024*1; /* 1 GB of RAM */
    server.vm_max_threads = 4;
    server.vm_blocked_clients = 0;
        if (server.vm_enabled)
    if (server.vm_enabled) vmInit();
        if (server.vm_enabled && server.vm_max_threads > 0 &&
            blockClientOnSwappedKeys(c,cmd)) return REDIS_ERR;
        if (server.vm_enabled) unlink(server.vm_swap_file);
        "vm_enabled:%d\r\n"
        server.vm_enabled != 0,
    if (server.vm_enabled) {
            "vm_conf_max_memory:%llu\r\n"
            "vm_conf_page_size:%llu\r\n"
            "vm_conf_pages:%llu\r\n"
            "vm_stats_used_pages:%llu\r\n"
            "vm_stats_swapped_objects:%llu\r\n"
            "vm_stats_swappin_count:%llu\r\n"
            "vm_stats_swappout_count:%llu\r\n"
            "vm_stats_io_newjobs_len:%lu\r\n"
            "vm_stats_io_processing_len:%lu\r\n"
            "vm_stats_io_processed_len:%lu\r\n"
            "vm_stats_io_active_threads:%lu\r\n"
            "vm_stats_blocked_clients:%lu\r\n"
            ,(unsigned long long) server.vm_max_memory,
            (unsigned long long) server.vm_page_size,
            (unsigned long long) server.vm_pages,
            (unsigned long long) server.vm_stats_used_pages,
            (unsigned long long) server.vm_stats_swapped_objects,
            (unsigned long long) server.vm_stats_swapins,
            (unsigned long long) server.vm_stats_swapouts,
            (unsigned long) listLength(server.io_newjobs),
            (unsigned long) listLength(server.io_processing),
            (unsigned long) listLength(server.io_processed),
            (unsigned long) server.io_active_threads,
            (unsigned long) server.vm_blocked_clients
    unsigned int vm_blocked_clients;
    int vm_enabled;
    char *vm_swap_file;
    off_t vm_page_size;
    off_t vm_pages;
    unsigned long long vm_max_memory;

Fixed code:
 * Note that since Redis supports multiple databases, the actual key name
 * is:
 *
 *  /0b/ee/<dbid>_0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
 *
 *  so for instance if the key is inside DB 0:
 *
 *  /0b/ee/0_0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
 *
 * The actaul implementation of this disk store is highly dependant to the
 * filesystem implementation itself. This implementation may be replaced by
    char *path = server.ds_path;
    redisAssert(!server.ds_enabled || obj->storage == REDIS_VM_MEMORY);
        redisAssert(server.ds_enabled);
        server.cache_blocked_clients--;
    /* Remove a few cached objects from memory if we are over the
     * configured memory limit */
    while (server.ds_enabled && zmalloc_used_memory() >
            server.cache_max_memory)
    {
        cacheFreeOneEntry();
    /* Awake clients that got all the on disk keys they requested */
    if (server.ds_enabled && listLength(server.io_ready_clients)) {
            server.cache_blocked_clients--;
    server.ds_enabled = 0;
    server.ds_path = zstrdup("/tmp/redis.ds");
    server.cache_max_memory = 64LL*1024*1024; /* 64 MB of RAM */
    server.cache_blocked_clients = 0;
        if (server.ds_enabled)
    if (server.ds_enabled) dsInit();
        if (server.ds_enabled && blockClientOnSwappedKeys(c,cmd))
            return REDIS_ERR;
        "ds_enabled:%d\r\n"
        server.ds_enabled != 0,
    if (server.ds_enabled) {
            "cache_max_memory:%llu\r\n"
            "cache_blocked_clients:%lu\r\n"
            ,(unsigned long long) server.cache_max_memory,
            (unsigned long) server.cache_blocked_clients
    unsigned int cache_blocked_clients;
    int ds_enabled; /* backend disk in redis.conf */
    char *ds_path;  /* location of the disk store on disk */
    unsigned long long cache_max_memory;