How to use read() to get the adress of a pointer? - pointers

I have 2 programs communicating with each other through a fifo, one's the writer the other's the reader.
The writer sends a pointer to a struct containing information.
The reader should receive the pointer and be able to see the information inside the struct.
Header file:
typedef struct req{
int _code;
char _client_pipe[PIPENAME];
char _box_name[BOXNAME];
} request;
/*writes to pipe tx a pointer with information*/
void send_request(int tx, request *r1) {
ssize_t ret = write(tx, &r1, sizeof(r1));
if (ret < 0) {
fprintf(stdout, "ERROR: %s\n", ERROR_WRITING_PIPE);
exit(EXIT_FAILURE);
}
}
/*Returns a pointer to a struct containing the request*/
request *serialize(int code, char* client_pipe, char* box_name){
request *r1 = (request*) malloc(sizeof(request));
r1->_code = code;
strcpy(r1->_client_pipe, client_pipe);
strcpy(r1->_box_name, box_name);
return r1;
}
Program writer:
int main(int argc, char **argv){
(void *) argc; // in my program i used argc, but for this problem it's not important hence why the //typecast to void
char register_pipe[PIPENAME];
char personal_pipe[PIPENAME];
char box_name[BOXNAME];
strcpy(register_pipe, argv[1]);
strcpy(personal_pipe, argv[2]);
strcpy(box_name, argv[3]);
int reg_pipe = open(register_pipe, O_WRONLY);
if (reg_pipe == -1) {
fprintf(stdout, "ERROR: %s\n", UNEXISTENT_PIPE);
return -1;
}
send_request(reg_pipe, serialize(1, personal_pipe, box_name));
}
Program reader:
char register_pipe[PIPENAME];
strcpy(register_pipe, argv[1]);
if(mkfifo(register_pipe, 0644) < 0)
exit(EXIT_FAILURE);
if ((reg_pipe = open(register_pipe, O_RDONLY)) < 0){
exit(EXIT_FAILURE);
}
if ((reg_pipe = open(register_pipe, O_RDONLY)) < 0){
exit(EXIT_FAILURE);
}
request* buffer = (request*) malloc(sizeof(request)); //this might be the issue but not sure
ssize_t broker_read= read(reg_pipe, buffer, 256); //is not reading correctly
printf("%d, %s, %s\n", buffer->_code, buffer->_client_pipe, buffer->_box_name);
So if i start program reader and set register pipe as "reg", this will create the register pipe and wait for someone to join it.
Then if i start the program writer like ./writer reg personal box
this will open the reg pipe correctly, create a struct of type request and then sent it to the reader.
The reader should receive a pointer to a struct req set like:
_code = 1;
_client_pipe[PIPENAME] = "personal";
_box_name[BOXNAME] = "box";
The reader is in fact receiving but for some reason it's not receiving correctly.
If i try to print like in the last line, it will output some random numbers and letters.
How can i fix this?

You would need to have that structure exist inside a shared memory region that you have arranged to be mapped into both processes at the same address.
Without some such arrangement, each process has a private address space, so an address known to process A is meaningless to process B.
How to make such an arrangement is very much dependent upon you operating system, and perhaps even variant of said operating system.
You will likely find it easier to just copy the structure, as opposed to its address, via the fifo.

Related

AsyncTCP on ESP32 and Odd Heap/Socket Issues w/SOFTAP

I'm struggling with an issue where an ESP32 is running as a AP with AsyncTCP connecting multiple ESP32 clients. The AP receives some JSON data and replies with some JSON data. Without the handleData() function, the code runs 100% fine with no issues. Heap is static when no clients connect and issues only occur when clients start connecting.
Can anyone see anything with my code that could be causing heap corruption or other memory weirdness?
static void handleData(void* arg, AsyncClient* client, void *data, size_t len) {
int i = 0, j = 0;
char clientData[CLIENT_DATA_MAX];
char packetData[len];
char *packetBuf;
packetBuf = (char *)data;
clientData[0] = '\0';
for (i=0;i <= len;i++) {
packetData[j] = packetBuf[i]; //packetBuf[i];
if ((packetData[j] == '\n') || (i == len)) {
packetData[j] = '\0';
if ((j > 0) && (packetData[0] != '\n') && (packetData[0] != '\r')) {
// See sensorData() below...
parseData.function(packetData, clientData);
if (clientData != NULL) {
// TCP reply to client
if (client->space() > 32 && client->canSend()) {
client->write(clientData);
}
}
}
j = 0;
} else
j++;
}
}
void sensorData(void *data, void *retData) {
StaticJsonDocument<CLIENT_DATA_MAX> fields;
StaticJsonDocument<CLIENT_DATA_MAX> output;
char sensor[15] = "\0";
char MAC[18] = "\0";
char value[20] = "\0";
bool sendOK = false;
memcpy((char *)retData, "\0", 1);
DeserializationError error = deserializeJson(fields, (char *)data, CLIENT_DATA_MAX);
if (error) {
DEBUG_PRINTLN(F("deserializeJson() failed"));
return;
}
if (fields["type"])
strcpy(sensor, fields["type"]);
switch (sensor[0]) {
case 'C':
if (fields["value"])
strcpy(value, fields["value"]);
sendOK = true;
break;
case 'T': //DEBUG_PRINT(F("Temp "));
setExtTempSensor(fields["value"]);
sendOK = true;
break;
case 'N':
output["IT"] = intTempC; //Internal temp
output["B1"] = battLevels[0];
serializeJson(output, (char *)retData, CLIENT_DATA_MAX-1);
break;
}
if (sendOK) {
output["Resp"] = "Ok";
serializeJson(output, (char *)retData, CLIENT_DATA_MAX-1);
}
strcat((char *)retData, "\n");
}
static void handleNewClient(void* arg, AsyncClient* client) {
client->setRxTimeout(1000);
client->setAckTimeout(500);
client->onData(&handleData, NULL);
client->onError(&handleError, NULL);
client->onDisconnect(&handleDisconnect, NULL);
client->onTimeout(&handleTimeOut, NULL);
}
void startServer() {
server = new AsyncServer(WIFI_SERVER_PORT);
server->onClient(&handleNewClient, &server)
}
Using AsyncTCP on the ESP32 was having multiple issues. Heap issues, socket issues, assert issues, ACK timeouts, connection timeouts, etc. Swapping to AsyncUDP using the exact same code as shown above with romkey's changes, resolved all of my issues. (Just using romkey's fixes did not fix the errors I was having with AsyncTCP.) I don't believe the issue is with AsyncTCP but with ESP32 libraries.
Either you should declare packetData to be of length len + 1 or your for loop should iterate until i < len. Because the index starts at 0, packetData[len] is actually byte len + 1, so you'll overwrite something random when you store something in packetData[len] if the array is only len chars long.That something random may be the pointer stored in packetBuf, which could easily cause heap corruption.
You should always use strncpy() and never strcpy(). Likewise use strncat() rather than strcat(). Don't depend on having done the math correctly or on sizes not changing as your code evolves. strncpy() and strncat() will guard against overflows. You'll need to pass a length into sensorData() to do that, but sensorData() shouldn't be making assumptions about the available length of retData.
Your test
if (clientData != NULL) {
will never fail because clientData is the address of array and cannot change. I'm not sure what you're trying to test for here but this if will always succeed.
You can just write:
char sensor[15] = "";
you don't need to explicitly assign a string with a null byte in it.
And
memcpy((char *)retData, "\0", 1);
is equivalent to
((char *)retData)[0] = '\0';
What's the point of declaring retData to be void * in the arguments to sensorData()? Your code starts out with it being a char* before calling sensorData() and uses it as a char* inside sensorData(). void * is meant to be an escape hatch for passing around pointers without worrying about their type. You don't need that here and end up needing to extra casts back to char* because of it. Just declare the argument to be char* and don't worry about casting it again.
You didn't share the code that calls handleData() so there may well be issues outside of these functions.

How do i store data from HTTPREAD into a variable?

I need a way to store HTTPREAD data into a variable because I will be comparing its value to another variable. Is there any way?
{
myGsm.print("AT+HTTPPARA=\"URL\",\"http://7ae0eae2.ngrok.io/get-ignition/ccb37bd2-a59e-4e56-a7e1-68fd0d7cf845"); // Send PARA command
myGsm.print("\"\r\n");
delay(1000);
printSerialData();
myGsm.println();
myGsm.println("AT+HTTPACTION=0");//submit the GET request
delay(8000);//the delay is important if the return datas are very large, the time required longer.
printSerialData();
myGsm.println("AT+HTTPREAD=0,17");// read the data from the website you access
delay(3000);
printSerialData();
delay(1000);
}
void printSerialData()
{
while(myGsm.available()!=0)
Serial.write(myGsm.read());
}
I am assuming that the Serial.write(myGsm.read()) is where you want to get the data from. In other words, you are receiving the data through the serial connection, and you want to parse the data returned from the AT+HTTPREAD command.
Since you did not provide any clue about what that command is returning in the serial, I gonna use as an example a different command that I know the output, the below one:
TX=> AT+CCLK?
RX=> AT+CCLK?\n\r
\t+CCLK: "2020/03/03, 22:00:14"\n\r
So, the string you are going to get from the above AT+CCLK? command is this (I am assigning to a char pointer for the sake of understanding):
char *answer = "AT+CCLK?\n\r\t+CCLK: "2020/03/03, 22:00:14"\n\r";
What you need is to parse the answer (the char *answer in this example) to get the "numbers" into variables.
How to do that?
You need to walk over that string, moving to specific places. For example, to be able to convert the 2020 into a variable, you need to be at position answer[19], and then you can use, let's say, the strtoul() to convert to an integer and store it into a variable.
uint32_t year = strtoul(&answer[19], NULL, 10);
Then, to get the month, you need to walk a bit more to reach the position at the month on the string:
uint32_t month = strtoul(&answer[24], NULL, 10);
And so on, but you are using magic numbers for that, in other words, the numbers 19, 24 are positions specific for this string.
Then, how to make this "walking" smarter?
You can use tokens in conjunction with the strstr() to go to the specific points you want in the string. In this case, we want to move the pointer to the first 2, so we can pass that pointer to the strtoul() to convert it into an integer.
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
int main() {
char *answer = "AT+CCLK?\n\r\t+CCLK: "2020/03/03, 22:00:14"\n\r";
char *token = "CCLK: \"";
char *ptr;
uint32_t year;
ptr = strstr(answer, token);
if (ptr == NULL) {
printf("Token not found\n");
return -1;
}
year = strtoul(++ptr, NULL, 10);
printf("Year = %d\n", year);
Then, to make this code into a function to be more generic, here it is:
bool parse_answer_to_uint32(char *buff, char *tokens[], uint32_t *val)
{
char *ptr;
int i;
if (val == NULL)
return false;
for (i = 0; buff != NULL && tokens[i] != NULL; i++) {
ptr = strstr(buff, tokens[i]);
if (ptr == NULL)
return false;
buff = (ptr + strlen(tokens[i]));
}
// Here, you reached the point you want, based on the tokens you seek
if (buff == NULL)
return false;
*val = strtoul(buff, NULL, 10);
}
So, you can be able to call this function like this:
char *tokens[] = { "CCLK: \"" };
uint32_t year;
if (parse_answer_to_uint32(myGsm.read().c_str(), tokens, &year) == false)
return -1;
printf("year is = %d\n", year);
The printf will print 2020 based on the example above.
This function is pretty flexible and generic enough. All you need is to pass different tokens to reach different points of the string and reach the value you want.
Take character buffer, Concat data comming from serial into this buffer, and process that buffer for comparison.

Write Error: bad address on writing encrypted data to wrapper filesystem

I am implementing a simple caeser cipher on WrapFS to store encrypted data and decrypt while reading. For that purpose I made minor changes to wrapfs_read() and wrapfs_write() functions provided in the source code to encrypt and decypt the data. My decryption is working fine, but due to my encryption code I am getting an error on write as follows bash: echo: write error: bad address. Any help regarding handling it would be really appreciated.
void caeser_encrypt(char __user *encrypted, size_t count)
{
int i;
for(i=0;i<(unsigned int)count;i++)
encrypted[i]=encrypted[i]+3;
printk(KERN_INFO "%s",encrypted);
return;
}
static ssize_t wrapfs_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
int err = 0;
struct file *lower_file;
struct dentry *dentry = file->f_path.dentry;
char *encrypted = NULL;
lower_file = wrapfs_lower_file(file);
/*Added by me*/
encrypted=kmalloc(sizeof(buf),GFP_USER);
memcpy(encrypted,buf,count);
printk(KERN_INFO "%d %d",(int)sizeof(buf), (int)count);
caeser_encrypt(encrypted,count);
err = vfs_write(lower_file, encrypted, count, ppos);
/*Added by me*/
//err = vfs_write(lower_file, buf, count, ppos);
/* update our inode times+sizes upon a successful lower write */
if (err >= 0) {
fsstack_copy_inode_size(dentry->d_inode,
lower_file->f_path.dentry->d_inode);
fsstack_copy_attr_times(dentry->d_inode,
lower_file->f_path.dentry->d_inode);
}
/*Added by me*/
kfree(encrypted);
return err;
}
I would say that "const char __user *buf" is user space address and vfs_write expects user space address and you are passing kernel space address to it. Also you cannot directly copy user space address to kernel space address. You can try using copy_from_user and copy_to_user functions. I hope you are aware that caeser cipher is insecure.

dev_add_pack hook and memory leak

I have to write lkm, which would resend all incoming packets. Yep, I know about xt_TEE, but have to write it on my own. I've looked through some examples: http://www.phrack.org/archives/55/p55_0x0c_Building%20Into%20The%20Linux%20Network%20Layer_by_lifeline%20&%20kossak.txt (it's rather old) and http://www.xakep.ru/post/20794/default.asp?print=true (packet sniffer).
Then I've wrote my code:
//INCLUDES//////////////////////////////////////////////////////////////
#include <linux/ip.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/module.h>
#include <linux/kernel.h>
//ABOUT/////////////////////////////////////////////////////////////////
MODULE_AUTHOR("");
MODULE_DESCRIPTION("");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.0.1");
//DEFINES///////////////////////////////////////////////////////////////
//SYSCALLS//////////////////////////////////////////////////////////////
//PROTOTYPES/////////////////////////////////////////////////////////////
int new_hook_func(struct sk_buff *skb, struct device *dv, struct packet_type *pt);
void test();
//GLOBALS///////////////////////////////////////////////////////////////
static struct packet_type my_packet_type;
static char *dev = "eth0";
struct net_dev *d;
//INIT//////////////////////////////////////////////////////////////////
static int __init init(void)
{
printk(KERN_ALERT "module init\n");
d = dev_get_by_name(&init_net, dev);
my_packet_type.type = htons(ETH_P_ALL);
my_packet_type.func = new_hook_func;
my_packet_type.dev = d;
dev_add_pack(&my_packet_type);
return 0;
}
//EXIT//////////////////////////////////////////////////////////////////
static void __exit exit(void)
{
dev_remove_pack(&my_packet_type);
printk(KERN_ALERT "module exit");
}
////////////////////////////////////////////////////////////////////////
module_init(init);
module_exit(exit);
////////////////////////////////////////////////////////////////////////
//CORE//////////////////////////////////////////////////////////////////
int new_hook_func(struct sk_buff *skb, struct device *dv, struct packet_type *pt)
{
struct iphdr *ip;
ip = (struct iphdr*)skb_network_header(skb);
if(skb->pkt_type != PACKET_OUTGOING)
{
if(ip->version == 4 && ip->protocol == IPPROTO_ICMP)
{
struct sk_buff *my_skb = 0;
//copy incoming skb
my_skb = skb_copy_expand(skb, 16, 16, GFP_ATOMIC);
//get eth header
struct ethhdr *eth = eth_hdr(my_skb);
//push ethernet layer to skb
skb_push(my_skb, ETH_HLEN);
//set packet type to outgoing
skb->pkt_type = PACKET_OUTGOING;
//send skb struct
dev_queue_xmit(my_skb);
//drop all incoming packets
// kfree_skb(my_skb);
// kfree_skb(skb);
}
}
return NET_RX_DROP;
}
This code is supposed to resend every icmp packet recieved.
So, I've faced three problems:
1) Memory leak. Some how it leaks. I tried to comment whole hook func and there was only return, but memory was still leaking.
2) Return codes don't work. It's no matter what I return(NET_RX_DROP/NET_RX_ACCEPT/NF_DROP/NF_ACCEPT/1/0) is still recieves packets and answers to it.
3) Problems with mac-layer. As you may see in my code, I copy skb struct with expansion and have to push 14 bytes of mac-layer there. Otherwise packet will be sent without any mac bytes.
I apologize for my poor english and kindly ask for help.

Management of Unix Shared Memory

We know that, shared memory in Windows is implemented via memory mapped files backed by system pagefile, and it is always managed in a reference counted way (http://msdn.microsoft.com/en-us/library/windows/desktop/aa366537(v=vs.85).aspx).
I wonder whether Unix does it in a similar way. Someone (http://stackoverflow.com/q/4278391/939142) says that Unix also manages shm in a reference counted way. I tried the an experiment on Mac OS X, and found that it was not the case.
Using the code supplied in the end, compile two programs: host and client. Type
./host
which creates a shm, writes (int) 10 at its first address, and quits. Then type
./client <shmid>
to examine the shm segment, which attaches to the shm created, prints the first int, and quits.
Note that we used shmat and shmdt to connect to / disconnect from the shm, and shmget to create the shm.
To destroy the shm, we have to do it manually using shmctl.
Conclusion:
shm is not managed as reference counting in Unix, at least for Mac OS X
/************************** host.c ****************************/
#include <stdio.h>
#include <sys/shm.h>
#include <mach/vm_param.h>
#include <assert.h>
int
main(int argc, char** argv)
{
int value = 10;
int id;
void* ptr;
/* create a new shm */
id = shmget(IPC_PRIVATE, PAGE_SIZE, IPC_CREAT | 0666);
assert(id != -1);
/* attach to the new shm */
ptr = shmat(id, (const void*) NULL, 0);
assert((int*) ptr != -1);
/* print the id so that client can use */
printf("shm id = %ld\n", id);
printf("address of id = %ld, length = %ld\n", ptr, PAGE_SIZE);
((int*) ptr)[0] = value;
printf("value at address %ld = %ld\n", ptr, *(int*) ptr);
/* detach from the shm and exit */
shmdt((const void*) ptr);
return 0;
}
/************************** host.c ****************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include "assert.h"
#include <mach/vm_param.h>
int
main(int argc, char** argv)
{
void* ptr;
int id = atoi(argv[1]);
assert(id != -1);
/* attach to the shm */
ptr = shmat(id, NULL, 0);
assert(ptr != -1);
printf("value at ptr = %ld = %ld\n", ptr, *(int*) ptr);
shmdt((const void*) ptr);
return 0;
}
It not pure reference counting. According to shmctl(2):
IPC_RMID: Mark the segment to be destroyed. The segment will only
actually be destroyed after the last process detaches it
(i.e., when the shm_nattch member of the associated structure
shmid_ds is zero). The caller must be the owner or creator,
This means: IPC_RMID will not delete immediately but only after the reference count drops to zero the next time.
This allows you to achieve several goals with the same tool:
Either a server/client approach where the server creates, attaches and immediately sets RMID. Then clients can connect as long as the server is here. If the server goes down, the clients should disconect and the resource is cleaned up by the OS.
Or the "message" approach: Someone writes a message, pins it to a known location. After that someone else can come, look for a message and act accordingly. This is what you have done. This approach is more open to resource garbage of course. But there are usecases for this.

Resources