Summary
When my code calls BIO_do_connect it jumps back to the start of the function that called it and then segfaults.
What Tried
Debugger, Valgrind, changing code
// compiled with:
// gcc -g -O0 -Wall -Wextra -o sslex sslex_main.c -fstack-protector -lssl -lcrypto
#include <stdio.h>
#include <string.h>
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
// BIO handles communication including files and sockets.
static BIO* g_bio = NULL;
// holds SSL connection information
static SSL_CTX* g_sslContext = NULL;
char* g_trustedStore = "certs/trusted.pem";
void initialize() {
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
}
int connect(char* hostnamePort) {
SSL* sslp = NULL;
BIO* out = NULL;
printf("Connect called\n");
printf("Connecting... to %s\n", hostnamePort);
g_sslContext = SSL_CTX_new(TLS_client_method());
// load trusted certificate store
if (! SSL_CTX_load_verify_locations(g_sslContext, g_trustedStore, NULL)) {
fprintf(stderr, "Failure loading certificats from trusted store %s!\n", g_trustedStore);
fprintf(stderr, "Error: %s\n", ERR_reason_error_string(ERR_get_error()));
return -1;
}
g_bio = BIO_new_ssl_connect(g_sslContext);
if (g_bio == NULL) {
fprintf(stderr, "Error cannot get BSD Input/Output\n");
return -1;
}
// retrieve ssl pointer of the BIO
BIO_get_ssl(g_bio, &sslp);
if (sslp == NULL) {
fprintf(stderr, "Could not locate SSL pointer\n");
fprintf(stderr, "Error: %s\n", ERR_reason_error_string(ERR_get_error()));
return -1;
}
// if server wants a new handshake, handle that in the background
SSL_set_mode(sslp, SSL_MODE_AUTO_RETRY);
// attempt to connect
BIO_set_conn_hostname(g_bio, hostnamePort);
out = BIO_new_fp(stdout, BIO_NOCLOSE);
printf("Connecting to: %s\n", BIO_get_conn_hostname(g_bio));
// THIS LINE CAUSES STACK SMASH
if (BIO_do_connect(g_bio) <= 0) { // BUGGY LINE
fprintf(stderr, "Error cannot connect to %s\n", hostnamePort);
fprintf(stderr, "Error: %s\n", ERR_reason_error_string(ERR_get_error()));
BIO_free_all(g_bio);
SSL_CTX_free(g_sslContext);
return -1;
}
return -1;
}
void close_connection() {
BIO_free_all(g_bio);
SSL_CTX_free(g_sslContext);
}
int main(int argc, char* argv[]) {
char* hostnamePort = argv[1];
initialize();
if (connect(hostnamePort) != 0)
return 0;
printf("Done connecting. doing operation\n");
close_connection();
return 0;
}
Expected Result:
"Connect called" should be displayed only once.
Program should not Segmentation fault.
Actual Output:
./sslex 192.168.11.141
Connect called
Connecting... to 192.168.11.141
Connecting to: 192.168.11.141
Connect called
Segmentation fault (core dumped)
Debugger Output and Backtrace:
Starting program: sslex 192.168.11.141
warning: Probes-based dynamic linker interface failed.
Reverting to original interface.
Connect called
Connecting... to 192.168.11.141
Connecting to: 192.168.11.141
Breakpoint 3, connect (hostnamePort=0x7fffffffe9db "192.168.11.141") at sslex_main.c:57
57 if (BIO_do_connect(g_bio) <= 0) { // BUGGY LINE
(gdb) bt
#0 connect (hostnamePort=0x7fffffffe9db "192.168.11.141") at sslex_main.c:57
#1 0x000055555555503a in main (argc=2, argv=0x7fffffffe698) at sslex_main.c:75
(gdb) s
Connect called
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff733d646 in ?? ()
(gdb) bt
#0 0x00007ffff733d646 in ?? ()
#1 0x00007ffff72e94d3 in ?? ()
#2 0x0000000000000000 in ?? ()
Your function connect() is hiding the standard neworking library function of the same name that OpenSSL is calling to make the actual TCP connection, but instead of getting the library one, it's calling yours.
Rename your function (say, to do_connect()) so it won't clash with the one from the library.
Related
(I have completely rewritten this question, as I have a minimal example now; see in history how original post looked like)
Consider this libusb program, which I compile under MINGW64 (part of MSYS2, which is updated as of today) on Windows 10 (also with latest updates as of today):
libusb-test.c
// build under MINGW64 on Windows with (assuming mingw64/mingw-w64-x86_64-libusb 1.0.26-1 installed):
// gcc -Wall -g -I/mingw64/include/libusb-1.0 libusb-test.c -o libusb-test.exe -lusb-1.0
#include <inttypes.h> //PRIu64
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "libusb.h"
int main(int argc, char *argv[]) {
libusb_device **devs;
ssize_t cnt;
int r=0, i;
struct libusb_device_descriptor desc;
r = libusb_init(NULL);
if (r < 0) {
printf("error: Cannot libusb_init, exiting\r\n");
return r;
}
cnt = libusb_get_device_list(NULL, &devs);
if (cnt < 0) {
printf("error: Cannot libusb_get_device_list (Failed to enumerate USB devices), exiting\r\n");
libusb_exit(NULL);
return 1;
}
for (i = 0; devs[i]; i++) { // or: for (libusb_device **dev = devs; *dev; dev++)
libusb_device *dev = devs[i];
libusb_device_handle *handle = NULL;
printf("Trying device %d: %p\r\n", i, dev);
int ret = libusb_get_device_descriptor(dev, &desc);
if (ret) {
printf(" Failed to read device %d descriptor (%d)\r\n", i, ret);
} else {
ret = libusb_open(dev, &handle);
if (ret) {
printf(" Failed to open device %d (%d)\r\n", i, ret);
} else {
printf( " device %d open ( handle %p )\r\n", i, handle);
}
if (handle) {
libusb_close(handle);
handle = NULL;
}
}
} // end for
libusb_free_device_list(devs, 1);
libusb_exit(NULL);
printf("Program finished; exiting.");
return r;
}
The program, after compiling, actually seems to run fine:
$ ./libusb-test.exe
Trying device 0: 000001eeb9321890
Failed to open device 0 (-5)
Trying device 1: 000001eeb9320c30
device 1 open ( handle 000001eeb93242e0 )
...
Trying device 12: 000001eeb9322640
device 12 open ( handle 000001eeb93242e0 )
Trying device 13: 000001eeb7a7bc50
Failed to open device 13 (-12)
Program finished; exiting.
... however, if I try to debug with gdb by breaking into main - it fails with "Cannot insert breakpoint":
$ gdb --args ./libusb-test.exe
GNU gdb (GDB) 12.1
...
Reading symbols from ./libusb-test.exe...
(gdb) b main
Breakpoint 1 at 0x140001593: file libusb-test.c, line 11.
(gdb) r
Starting program: C:\msys64\tmp\libusb-test.exe
[New Thread 20144.0x24c0]
[New Thread 20144.0x436c]
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x140001584
Command aborted.
(gdb)
Why does this happen - and how can I get gdb to break into this program?
I am trying to write my own wrapper function to libhiredis to use in my project but when i try to pass the redis_context into another function to issue commands from there. The code segfaults and reports this through gdb:
GDB Error:
Program received signal SIGSEGV, Segmentation fault.
sdscatlen (s=0x0, t=0x555555757690, len=22) at sds.c:239
239 sds.c: No such file or directory.
(gdb) backtrace
#0 sdscatlen (s=0x0, t=0x555555757690, len=22) at sds.c:239
#1 0x00007ffff7bcd300 in __redisAppendCommand (c=0x7fffffffddd0, cmd=<optimized out>, len=<optimized out>) at hiredis.c:910
#2 0x00007ffff7bcd38c in redisvAppendCommand (c=0x7fffffffddd0, format=<optimized out>, ap=<optimized out>) at hiredis.c:942
#3 0x00007ffff7bcd579 in redisvCommand (c=0x7fffffffddd0, format=<optimized out>, ap=ap#entry=0x7fffffffdcc0) at hiredis.c:1003
#4 0x00007ffff7bcd634 in redisCommand (c=<optimized out>, format=<optimized out>) at hiredis.c:1012
#5 0x0000555555554b9e in getnow (redis_context=0x7fffffffddd0) at src/testRedis.c:18
#6 0x0000555555554c14 in main () at src/testRedis.c:49
Here is the code:
RedisWrapper.h:
#ifndef REDIS_WRAPPER_H
#define REDIS_WRAPPER_H
int redis_wrapper_init(redisContext *redis_context, char *ip, int port);
int redis_wrapper_set(redisContext *redis_context, char *key, char *value);
int redis_wrapper_get(redisContext *redis_context, char *key, char *retrieved_value);
#endif
RedisWrapper.c:
#include <hiredis.h>
int redis_wrapper_init(redisContext *redis_context, char* ip, int port) {
redis_context = redisConnect(ip, port);
if (redis_context == NULL || redis_context->err) {
if (redis_context) {
fprintf(stderr, "cget: redis init error: %s\n", redis_context->errstr);
} else {
fprintf(stderr, "cget: can't allocate redis context\n");
}
return 1;
}
return 0;
}
int redis_wrapper_set(redisContext *redis_context, char *key, char *value) {
redisReply *reply = redisCommand(redis_context, "SET %s %s", key, value);
if(reply == NULL) {
fprintf(stderr, "cget: redis set error key: %s, val: %s\n", key, value);
fprintf(stderr, "cget: redis set error: %s\n", redis_context->errstr);
return 1;
}
freeReplyObject(reply);
return 0;
}
int redis_wrapper_get(redisContext *redis_context, char *key, char *retrieved_value) {
redisReply *reply = redisCommand(redis_context, "GET foo");
if(reply == NULL) {
fprintf(stderr, "cget: redis get error key: %s\n", key);
fprintf(stderr, "cget: redis get error: %s\n", redis_context->errstr);
return 1;
}
printf("GET: %s\n", reply->str);
retrieved_value = reply->str;
freeReplyObject(reply);
return 0;
}
Main.c
#include <stdio.h>
#include <string.h>
#include <hiredis.h>
#include "RedisWrapper.h"
void getnow(redisContext *redis_context) {
redisReply *reply = redisCommand(redis_context, "GET foo");
printf("GET foo: %s\n", reply->str);
freeReplyObject(reply);
}
int main() {
redisContext *redis_context;
redis_wrapper_init(redis_context, "127.0.0.1", 6379);
getnow(redis_context);
return 0;
}
My compile command:
gcc -Wall -g -o src/redisTest src/RedisWrapper.c `pkg-config --cflags hiredis` src/Main.c `pkg-config --libs hiredis`
More Details:
# uname -a
Linux node1 4.13.0-21-generic #24-Ubuntu SMP Mon Dec 17 17:29:16 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
# locate libhiredis
/usr/lib/x86_64-linux-gnu/libhiredis.a
/usr/lib/x86_64-linux-gnu/libhiredis.so
/usr/lib/x86_64-linux-gnu/libhiredis.so.0.13
/usr/share/doc/libhiredis-dbg
/usr/share/doc/libhiredis-dev
/usr/share/doc/libhiredis0.13
/usr/share/doc/libhiredis-dbg/changelog.Debian.gz
/usr/share/doc/libhiredis-dbg/copyright
/usr/share/doc/libhiredis-dev/README.md.gz
/usr/share/doc/libhiredis-dev/changelog.Debian.gz
/usr/share/doc/libhiredis-dev/copyright
/usr/share/doc/libhiredis0.13/changelog.Debian.gz
/usr/share/doc/libhiredis0.13/copyright
/var/cache/apt/archives/libhiredis-dbg_0.13.3-2_amd64.deb
/var/cache/apt/archives/libhiredis0.13_0.13.3-2_amd64.deb
/var/lib/dpkg/info/libhiredis-dbg:amd64.list
/var/lib/dpkg/info/libhiredis-dbg:amd64.md5sums
/var/lib/dpkg/info/libhiredis-dev:amd64.list
/var/lib/dpkg/info/libhiredis-dev:amd64.md5sums
/var/lib/dpkg/info/libhiredis0.13:amd64.list
/var/lib/dpkg/info/libhiredis0.13:amd64.md5sums
/var/lib/dpkg/info/libhiredis0.13:amd64.shlibs
/var/lib/dpkg/info/libhiredis0.13:amd64.symbols
/var/lib/dpkg/info/libhiredis0.13:amd64.triggers
What i found strange is that if i do all the operations all in the Main.c and not use the wrapper files it works. That is not useful to my project though, i need to be able to pass the redis_context around and have it work.
redis_context in redis_wrapper_init should be passed by reference (in C by pointer) to keep result of assignment redis_context = redisConnect(ip, port); after calling this function. Without this, you assign pointer returned by redisConnect to local variable, which is destroyed when function returns.
So definition should be
int redis_wrapper_init(redisContext ** redis_context, char* ip, int port) {
*redis_context = redisConnect(ip, port);
if (*redis_context == NULL || (*redis_context)->err) {
if (*redis_context) {
fprintf(stderr, "cget: redis init error: %s\n", (*redis_context)->errstr);
}
...
}
}
in main you get address of redis_context variable and pass it to redis_wrapper_init
redisContext *redis_context = 0;
redis_wrapper_init(&redis_context, "127.0.0.1", 6379);
My goal: Is to monitor the state of my network interface (mainly wireless) from my firmware (in C) by monitoring the wpa_supplicant through the D-Bus interfaces. I would like to stick with C and low-level API of D-bus.
What I have so far
I've written a small program in C, copied most of the code as is from this SO user.
I've gone through all possible tutorials on D-Bus and wpa_supplicant
My program compiles and works properly. However it does not produce the expected output.
Here's my code:
#include <stdio.h>
#include <dbus/dbus.h>
#define WPAS_DBUS_SERVICE "fi.epitest.hostap.WPASupplicant"
#define WPAS_DBUS_PATH "/fi/epitest/hostap/WPASupplicant"
#define WPAS_DBUS_INTERFACE "fi.epitest.hostap.WPASupplicantAAA"
#define WPAS_DBUS_PATH_INTERFACES WPAS_DBUS_PATH "/Interfaces"
#define WPAS_DBUS_IFACE_INTERFACE WPAS_DBUS_INTERFACE ".Interfaces"
#define WPAS_DBUS_NETWORKS_PART "Networks"
#define WPAS_DBUS_IFACE_NETWORK WPAS_DBUS_INTERFACE ".Network"
#define WPAS_DBUS_BSSIDS_PART "BSSIDs"
#define WPAS_DBUS_IFACE_BSSID WPAS_DBUS_INTERFACE ".BSSID"
int ret;
char signalDesc[1024]; // Signal description as string
// Signal handling
signal(SIGKILL, stopLoop);
signal(SIGTERM, stopLoop);
void loop(DBusConnection* conn)
{
DBusMessage* msg;
DBusMessageIter args;
DBusMessageIter subArgs;
int argType;
int i;
int buffSize = 1024;
char strValue[buffSize];
const char* member = 0;
while (1)
{
// non blocking read of the next available message
dbus_connection_read_write(conn, 0);
msg = dbus_connection_pop_message(conn);
// loop again if we haven't read a message
if (!msg)
{
printf("No message received, waiting a little ...\n");
sleep(1);
continue;
}
else printf("Got a message, will analyze it ...\n");
// Print the message member
printf("Got message for interface %s\n",
dbus_message_get_interface(msg));
member = dbus_message_get_member(msg);
if(member) printf("Got message member %s\n", member);
// Check has argument
if (!dbus_message_iter_init(msg, &args))
{
printf("Message has no argument\n");
continue;
}
else
{
// Go through arguments
while(1)
{
argType = dbus_message_iter_get_arg_type(&args);
if (argType == DBUS_TYPE_STRING)
{
printf("Got string argument, extracting ...\n");
char* str = NULL;
dbus_message_iter_get_basic(&args, &str);
printf("Received string: \n %s \n",str);
}
else
printf("Arg type not implemented yet !\n");
if(dbus_message_iter_has_next(&args))
dbus_message_iter_next(&args);
else break;
}
printf("No more arguments!\n");
}
// free the message
dbus_message_unref(msg);
}
}
int main()
{
DBusConnection *connection;
DBusError error;
char *name = "org.share.linux";
dbus_error_init(&error);
connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
if ( dbus_error_is_set(&error) )
{
printf("Error connecting to the daemon bus: %s",error.message);
dbus_error_free(&error);
return 1;
}
// request a name on the bus
ret = dbus_bus_request_name(connection, WPAS_DBUS_SERVICE, 0, &error);
if (dbus_error_is_set(&error))
{
printf(stderr, "Name Error (%s)\n", error.message);
dbus_error_free(&error);
}
/* Connect to signal */
// Interface signal ..
printf(signalDesc, "type='signal',interface='%s'",WPAS_DBUS_IFACE_INTERFACE);
dbus_bus_add_match(connection, signalDesc, &error);
dbus_connection_flush(connection);
if (dbus_error_is_set(&error))
{
fprintf(stderr, "Match Error (%s)\n", error.message);
return 1;
}
// Do main loop
loop(connection);
dbus_connection_close(connection);
return 0;
}
List of D-bus services on my BBB
Output
Some pointers
I would like to catch the signals as shown in the D-Bus API of wpa_supplicant.
Some things I would like to do -- see when a wireless interface say wlan0 is enabled, connects to access point etc. Also capability to set AP and stuff.
Its catching signal from other interfaces for which no match has been added.
I run this program and change the state of the networking interfaces but I dont get any signals. Also, I dont know if requesting name on the bus is necessary as I'm just listening.
What's the possible issue here? Any pointers will be really helpful.
I have a program that is using a library called "wjelement", whenever I try to use this library with FastCGI I get a segfault. I have made a simplified test case below. If I compile the code without fcgi_stdio.h and do not link against the library, the code works fine, if I add the fastcgi header and link against it I get a segfault, even if I don't use any fast cgi calls.
In My FastCGI code the opposite is also true, if I remove the WJelement code the rest of the program works fine.
I'm not sure if I need to blame my program, the FastCGI Library, or the WJElement library...
#include <stdio.h>
#include <fcgi_stdio.h>
#include <wjreader.h>
int main (int argc, char *argv[]) {
FILE *my_schema_file;
my_schema_file = fopen("test_schema.json", "rb");
if (my_schema_file == NULL) {
printf("Failed to open test schema file\n");
return 1;
} else {
printf("Opened test schema file\n");
}
WJReader my_schema_reader;
my_schema_reader = WJROpenFILEDocument(my_schema_file, NULL, 0);
if (my_schema_reader == NULL) {
printf("Failed to open test schema reader\n");
return 1;
} else {
printf("Opened test schema reader\n");
}
return 0;
}
GDB Backtrace:
Program received signal SIGSEGV, Segmentation fault.
0x0000003e19e6c85f in __GI__IO_fread (buf=0x6023c4, size=1, count=2731, fp=0x602250) at iofread.c:41
41 _IO_acquire_lock (fp);
(gdb) backtrace
#0 0x0000003e19e6c85f in __GI__IO_fread (buf=0x6023c4, size=1, count=2731, fp=0x602250) at iofread.c:41
#1 0x00007ffff7dde5d9 in WJRFileCallback () from /lib/libwjreader.so.0
#2 0x00007ffff7dde037 in WJRFillBuffer () from /lib/libwjreader.so.0
#3 0x00007ffff7dde4e9 in _WJROpenDocument () from /lib/libwjreader.so.0
#4 0x000000000040081f in main (argc=1, argv=0x7fffffffdeb8) at test.c:20
Found the answer here: http://www.fastcgi.com/devkit/doc/fcgi-devel-kit.htm
If your application passes FILE * to functions implemented in libraries for which you do not have source code, then you'll need to include the headers for these libraries before you include fcgi_stdio.h
I then had to convert from FCGI_FILE * to FILE * with FCGI_ToFILE(FCGI_FILE *);
#include <stdio.h>
#include <wjreader.h>
#include <fcgi_stdio.h>
int main (int argc, char *argv[]) {
FILE *my_schema_file;
my_schema_file = fopen("test_schema.json", "rb");
if (my_schema_file == NULL) {
printf("Failed to open test schema file\n");
return 1;
} else {
printf("Opened test schema file\n");
}
WJReader my_schema_reader;
my_schema_reader = WJROpenFILEDocument(FCGI_ToFILE(my_schema_file), NULL, 0);
if (my_schema_reader == NULL) {
printf("Failed to open test schema reader\n");
return 1;
} else {
printf("Opened test schema reader\n");
}
return 0;
}
here are the code folks :
#include <stdio.h>
#include <stdlib.h>
#include <gnokii.h>
#include <signal.h>
/*
*
*/
#define _(x) x
struct gn_statemachine *state = NULL;
void busterminate(void) {
gn_lib_phone_close(state);
gn_lib_phoneprofile_free(&state);
gn_lib_library_free();
}
void businit(void) {
gn_error error;
atexit(busterminate);
error = gn_lib_phoneprofile_load(NULL, &state);
if (GN_ERR_NONE == error) {
error = gn_lib_phone_open(state);
}
if (GN_ERR_NONE != error) {
fprintf(stderr, "%s\n", gn_error_print(error));
exit(-1);
}
}
void signal_handler(int signal) {
(void)signal;
exit(-2);
}
int main(int argc, char *argv[]) {
gn_data *data;
gn_sms sms;
gn_error error;
businit();
signal(SIGINT, signal_handler);
gn_data_clear(data);
sprintf(sms.remote.number,"%s","+628571641111");
sprintf(sms.user_data[0].u.text,"%s","tesss");
data->message_center = calloc(1, sizeof(gn_sms_message_center));
data->message_center->id= 1;
error = gn_sm_functions(GN_OP_GetSMSCenter, data, state);
if(error == GN_ERR_NONE)
{
snprintf(sms.smsc.number,sizeof(sms.smsc.number),"%s",data->sms->smsc.number); // set to sms.smsc.number from data.sms.smsc.number
sms.smsc.type = data->message_center->smsc.type;
//g_slice_free(gn_sms_message_center,data->message_center); // free the ram
free(data->message_center);
}
if(!sms.smsc.number[0])
{
printf("failed once getting sms center number\n");
}
if(!sms.smsc.type)
{
sms.smsc.type = GN_GSM_NUMBER_Unknown;
}
data->sms = &sms;
//send the message
error = gn_sms_send(data,state);
if(error == GN_ERR_NONE)
{
if(sms.parts > 1)
{
int j;
printf("sms sent with : %d parts, and reference number is : ", sms.parts);
for(j=0; j < sms.parts; j++)
{
printf("%d\n",sms.reference[j]);
}
}
else
{
printf("one sms sent with reference number : %d\n",sms.reference[0]);
}
}
else
{
printf("libgnokii error : %s\n",gn_error_print(error));
}
free(sms.reference);
return 0;
}
im gonna send an sms to +628571641111, with the text "tesss", but unfortunately the OS said it segmentation fault, thus, where is my fault ?
$ gnokii --identify
GNOKII Version 0.6.29
IMEI : 3556XXXXX509XXX
Manufacturer : ZTE INCORPORATED
Model : MF627
Product name : MF627
Revision : BD_3GHAP673A4V1.0.0
$ gdb -q ./gnokii_send_sms
Reading symbols from /root/gnokii_send_sms...(no debugging symbols found)...done.
(gdb) r
Starting program: /root/gnokii_send_sms
[Thread debugging using libthread_db enabled]
Program received signal SIGSEGV, Segmentation fault.
0x00317334 in ?? () from /lib/libc.so.6
(gdb)
You're passing to gn_data_clear a pointer you haven't initialized yet. In the beginning of your main function you need to have
gn_data data;
Not
gn_data *data;
Here's the function implementation:
GNOKII_API void gn_data_clear(gn_data *data)
{
memset(data, 0, sizeof(gn_data));
}