[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#593558: marked as done (libffi-dev: ffi_call segfault: read beyond the heap, allocated for return value)



Your message dated Mon, 14 Dec 2015 19:14:34 +0100
with message-id <566F070A.8020903@debian.org>
and subject line closing old issue
has caused the Debian Bug report #593558,
regarding libffi-dev: ffi_call segfault: read beyond the heap, allocated for return value
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
593558: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=593558
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: libffi-dev
Version: 3.0.9-2
Severity: important

The test C-code is attached:
gcc-4.4 -lffi -lunistring -o test test.c

It can be compiled without libunistring as well (see notes, please):
1. comment out rows #7 and #8
2. uncomment #9
3. gcc-4.4 -lffi -o test test.c

What the code does:
1. creates a new ffi_type to emulate size_t;
2. allocates array of types of function arguments: (char *) and (size_t);
3. prepare CIF to call the size_t function with two arguments;
4. allocates array of pointers to two arguments: char *b and size_t a;
5. runs ffi_call and segfaults;

The function can be called directly without ffi_call: comment #68 and uncomment the next statement. In this case the code will not cause segfault.

I use valgrind to see internals:
valgrind --track-origins=yes -q ./test

In the case with ffi_call, valgrind shows:
--------------------vvvvvvvvvvvvvvvvvvvvvv
just before...
==4153== Conditional jump or move depends on uninitialised value(s)
==4153==    at 0x4084827: u8_mbtoucr (in /usr/lib/libunistring.so.0.1.2)
==4153==    by 0x40842E8: u8_mbsnlen (in /usr/lib/libunistring.so.0.1.2)
==4153==    by 0x404154E: ffi_call_SYSV (in /usr/lib/libffi.so.5.0.10)
==4153==    by 0x404138D: ffi_call (in /usr/lib/libffi.so.5.0.10)
==4153==    by 0x804890C: main (in /home/ygrex/devel/dlffi/test)
==4153==  Uninitialised value was created by a heap allocation
==4153==    at 0x4023F50: malloc (vg_replace_malloc.c:236)
==4153==    by 0x8048852: main (in /home/ygrex/devel/dlffi/test)
==4153== 
==4153== Invalid read of size 1
==4153==    at 0x4084822: u8_mbtoucr (in /usr/lib/libunistring.so.0.1.2)
==4153==    by 0x40842E8: u8_mbsnlen (in /usr/lib/libunistring.so.0.1.2)
==4153==    by 0x404154E: ffi_call_SYSV (in /usr/lib/libffi.so.5.0.10)
==4153==    by 0x404138D: ffi_call (in /usr/lib/libffi.so.5.0.10)
==4153==    by 0x804890C: main (in /home/ygrex/devel/dlffi/test)
==4153==  Address 0x429a0ec is 0 bytes after a block of size 4 alloc'd
==4153==    at 0x4023F50: malloc (vg_replace_malloc.c:236)
==4153==    by 0x8048852: main (in /home/ygrex/devel/dlffi/test)
==4153== 
==4153== 
==4153== Process terminating with default action of signal 11 (SIGSEGV)
==4153==  Access not within mapped region at address 0x469A000
==4153==    at 0x4084822: u8_mbtoucr (in /usr/lib/libunistring.so.0.1.2)
==4153==    by 0x40842E8: u8_mbsnlen (in /usr/lib/libunistring.so.0.1.2)
==4153==    by 0x404154E: ffi_call_SYSV (in /usr/lib/libffi.so.5.0.10)
==4153==    by 0x404138D: ffi_call (in /usr/lib/libffi.so.5.0.10)
==4153==    by 0x804890C: main (in /home/ygrex/devel/dlffi/test)
==4153==  If you believe this happened as a result of a stack
==4153==  overflow in your program's main thread (unlikely but
==4153==  possible), you can try to increase the size of the
==4153==  main thread stack using the --main-stacksize= flag.
==4153==  The main thread stack size used in this run was 8388608.
Segmentation fault
--------------------^^^^^^^^^^^^^^^^^^^^^^

the message "0 bytes after a block of size 4 alloc'd" is about #52:
	void *ret = malloc(T_size_t->size);
this pointer is used as a return value allocation then.

Some notes on libunistring vs default strings: when I use strnlen instead of u8_mbsnlen and modify the 52-nd line:
	void *ret = calloc(T_size_t->size, 1);
valgrind is happy and no segmentation fault occurs (but it still here with malloc);

-- System Information:
Debian Release: squeeze/sid
  APT prefers unstable
  APT policy: (500, 'unstable'), (500, 'testing'), (500, 'stable'), (1, 'experimental')
Architecture: i386 (i686)

Kernel: Linux 2.6.33.1-ygrex (SMP w/2 CPU cores)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/bash

Versions of packages libffi-dev depends on:
ii  dpkg                      1.15.8.4       Debian package management system
ii  install-info              4.13a.dfsg.1-5 Manage installed documentation in 
ii  libffi5                   3.0.9-2        Foreign Function Interface library

libffi-dev recommends no packages.

libffi-dev suggests no packages.

-- no debconf information
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <ffi.h>

#include <unistr.h>
size_t (* sample)(const uint8_t *, size_t) = u8_mbsnlen;
//size_t (* sample)(const char *, size_t) = strnlen;

ffi_type *type_init(size_t size)
{
	ffi_type *new = malloc(sizeof(ffi_type));
	if (!new) return NULL;
	new->size = new->alignment = 0;
	new->type = FFI_TYPE_STRUCT;
	new->elements = calloc(size + 1, sizeof(ffi_type *));
	if (!new->elements) {
		free(new);
		return NULL;
	}
	size_t i;
	for (i = 0; i < size; i++) new->elements[i] = &ffi_type_uchar;
	new->elements[size] = NULL;
	return new;
}

int main()
{
	ffi_type *T_size_t = type_init(sizeof(size_t));
	if (! T_size_t) return -1;

	ffi_type **types = calloc( 2, sizeof(ffi_type *));
	if (! types) {
		free(T_size_t->elements);
		free(T_size_t);
		return -2;
	}
	types[0] = &ffi_type_pointer;
	types[1] = T_size_t;

	ffi_cif cif;

	ffi_status stat = ffi_prep_cif(
		&cif,
		FFI_DEFAULT_ABI,
		2,
		T_size_t,
		types
	);

	void *ret = malloc(T_size_t->size);
	void **argv = calloc( 2, sizeof(void *));
	if ((stat != FFI_OK) || !ret || !argv) {
		free(types);
		free(T_size_t->elements);
		free(T_size_t);
		return -3;
	}

	size_t a = 10;
	const char *b = "текст";

	argv[1] = &a;
	argv[0] = &b;

	puts("just before...");
	ffi_call(&cif, (void *)sample, ret, argv);
	/*
	*(size_t *)ret = (size_t)sample(
		*(const uint8_t **)(argv[0]),
		*(size_t *)(argv[1])
	);
	*/
	puts("right after!");

	printf("ret value: %zu\n", *(size_t *)ret);

	free(argv);
	free(ret);
	free(types);
	free(T_size_t->elements);
	free(T_size_t);

	return 0;
}


--- End Message ---
--- Begin Message ---
closing old issue; please recheck with 3.2.1 and reopen if appropriate.

--- End Message ---

Reply to: