Out-of-bound access of vector in C++

Today I debugged a crash bug of C++ program, and the core dump is like this:

Program terminated with signal SIGABRT, Aborted.
#0  0x00007f57ba2ed860 in raise () from /usr/lib/libc.so.6
(gdb) bt
#0  0x00007f57ba2ed860 in raise () from /usr/lib/libc.so.6
#1  0x00007f57ba2eeec9 in abort () from /usr/lib/libc.so.6
#2  0x00007f57ba330437 in __libc_message () from /usr/lib/libc.so.6
#3  0x00007f57ba336d34 in malloc_printerr () from /usr/lib/libc.so.6
#4  0x00005593dc2f7b6c in __gnu_cxx::new_allocator<int>::deallocate (this=0x7ffc65848820, __p=0x5593dce6fac0)
    at /usr/include/c++/7.2.1/ext/new_allocator.h:125
#5  0x00005593dc2f7a36 in std::allocator_traits<std::allocator<int> >::deallocate (__a=..., __p=0x5593dce6fac0, __n=12)
    at /usr/include/c++/7.2.1/bits/alloc_traits.h:462
#6  0x00005593dc2f789a in std::_Vector_base<int, std::allocator<int> >::_M_deallocate (this=0x7ffc65848820,
    __p=0x5593dce6fac0, __n=12) at /usr/include/c++/7.2.1/bits/stl_vector.h:180
#7  0x00005593dc2f7543 in std::_Vector_base<int, std::allocator<int> >::~_Vector_base (this=0x7ffc65848820,
    __in_chrg=<optimized out>) at /usr/include/c++/7.2.1/bits/stl_vector.h:162
#8  0x00005593dc2f71cf in std::vector<int, std::allocator<int> >::~vector (this=0x7ffc65848820,
    __in_chrg=<optimized out>) at /usr/include/c++/7.2.1/bits/stl_vector.h:435
......

From the stack trace, we can see the abort() occurred in vector‘s destructor function. After some debugging, I find the root cause is the general “out-of-bound” error, which accessed the memory beyond the vector space. But the caveat is that “out-of-bound” error may be silent and give you no hurt apparently. E.g., I write a simple test program:

#include <vector>

void fun() {
    std::vector<int> v(1);

    auto it = v.begin();
    for (int i = 0; i < 100; i++) {
        *it++ = i;
    }
}
int main() {
    fun();
    return 0;
}

Build and run it:

# g++ -g test.cpp
# ./a.out
# ./a.out

The application goes well. So we really should pay enough attention to vector access.

Install make before using cmake

Today I tried to build a project, but running “cmake” gave me a strange output:

# cmake ..
CMake Error: CMake was unable to find a build program corresponding to "Unix Makefiles".  CMAKE_MAKE_PROGRAM is not set.  You probably need to select a different build tool.
CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage
CMake Error: CMAKE_CXX_COMPILER not set, after EnableLanguage

After referring this discussion: CMAKE_MAKE_PROGRAM not found, I suddenly realized that this a new setup server, so make program may not be installed. As expected:

# make
-bash: make: command not found

After installing make, the cmake flow works normally.

My tour report of Black Hat Europe 2017

Although I have been working for 10 years, taking part in Black Hat Europe 2017 is actually my first business trip ever.

The first 2 days (December 4th ~ 5th) were for trainings, and I attended Advanced Infrastructure Hacking – 2017 Edition. This course is comprehensive and covers a lot of hacking techniques. The primary harvest which I get includes following parts:

a) Many network related knowledge. E.g., I got a recap of basics of IPv4/IPv6, and learned the usage of command line tools: nmap,SNMP, arp-scan, etc. Since I have great interest in socket programming, and maybe I should spend time in reading the source code of these tools, and share it if possible, like what I have done with netcat: Learn socket programming tips from netcat.

b) Linux hacks. Since I mostly use Linux in my daily life, this part is really impressive and teach me some caveats which I can’t pay enough attention to: uid and euid, the sticky bit, and so on. BTW, Because I worked for a telecommunication software company before,VoIP hacks is another area which I am familiar with.

c) Some awesome websites, like https://www.rebootuser.com/ and https://www.shodan.io/.

For other parts of the training, as I don’t have much hands-on experience on them, honestly, I didn’t inhale too much knowledge.

The following 2 days (December 6th ~ 7th) is for social events: briefings, arsenal and business networking. Because of the budget, I didn’t take part in briefings which the speakers gave talks about one specific security area. My primary task is to seek potential partners who have interest in encrypting data field. Fortunately, even most attended companies concentrate on firewall, safer data access, data monitor, etc; there are still few corps have tastes on this “niche” technology. So after my back to company, we will communicate further. BTW, another Fintech event was held in the same building simultaneously, so this is truly “kill two birds with one stone”.

Besides the content aforementioned, I also knew some new friends. For example, some guy took part in both training and briefings at his own expense; that gave me a real deep impression.

In summary, I have a rich gain during this trip, and hope to take part in more events like this in the future. London, see you again~

The anatomy of tee program on OpenBSD

The tee command is used to read content from standard input and displays it not only in standard output but also saves to other files simultaneously. The source code of tee in OpenBSD is very simple, and I want to give it an analysis:

(1) tee leverages Singlely-linked List defined in sys/queue.h to manage outputted files (including standard output):

struct list {
    SLIST_ENTRY(list) next;
    int fd;
    char *name;
};
SLIST_HEAD(, list) head;

......

static void
add(int fd, char *name)
{
    struct list *p;
    ......
    SLIST_INSERT_HEAD(&head, p, next);
}

int
main(int argc, char *argv[])
{
    struct list *p;
    ......
    SLIST_INIT(&head);
    ......
    SLIST_FOREACH(p, &head, next) {
        ......
    }
}

To understand it easily, I extract the macros from sys/queue.h and created a file which utilizes the marcos:

#define SLIST_HEAD(name, type)                      \
struct name {                               \
    struct type *slh_first; /* first element */         \
}

#define SLIST_ENTRY(type)                       \
struct {                                \
    struct type *sle_next;  /* next element */          \
}

#define SLIST_FIRST(head)   ((head)->slh_first)
#define SLIST_END(head)     NULL
#define SLIST_EMPTY(head)   (SLIST_FIRST(head) == SLIST_END(head))
#define SLIST_NEXT(elm, field)  ((elm)->field.sle_next)

#define SLIST_FOREACH(var, head, field)                 \
    for((var) = SLIST_FIRST(head);                  \
        (var) != SLIST_END(head);                   \
        (var) = SLIST_NEXT(var, field))

#define SLIST_INIT(head) {                      \
    SLIST_FIRST(head) = SLIST_END(head);                \
}

#define SLIST_INSERT_HEAD(head, elm, field) do {            \
    (elm)->field.sle_next = (head)->slh_first;          \
    (head)->slh_first = (elm);                  \
} while (0)

struct list {
    SLIST_ENTRY(list) next;
    int fd;
    char *name;
};
SLIST_HEAD(, list) head;

int
main(int argc, char *argv[])
{
    struct list *p;
    SLIST_INIT(&head);

    SLIST_INSERT_HEAD(&head, p, next);
    SLIST_FOREACH(p, &head, next) {

    }
}

Then employed gcc‘s pre-processing function:

# gcc -E slist.c
# 1 "slist.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "slist.c"
# 30 "slist.c"
struct list {
 struct { struct list *sle_next; } next;
 int fd;
 char *name;
};
struct { struct list *slh_first; } head;

int
main(int argc, char *argv[])
{
 struct list *p;
 { ((&head)->slh_first) = NULL; };

 do { (p)->next.sle_next = (&head)->slh_first; (&head)->slh_first = (p); } while (0);
 for((p) = ((&head)->slh_first); (p) != NULL; (p) = ((p)->next.sle_next)) {

 }
}

It becomes clear now! The head node in list contains only 1 member: slh_first, which points to the first valid node. For the elements in the list, it is embedded with next struct which uses sle_next to refer to next buddy.

(2) By default, tee will overwrite the output files. If you want to append it, use -a option, and the code is as following:

while (*argv) {
    if ((fd = open(*argv, O_WRONLY | O_CREAT |
        (append ? O_APPEND : O_TRUNC), DEFFILEMODE)) == -1) {
        ......
    } 
    ......
}

(3) The next part is the skeleton of saving content to files:

while ((rval = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
    SLIST_FOREACH(p, &head, next) {
        n = rval;
        bp = buf;
        do {
            if ((wval = write(p->fd, bp, n)) == -1) {
                ......
            }
            bp += wval;
        } while (n -= wval);
    }
}

We need to iterates every opened file descriptor and write contents into it.

(4) Normally, theinterrupt signal will cause tee exit:

# tee
fdkfkdfjk
fdkfkdfjk
^C
#

To disable this feature, use -i option:

# tee -i
fdhfhd
fdhfhd
^C^C

The corresponding code is like this:

......
case 'i':
    (void)signal(SIGINT, SIG_IGN);
    break;