Fix: sessiond: unbounded elf section data size allocation
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Tue, 8 Oct 2019 21:34:51 +0000 (17:34 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Tue, 8 Oct 2019 22:09:00 +0000 (18:09 -0400)
The size of ELF sections is read from a user-provided file descriptor
to an ELF file which could be malformed. In theory it would not
really be a problem as the run-as process is automatically restarted
after a crash (e.g. SIGBUS).

The alloctions are now bounded to the smallest of 512MB or the
file's size. The limit is kept high to accomodate very large
binaries and not impose an artificial limitation.

In time, this should be replaced by an mmap() of the section's
data rather than copying to a private set of pages.

1405558 Untrusted value as argument

The argument could be controlled by an attacker, who could invoke the
function with arbitrary values (for example, a very high or negative
buffer size).

In lttng_elf_get_sdt_probe_offsets: An unscrutinized value from an
untrusted source used as argument to a function (for example, a buffer
size) (CWE-20)

Reported-by: Coverity Scan
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
src/common/lttng-elf.c

index 5d4b93bbb80d13943571fede84f82057dea3a09d..91afcfdea3d19ae0435d655e4b49465064832d07 100644 (file)
@@ -43,6 +43,7 @@
 #define NOTE_STAPSDT_SECTION_NAME ".note.stapsdt"
 #define NOTE_STAPSDT_NAME "stapsdt"
 #define NOTE_STAPSDT_TYPE 3
+#define MAX_SECTION_DATA_SIZE   512 * 1024 * 1024
 
 #if BYTE_ORDER == LITTLE_ENDIAN
 #define NATIVE_ELF_ENDIANNESS ELFDATA2LSB
@@ -191,6 +192,7 @@ struct lttng_elf_sym {
 
 struct lttng_elf {
        int fd;
+       size_t file_size;
        uint8_t bitness;
        uint8_t endianness;
        /* Offset in bytes to start of section names string table. */
@@ -531,16 +533,28 @@ struct lttng_elf *lttng_elf_create(int fd)
        struct lttng_elf_shdr section_names_shdr;
        struct lttng_elf *elf = NULL;
        int ret;
+       struct stat stat_buf;
 
        if (fd < 0) {
                goto error;
        }
 
+       ret = fstat(fd, &stat_buf);
+       if (ret) {
+               PERROR("Failed to determine size of elf file");
+               goto error;
+       }
+       if (!S_ISREG(stat_buf.st_mode)) {
+               ERR("Refusing to initialize lttng_elf from non-regular file");
+               goto error;
+       }
+
        elf = zmalloc(sizeof(struct lttng_elf));
        if (!elf) {
                PERROR("Error allocating struct lttng_elf");
                goto error;
        }
+       elf->file_size = (size_t) stat_buf.st_size;
 
        elf->fd = dup(fd);
        if (elf->fd < 0) {
@@ -632,6 +646,8 @@ char *lttng_elf_get_section_data(struct lttng_elf *elf,
        int ret;
        off_t section_offset;
        char *data;
+       const size_t max_alloc_size = min_t(size_t, MAX_SECTION_DATA_SIZE,
+                       elf->file_size);
 
        if (!elf || !shdr) {
                goto error;
@@ -643,6 +659,11 @@ char *lttng_elf_get_section_data(struct lttng_elf *elf,
                goto error;
        }
 
+       if (shdr->sh_size > max_alloc_size) {
+               ERR("ELF section size exceeds maximal allowed size of %zu bytes",
+                               max_alloc_size);
+               goto error;
+       }
        data = zmalloc(shdr->sh_size);
        if (!data) {
                PERROR("Error allocating buffer for ELF section data");
This page took 0.026232 seconds and 4 git commands to generate.