Разбиение стека в Java Interposer

Я пишу Java-Interposer для изменения системных вызовов, связанных с сетевой связью. В принципе, я хочу изменить IP и порт предполагаемого получателя.

Код работает правильно на моем ноутбуке, но на университетском ПК он дает ошибку разбития стека :

*** stack smashing detected ***: java terminated ======= Backtrace: ========= /lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x45)[0xb7702dd5] /lib/i386-linux-gnu/libc.so.6(+0xffd8a)[0xb7702d8a] /home/mwaqar/vibe/ldinterposer_2.so(+0x28e4)[0xb77c98e4] /home/mwaqar/vibe/ldinterposer_2.so(connect+0x9c5)[0xb77c9093] /usr/lib/jvm/java-7-openjdk-i386/jre/lib/i386/libnet.so(+0xceff)[0x8b226eff] /usr/lib/jvm/java-7-openjdk-i386/jre/lib/i386/libnet.so(Java_java_net_PlainSocketImpl_socketConnect+0x4c1)[0x8b227c51] 

Соответствующий код (interposition of connect system call) выглядит следующим образом:

 int connect(int fd, const struct sockaddr *sk, socklen_t sl) { struct sockaddr_in *lsk_in = (struct sockaddr_in *) sk; struct sockaddr_in6 *lsk_in6 = (struct sockaddr_in6 *) sk; struct sockaddr_in addr4; unsigned int len; int nbytes, oport, tport, ret, i; char ip_address[30]; char buffer[1024]; char tempBuffer[1024]; if((lsk_in->sin_family == AF_INET) || (lsk_in->sin_family == AF_INET6)) { if(lsk_in->sin_family == AF_INET) { oport = ntohs(lsk_in->sin_port); memcpy(&addr4.sin_addr.s_addr, &lsk_in->sin_addr.s_addr, sizeof(addr4.sin_addr.s_addr)); } else if(lsk_in->sin_family == AF_INET6) { oport = ntohs(lsk_in6->sin6_port); memcpy(&addr4.sin_addr.s_addr, lsk_in6->sin6_addr.s6_addr+12, sizeof(addr4.sin_addr.s_addr)); } memset(buffer, '\0', sizeof(buffer)); sprintf(buffer, "%s%c%s%c%i", NAT_VM_CONNECT_RULE, NAT_VM_DELIMITER, (char *)inet_ntoa(addr4.sin_addr), NAT_VM_DELIMITER, oport); nbytes = send(sock, buffer, strlen(buffer), 0); if(DEBUG_MODE) fprintf(stdout, "[LD_INTERPOSER] Sent[%s]\n", buffer); memset(buffer, '\0', sizeof(buffer)); nbytes = recv(sock, buffer, sizeof(buffer), 0); fprintf(stderr, "[LD_INTERPOSER] Received CONNECT [%s]\n", buffer); memset(ip_address, '\0', sizeof(ip_address)); int pos = strrchr(buffer, NAT_VM_DELIMITER) - buffer; strncpy(ip_address, buffer, pos); ip_address[pos] = '\0'; tport = atoi(buffer + pos + 1); if(lsk_in->sin_family == AF_INET) { lsk_in->sin_addr.s_addr = inet_addr(ip_address + 7); lsk_in->sin_port = htons(tport); } else if(lsk_in->sin_family == AF_INET6) { inet_pton(AF_INET6, ip_address, &(lsk_in6->sin6_addr)); lsk_in6->sin6_port = htons(tport); } fprintf(stderr, "[LD_INTERPOSER] IP[%s], Port[%d] for VM[%s]\n", ip_address, tport, vm_ip); } int my_ret = real_connect(fd, sk, sl); fprintf(stderr, "Done\n"); return my_ret; } 

Здесь sock – это сокет, который я инициализировал в «конструкторе» разделяемой библиотеки.

Программа работает правильно и печатает Готово . На последней (возвратной) линии она дает ошибку разбиения стека. Я понятия не имею, что вызывает это.

Я подозреваю, что strrcr возвращает NULL в строке

 int pos = strrchr(buffer, NAT_VM_DELIMITER) - buffer; 

Тогда pos будет огромным, и следующие строки будут читать и записывать неверные адреса.

Всегда проверяйте возвращаемое значение функций (особенно, когда они запускаются по данным, полученным вне вашей программы).

Кроме того, как я писал в своем комментарии, никогда не используйте sprintf . Я не могу сказать, не сработает ли он, потому что я не знаю, что такое NAT_VM_CONNECT_RULE . Даже если вы подсчитали байты и знаете, что все в порядке, вы все равно должны быть осторожны и вместо этого использовать snprintf .