I am writing a Java interposer to modify network communication related system calls. Basically, I want to modify the IP and port of the intended recipient.
The code works correctly on my laptop, but on university PC, it gives a stack smashing error as:
*** 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]
The relevant code (interposition of connect system call) is as follows:
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;
}
Here, sock is a socket that I have initialized in "constructor" of the shared library.
The program works correctly and prints Done. On the last (return) line, it gives the stack smashing error. I have no idea what is causing this.
I suspect that strrcr returns NULL in the line
int pos = strrchr(buffer, NAT_VM_DELIMITER) - buffer;
Then pos will be huge, and the following lines will read and write invalid addresses.
Always check the return value of functions (especially when they're run on data received from outside your program).
Also, as I wrote in my comment, never use sprintf. I can't tell if it fails, because I don't know what's NAT_VM_CONNECT_RULE. Even if you counted the bytes and know you're OK, you should still be careful and use snprintf instead.
Related
I create this entrypoint on the Java side:
#CEntryPoint(name = "printStruct")
public static void printStruct(IsolateThread thread, VoidPointer message, int size) {
System.out.println(message.isNull());
ByteBuffer buf = CTypeConversion.asByteBuffer(message, size);
System.out.println(new String(buf.array()));
}
It's compiled by the GraalVM native-image compiler and libexample.h is generated with:
void printStruct(graal_isolatethread_t* thread, void* message, int size);
Then I build and run C code:
int main() {
graal_isolatethread_t *thread;
int i = graal_create_isolate(NULL, NULL, &thread);
if (i != 0) {
printf("Error creating isolate %d", i);
return -1;
}
printStruct(thread, "heh", 3);
i = graal_tear_down_isolate(thread);
if (i != 0) {
printf("Error tearing down isolate %d", i);
}
return 0;
}
It builds fine but being executed outputs:
false
java.lang.UnsupportedOperationException: null
at java.nio.ByteBuffer.array(ByteBuffer.java:1471)
at examples.App.printStruct(App.java:26)
I couldn't find any explanation of that. The documentation of asByteArray says:
Creates a ByteBuffer that refers to the native memory at the specified address.
So the message is not a null pointer but I cannot access byte array I passed.
you need to transfer the bytes from the buffer to destination array:
var buf = CTypeConversion.asByteBuffer(message, size);
byte[] arr = new byte[buf.remaining()];
buf.get(arr);
I am using the following code. This is the code after device discovery works fine.
BluetoothDevice btdevice = adapter.getRemoteDevice(device.getAddress());
btdevice.fetchUuidsWithSdp();
ParcelUuid[] bt = btdevice.getUuids();
for (ParcelUuid x:bt) {
try {
BluetoothSocket socket = btdevice.createRfcommSocketToServiceRecord(x.getUuid());
socket.connect();
if (socket.isConnected())
break;
} catch (IOException e) {
e.printStackTrace();
}
}
On PC side I am running Ubuntu 18.04 and BlueZ version 5.48.
The server side code is:
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
sdp_session_t *register_service()
{
uint32_t svc_uuid_int[] = { 0x00000000,0x00000000,0x00000000,0x00000000 };
uint8_t rfcomm_channel = 11;
const char *service_name = "Remote Host";
const char *service_dsc = "What the remote should be connecting to.";
const char *service_prov = "Your mother";
uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_uuid;
sdp_list_t *l2cap_list = 0,
*rfcomm_list = 0,
*root_list = 0,
*proto_list = 0,
*access_proto_list = 0;
sdp_data_t *channel = 0, *psm = 0;
sdp_record_t *record = sdp_record_alloc();
// set the general service ID
sdp_uuid128_create( &svc_uuid, &svc_uuid_int );
sdp_set_service_id( record, svc_uuid );
// make the service record publicly browsable
sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
root_list = sdp_list_append(0, &root_uuid);
sdp_set_browse_groups( record, root_list );
// set l2cap information
sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
l2cap_list = sdp_list_append( 0, &l2cap_uuid );
proto_list = sdp_list_append( 0, l2cap_list );
// set rfcomm information
sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
channel = sdp_data_alloc(SDP_UINT8, &rfcomm_channel);
rfcomm_list = sdp_list_append( 0, &rfcomm_uuid );
sdp_list_append( rfcomm_list, channel );
sdp_list_append( proto_list, rfcomm_list );
// attach protocol information to service record
access_proto_list = sdp_list_append( 0, proto_list );
sdp_set_access_protos( record, access_proto_list );
// set the name, provider, and description
sdp_set_info_attr(record, service_name, service_prov, service_dsc);
int err = 0;
sdp_session_t *session = 0;
// connect to the local SDP server, register the service record, and
// disconnect
session = sdp_connect( BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY );
err = sdp_record_register(session, record, 0);
// cleanup
//sdp_data_free( channel );
sdp_list_free( l2cap_list, 0 );
sdp_list_free( rfcomm_list, 0 );
sdp_list_free( root_list, 0 );
sdp_list_free( access_proto_list, 0 );
return session;
}
int main(int argc, char **argv)
{
struct sockaddr_rc loc_addr = { 0 }, rem_addr = { 0 };
char buf[1024] = { 0 };
char str[1024] = { 0 };
int s, client, bytes_read;
sdp_session_t *session;
socklen_t opt = sizeof(rem_addr);
session = register_service();
s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
loc_addr.rc_family = AF_BLUETOOTH;
loc_addr.rc_bdaddr = *BDADDR_ANY;
loc_addr.rc_channel = (uint8_t) 11;
bind(s, (struct sockaddr *)&loc_addr, sizeof(loc_addr));
listen(s, 1);
client = accept(s, (struct sockaddr *)&rem_addr, &opt);
ba2str( &rem_addr.rc_bdaddr, buf );
fprintf(stderr, "accepted connection from %s\n", buf);
memset(buf, 0, sizeof(buf));
bytes_read = read(client, buf, sizeof(buf));
if( bytes_read > 0 ) {
printf("received [%s]\n", buf);
}
sprintf(str,"to Android.");
printf("sent [%s]\n",str);
write(client, str, sizeof(str));
close(client);
close(s);
sdp_close( session );
return 0;
}
I have tried with channels 1 and 11. I tried using the UUID I provided in C code and also the UUIDs by using btdevice.getUuids(); and the Uuids that I am receiving are
0000110a-0000-1000-8000-00805f9b34fb
00001108-0000-1000-8000-00805f9b34fb
0000110b-0000-1000-8000-00805f9b34fb
0000110e-0000-1000-8000-00805f9b34fb
00001112-0000-1000-8000-00805f9b34fb
00000000-0000-1000-8000-00805f9b34fb
00000000-0000-1000-8000-00805f9b34fb
The android code is able to pair to linux device but I think that't the system implementation of Ubuntu and not my code because it's not printing anything.
On android side it gives the following error on the line:
socket.connect();
java.io.IOException: read failed, socket might closed or timeout, read
ret: -1
Please someone tell me what can I do? it has already taken one full day of my time.
I'm having an issue where I need to send an INT32 to another application, but from what I've read, messagepack.putInt and messagepack.putLong will try to optimize this into UINT32 which is causing problems for the receiving application.
The receiving application is giving me the error message
decode error, skipping message. msgp: attempted to decode type "uint" with method for "int"
I am using maven with the dependency
<dependency>
<groupId>org.msgpack</groupId>
<artifactId>msgpack-core</artifactId>
<version>0.8.13</version>
</dependency>
Someone else had this same issue and stated the solution to it was as follows
"OK, so we found the problem, it seems like metricTank requires the time property of the message object to be serialized as INT32, however the packInt (or packLong) will always try to optimize it into UINT32 which metricTank doesnt like. so we had to use addPayload and serialize MessagePacker.Code.INT32, and then the actual 4 bytes of the time property."
But I am unsure what to do and I am unable to contact the OP.
I have tried the following but it does not work
ByteBuffer buf = ByteBuffer.allocate(1 + Long.BYTES);
buf.put(MessagePack.Code.INT32);
buf.putLong(md.time);
packer.addPayload(buf.array());
The bytes array needs to be 5 in length, first byte is the header, being 0xd2 and the other 4 bytes need to be the value
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeLong(md.time);
dos.close();
byte[] longBytes = baos.toByteArray();
ByteBuffer lBytes = ByteBuffer.allocate(4);
for (int i = 0; i < 4; i++) {
lBytes.put(longBytes[i]);
}
ByteBuffer buf = ByteBuffer.allocate(5);
buf.put((byte) 0xd2);
buf.put(lBytes.array());
This produces no error, but the time value is incorrect when received.
Could someone show me how I can pack an INT32 into my MessagePack rather than UINT32 or show me how I can pack the data in the correct way so it is unpacked correctly on the receiving application?
The receiving application is written in Go and uses the tinylib msgp library to decode the data
// ReadInt64Bytes tries to read an int64
// from 'b' and return the value and the remaining bytes.
// Possible errors:
// - ErrShortBytes (too few bytes)
// - TypeError (not a int)
func ReadInt64Bytes(b []byte) (i int64, o []byte, err error) {
l := len(b)
if l < 1 {
return 0, nil, ErrShortBytes
}
lead := b[0]
if isfixint(lead) {
i = int64(rfixint(lead))
o = b[1:]
return
}
if isnfixint(lead) {
i = int64(rnfixint(lead))
o = b[1:]
return
}
switch lead {
case mint8:
if l < 2 {
err = ErrShortBytes
return
}
i = int64(getMint8(b))
o = b[2:]
return
case mint16:
if l < 3 {
err = ErrShortBytes
return
}
i = int64(getMint16(b))
o = b[3:]
return
case mint32:
if l < 5 {
err = ErrShortBytes
return
}
i = int64(getMint32(b))
o = b[5:]
return
case mint64:
if l < 9 {
err = ErrShortBytes
return
}
i = getMint64(b)
o = b[9:]
return
default:
err = badPrefix(IntType, lead)
return
}
}
This checks the first byte, and if the first byte is equal to mint32 which is 0xd2, then the next four bytes are read, which is the value of the long using getmint32
func getMint32(b []byte) int32 {
return (int32(b[1]) << 24) | (int32(b[2]) << 16) | (int32(b[3]) << 8) | (int32(b[4]))
}
In this particular issue, the receiving application had to receive an INT32 and the bytes array needs to be 5 in length. The first byte is the header 0xd2 as seen in the OP. This tells the decoding method that it's an INT32. The next four 4 bytes is the time value.
I was forgetting that a long is 8 bytes so we just need to use epoch time which is an integer.
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeInt((int)(md.time/1000));
dos.close();
byte[] timeBytes = baos.toByteArray();
ByteBuffer buf = ByteBuffer.allocate(5);
buf.put((byte) 0xd2);//header
buf.put(timeBytes);//time value (int32 bytes not uint32)
I'm trying to work with JSSC.
I built my app according to this link:
https://code.google.com/p/java-simple-serial-connector/wiki/jSSC_examples
My event handler looks like:
static class SerialPortReader implements SerialPortEventListener {
public void serialEvent(SerialPortEvent event) {
if(event.isRXCHAR()){//If data is available
try {
byte buffer[] = serialPort.readBytes();
}
catch (SerialPortException ex) {
System.out.println(ex);
}
}
}
}
}
The problem is that I'm always not getting the incoming data in one piece. (I the message has a length of 100 bytes, Im getting 48 and 52 bytes in 2 separates calls)
- The other side send me messages in different lengths.
- In the ICD Im working with, there is a field which tell us the length of the message. (from byte #10 to byte #13)
- I cant read 14 bytes:
(serialPort.readBytes(14);,
parse the message length and read the rest of the message:
(serialPort.readBytes(messageLength-14);
But if I will do it, I will not have the message in once piece (I will have 2 separates byte[] and I need it in one piece (byte[]) without the work of copy function.
Is it possible ?
When working with Ethernet (SocketChannel) we can read data using ByteBuffer. But with JSSC we cant.
Is there a good alternative to JSSC ?
Thanks
You can't rely on any library to give you all the content you need at once because :
the library dont know how many data you need
the library will give you data as it comes and also depending on buffers, hardware, etc
You must develop your own business logic to handle your packets reception. It will of course depend on how your packets are defined : are they always the same length, are they separated with same ending character, etc.
Here is an example that should work with your system (note you should take this as a start, not a full solution, it doesn't include timeout for example) :
static class SerialPortReader implements SerialPortEventListener
{
private int m_nReceptionPosition = 0;
private boolean m_bReceptionActive = false;
private byte[] m_aReceptionBuffer = new byte[2048];
#Override
public void serialEvent(SerialPortEvent p_oEvent)
{
byte[] aReceiveBuffer = new byte[2048];
int nLength = 0;
int nByte = 0;
switch(p_oEvent.getEventType())
{
case SerialPortEvent.RXCHAR:
try
{
aReceiveBuffer = serialPort.readBytes();
for(nByte = 0;nByte < aReceiveBuffer.length;nByte++)
{
//System.out.print(String.format("%02X ",aReceiveBuffer[nByte]));
m_aReceptionBuffer[m_nReceptionPosition] = aReceiveBuffer[nByte];
// Buffer overflow protection
if(m_nReceptionPosition >= 2047)
{
// Reset for next packet
m_bReceptionActive = false;
m_nReceptionPosition = 0;
}
else if(m_bReceptionActive)
{
m_nReceptionPosition++;
// Receive at least the start of the packet including the length
if(m_nReceptionPosition >= 14)
{
nLength = (short)((short)m_aReceptionBuffer[10] & 0x000000FF);
nLength |= ((short)m_aReceptionBuffer[11] << 8) & 0x0000FF00;
nLength |= ((short)m_aReceptionBuffer[12] << 16) & 0x00FF0000;
nLength |= ((short)m_aReceptionBuffer[13] << 24) & 0xFF000000;
//nLength += ..; // Depending if the length in the packet include ALL bytes from the packet or only the content part
if(m_nReceptionPosition >= nLength)
{
// You received at least all the content
// Reset for next packet
m_bReceptionActive = false;
m_nReceptionPosition = 0;
}
}
}
// Start receiving only if this is a Start Of Header
else if(m_aReceptionBuffer[0] == '\0')
{
m_bReceptionActive = true;
m_nReceptionPosition = 1;
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
break;
default:
break;
}
}
}
After writing data to serial port it need to be flushed. Check the timing and pay attention to the fact that read should occur only after other end has written. read size is just an indication to read system call and is not guaranteed. The data may have arrived and is buffered in serial port hardware buffer but may not have been transferred to operating system buffer hence not to application. Consider using scm library, it flushes data after each write http://www.embeddedunveiled.com/
Try this:
Write your data to the serial port (using serialPort.writeBytes()) and if you are expecting a response, use this:
byte[] getData() throws SerialPortException, IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b;
try {
while ((b = serialPort.readBytes(1, 100)) != null) {
baos.write(b);
// System.out.println ("Wrote: " + b.length + " bytes");
}
// System.out.println("Returning: " + Arrays.toString(baos.toByteArray()));
} catch (SerialPortTimeoutException ex) {
; //don't want to catch it, it just means there is no more data to read
}
return baos.toByteArray();
}
Do what you want with the returned byte array; in my case I just display it for testing.
I found it works just fine if you read one byte at a time, using a 100ms timeout, and when it does time out, you've read all data in the buffer.
Source: trying to talk to an Epson serial printer using jssc and ESC/POS.
I'm trying to have a connection between a Java server and a C++ client. But when I read the data in my client I always have the same strange character (’). I tried to change the encoding in both side but nothing work.
Here is my Java code :
public class Serveur
{
public static void main(String[] args) throws Exception
{
final int PORT = 13370;
try
{
ServerSocket service= new ServerSocket(PORT);
Socket connection = service.accept();
PrintWriter pw = new PrintWriter(connection.getOutputStream());
String s = Integer.toString(5);
while(true)
{
pw.print(s.getBytes("UTF-8"));
pw.flush();
pw.close();
}
connection.close();
}
}
I also tried to use an OutputStream, a DataOutputStream and a BufferedOutputStream.
And here is the C++ code :
int main(int argc, char* argv[])
{
WSADATA WSAData;
WSAStartup(MAKEWORD(2,0), &WSAData);
SOCKET sock;
SOCKADDR_IN sin;
char buffer[512];
sin.sin_addr.s_addr = inet_addr("127.0.0.1");
sin.sin_family = AF_INET;
sin.sin_port = htons(13370);
sock = socket(AF_INET,SOCK_STREAM,0);
if(connect(sock, (SOCKADDR*)&sin, sizeof(sin)) != SOCKET_ERROR)
{
cout<<"connection"<<endl;
if(recv(sock, buffer, sizeof(buffer), 0) != SOCKET_ERROR)
{
string s = buffer;
wchar_t *pwchello = L"Hi";
wchar_t *pwc = (wchar_t *)malloc( sizeof( wchar_t ));
char *pmbhello = buffer;
int i = mbstowcs(pwc,pmbhello, MB_CUR_MAX);
cout << i << endl;
cout<<"cout : "<<pwc<<endl;
cout <<buffer<<endl;
printf("printf : %s\n", buffer);
cout << "wsagetlasterror() : "<<WSAGetLastError();
closesocket(sock);
WSACleanup();
free(m_pBuffer);
}
return 0;
}
As you can see, I tried different solution but without success.
Thanks in advance, and sorry for my english it may be not very good
You are mixing up lots of different encoding conversions and I/O strategies. You should try out the following simplified version:
if(connect(sock, (SOCKADDR*)&sin, sizeof(sin)) != SOCKET_ERROR)
{
cout << "connection" << endl;
// the result of 'recv()' is either SOCKET_ERROR or
// the number of bytes received. don't though away
// the return value.
const int result = recv(sock, buffer, sizeof(buffer), 0);
if(result != SOCKET_ERROR)
{
// use length (in bytes) returned by 'recv()'
// since buffer is not null terminated.
string s(buffer,result);
// 's' is in UTF-8 no converstion to wide strings
// should be necessary.
cout << "message: '" << s << "'." << endl;
}
closesocket(sock);
}
WSACleanup();
However, note that the standard output is in the current code page and usually UTF-8 is not the default code page. Outputing Unicode data to the console in windows requires a few other library calls to configure.
recv does not turn its destination buffer into null-terminated string. It fills in a number of bytes in the buffer, but does not append a 0.
You need top do this (with error checking, of course):
ssize_t bytesRead = recv(buffer, ...);
string str(buffer, bytesRead);
Also, be aware that recv does not guarantee that something sent in one call gets received in one call (unless you're doing UDP).
You're only allocating room for a single wchar_t here:
wchar_t *pwc = (wchar_t *)malloc( sizeof( wchar_t ));
You also assign buffer to string s, but never seem to use s
I have been having the same problem since last night. Finally figured out that encoding is not recognized by my server (written in C). Therefore, I changed in my client
someOutputStream.writeUTF(someSillyString);
to
someOutputStream.write(someSillyString.getBytes());
This way, I did not even need to typecast on the server side.