I have a client process that builds an IPC message struct queue_msg that is being sent to a server via the linux IPC msg queue. 68 bytes in size. struct is defined as:
struct FOO_TYPE {
long mtype;
struct {
int sev;
char msg[32];
char bt[32];
} foomsg;
};
the client declares a pointer to the a struct of FOO_TYPE locally in the function and mallocs space for it. the code then loads the sev, msg and bt fields.
static struct FOO_TYPE *FooEntry = NULL;
...code clipped
if (FooEntry == NULL)
FooEntry = malloc(sizeof(struct FOO_TYPE));
memset(FooEntry, 0, sizeof(struct FOO_TYPE));
...code clipped
MsgSize = sizeof(FooEntry) - sizeof(long);
FooEntry->mtype = CHANGESTATUS;
FooEntry->foomsg.sev = serr->serr_data->sev;
strcpy(FooEntry->syserrmsg.emsg, elog);
strcpy(FooEntry->syserrmsg.bt, btlog);
... code clipped
result = msg_snd(FooExchange, FooEntry, MsgSize, IPC_WAIT);
the server receiving the IPC msg is getting 68 bytes (ie: sizeof FOO_TYPE), however intermittently, the fields inside are either missing or garbage.
do I have to malloc space for the fields in the struct inside the structure as well??
This is at least one bug:
MsgSize = sizeof(FooEntry) - sizeof(long);
FooEntry is a pointer defined here:
static struct FOO_TYPE *FooEntry = NULL;
so sizeof(FooEntry) gives you the size of a pointer - not the size of a struct.
You probably want
MsgSize = sizeof(*FooEntry) - sizeof(long);
or perhaps just
MsgSize = sizeof(FooEntry->foomsg);
I am trying to read sk_buff->network_header but when I try to read my computer get froze and never gets unfreez. Why is that happening. This is my code in poll of napi api
In probe function
netif_napi_add(netdev, &adapter->napi, e1000e_poll, 64);
static int e1000e_poll(struct napi_struct *napi, int budget)
{
struct sk_buff *skb=napi->skb;
// (struct iphdr *)skb_network_header(&napi->skb);
struct iphdr *ip_header = (struct iphdr *)skb->network_header;
struct udphdr *udp_header;
struct tcphdr *tcp_header;
struct list_head *p;
//unsigned int src_ip = (unsigned int)ip_header->saddr;
}
I simply dont want to assign just about anything to something similar. I had check types when assigning plus prinkk not the solution since it does not have formats that covers all types
I'm trying to send a struct from user-space to my module in kernel space using netlink, my struct in the user-space is:
struct test{
unsigned int length;
char name[MAX_NAME_LENGTH];
};
and in the kernel space is:
struct test{
__u32 length;
char name[MAX_NAME_LENGTH];
};
where MAX_NAME_LENGTH is a macro defined to be equal 50.
In the user-space, I've the function main which send my struct to the kernel with the following code:
int main(){
struct iovec iov[2];
int sock_fd;
struct sockaddr_nl src_add;
struct sockaddr_nl dest_add;
struct nlmsghdr * nl_hdr = NULL;
struct msghdr msg;
struct test message;
memset(&message, 0, sizeof(struct test));
message.length = 18;
strcpy(message.name, "Just a test\0");
sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
if (sock_fd < 0){
printf("Netlink socket creation failed\n");
return -1;
}
memset(&src_add, 0, sizeof(src_add));
src_add.nl_family = AF_NETLINK;
src_add.nl_pid = getpid();
memset(&dest_add, 0, sizeof(dest_add));
dest_add.nl_family = AF_NETLINK;
dest_add.nl_pid = 0; // Send to linux kernel
dest_add.nl_groups = 0; // Unicast
bind(sock_fd,(struct sockaddr *)&src_add,sizeof(src_add));
nl_hdr = (struct nlmsghdr *) malloc(NLMSG_SPACE(sizeof(struct test)));
memset(nl_hdr, 0, NLMSG_SPACE(sizeof (struct test)));
nl_hdr->nlmsg_len = NLMSG_SPACE(sizeof(struct test));
nl_hdr->nlmsg_pid = getpid();
nl_hdr->nlmsg_flags = 0;
iov[0].iov_base = (void *)nl_hdr;
iov[0].iov_len = nl_hdr->nlmsg_len;
iov[1].iov_base = &message;
iov[1].iov_len = sizeof(struct test);
memset(&msg,0, sizeof(msg));
msg.msg_name = (void *)&dest_add;
msg.msg_namelen = sizeof(dest_add);
msg.msg_iov = &iov[0];
msg.msg_iovlen = 2;
sendmsg(sock_fd,&msg,0);
close(sock_fd);
return 0;
}
And in the kernel side I've registered a function called callback to be called every time that a message is received, this is the callback function:
static void callback(struct sk_buff *skb){
struct nlmsghdr *nl_hdr;
struct test * msg_rcv;
nl_hdr = (struct nlmsghdr*)skb->data;
msg_rcv = (struct test*) nlmsg_data(nl_hdr);
printk(KERN_INFO "Priting the length and name in the struct:%u, %s\n",msg_rcv->length, msg_rcv->name);
}
When I run these codes and see the dmesg output I receive the following message: Priting the length and name in the struct:0,, so why the fields of the struct filled in the user-space side aren't being sent to the kernel?
Btw, NETLINK_USER is defined as 31.
DON'T DO THAT. YOUR CODE HAS BUGS BY DESIGN.
I'm going to first explain the one superfluous issue that prevents your code from doing what you want, then explain why what you want is a bad idea, then explain the right solution.
1. Doing what you want
You "want" to send a packet consisting of a netlink header followed by a struct. In other words, this:
+-----------------+-------------+
| struct nlmsghdr | struct test |
| (16 bytes) | (54 bytes) |
+-----------------+-------------+
The problem is that's not what you're telling your iovec. According to your iovec code, the packet looks like this:
+-----------------+--------------+-------------+
| struct nlmsghdr | struct test | struct test |
| (16 bytes) | (54 bytes) | (54 bytes) |
| (data) | (all zeroes) | (data) |
+-----------------+--------------+-------------+
This line:
iov[0].iov_len = nl_hdr->nlmsg_len;
Should be this:
iov[0].iov_len = NLMSG_HDRLEN;
Because your first iovec slot is just the Netlink header; not the whole packet.
2. Why what you want is bad
C has a gotcha called "data structure padding." Don't skip this lecture; I'd argue that anyone who deals with the C language MUST read it ASAP: http://www.catb.org/esr/structure-packing/
The gist of it is that C compilers are allowed to introduce garbage between the members of any structure. Thus, when you declare this:
struct test {
unsigned int length;
char name[MAX_NAME_LENGTH];
};
The compiler is technically allowed to mutate that during implementation into something like
struct test {
unsigned int length;
unsigned char garbage[4];
char name[MAX_NAME_LENGTH];
};
See the problem? If your kernel module and your userspace client were generated by different compilers, or by the same compiler but with slightly different flags, or even by slightly different versions of the same compiler, the structures might differ and the kernel will receive garbage, no matter how correct your code looks.
Update: Someone asked me to elaborate on that, so here it goes:
Suppose you have the following structure:
struct example {
__u8 value8;
__u16 value16;
};
In userspace, the compiler decides to leave it as is. However, in kernelspace the compiler "randomly" decides to convert it to:
struct example {
__u8 value8;
__u8 garbage;
__u16 value16;
};
In your userspace client, you then write this code:
struct example x;
x.value8 = 0x01;
x.value16 = 0x0203;
In memory, the structure will look like this:
01 <- value8
02 <- First byte of value16
03 <- Second byte of value16
When you send that to the kernel, the kernel will, of course, receive the same thing:
01
02
03
But it will interpret it differently:
01 <- value8
02 <- garbage
03 <- First byte of value16
junk <- Second byte of value16
(End of Update)
In your case the problem is aggravated by the fact that you define test.length as unsigned int in userspace, yet for some reason you change it into __u32 in kernelspace. Your code is problematic even before structure padding; if your userspace defines basic integers as 64-bit, the bug will also inevitably trigger.
And there's another problem: "Btw, NETLINK_USER is defined as 31" tells me you're following tutorials or code samples long obsolete or written by people who don't know what they are doing. Do you know where that 31 comes from? It's the identifier of your "Netlink family." They define it as 31 because that's the highest possible value it can have (0-31), and therefore, it's the most unlikely one to collide with other Netlink families defined by the kernel. (Because they are numbered monotonically.) But most careless Netlink users are following the tutorials, and therefore most of their Netlink families identify as 31. Therefore, your kernel module will be unable to coexist with any of them. netlink_kernel_create() will kick you out because 31 is already claimed.
And you might be wondering, "well shit. There are only 32 available slots, 23 of them are already taken by the kernel and there's an unknown but likely large number of additional people wanting to register different Netlink families. What do I do?!"
3. The proper way
It's 2020. We don't use Netlink anymore. We use better-Netlink: Generic Netlink.
Generic Netlink uses strings and dynamic integers as family identifiers, and drives you to use Netlink's "attribute" framework by default. (The latter encourages you to serialize and deserialize structures in a portable way, which is the real solution to your original problem.)
This code needs to be visible to both your userspace client and kernel module:
#define SAMPLE_FAMILY "Sample Family"
enum sample_operations {
SO_TEST, /* from your "struct test" */
/* List more here for different request types. */
};
enum sample_attribute_ids {
/* Numbering must start from 1 */
SAI_LENGTH = 1, /* From your test.length */
SAI_NAME, /* From your test.name */
/* This is a special one; don't list any more after this. */
SAI_COUNT,
#define SAI_MAX (SAI_COUNT - 1)
};
This is the kernel module:
#include <linux/module.h>
#include <linux/version.h>
#include <net/genetlink.h>
#include "../include/protocol.h"
/*
* A "policy" is a bunch of rules. The kernel will validate the request's fields
* match these data types (and other defined constraints) for us.
*/
struct nla_policy const sample_policy[SAI_COUNT] = {
[SAI_LENGTH] = { .type = NLA_U32 },
[SAI_NAME] = { .type = NLA_STRING },
};
/*
* This is the function the kernel calls whenever the client sends SO_TEST
* requests.
*/
static int handle_test_operation(struct sk_buff *skb, struct genl_info *info)
{
if (!info->attrs[SAI_LENGTH]) {
pr_err("Invalid request: Missing length attribute.\n");
return -EINVAL;
}
if (!info->attrs[SAI_NAME]) {
pr_err("Invalid request: Missing name attribute.\n");
return -EINVAL;
}
pr_info("Printing the length and name: %u, '%s'\n",
nla_get_u32(info->attrs[SAI_LENGTH]),
(unsigned char *)nla_data(info->attrs[SAI_NAME]));
return 0;
}
static const struct genl_ops ops[] = {
/*
* This is what tells the kernel to use the function above whenever
* userspace sends SO_TEST requests.
* Add more array entries if you define more sample_operations.
*/
{
.cmd = SO_TEST,
.doit = handle_test_operation,
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0)
/* Before kernel 5.2, each op had its own policy. */
.policy = sample_policy,
#endif
},
};
/* Descriptor of our Generic Netlink family */
static struct genl_family sample_family = {
.name = SAMPLE_FAMILY,
.version = 1,
.maxattr = SAI_MAX,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)
/* Since kernel 5.2, the policy is family-wide. */
.policy = sample_policy,
#endif
.module = THIS_MODULE,
.ops = ops,
.n_ops = ARRAY_SIZE(ops),
};
/* Called by the kernel when the kernel module is inserted */
static int test_init(void)
{
return genl_register_family(&sample_family);
}
/* Called by the kernel when the kernel module is removed */
static void test_exit(void)
{
genl_unregister_family(&sample_family);
}
module_init(test_init);
module_exit(test_exit);
And here's the userspace client (You need to install libnl-genl-3 --sudo apt install libnl-genl-3-dev on Debian/Ubuntu):
#include <errno.h>
#include <netlink/genl/ctrl.h>
#include <netlink/genl/genl.h>
#include "../include/protocol.h"
static struct nl_sock *sk;
static int genl_family;
static void prepare_socket(void)
{
sk = nl_socket_alloc();
genl_connect(sk);
genl_family = genl_ctrl_resolve(sk, SAMPLE_FAMILY);
}
static struct nl_msg *prepare_message(void)
{
struct nl_msg *msg;
msg = nlmsg_alloc();
genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, genl_family, 0, 0, SO_TEST, 1);
/*
* The nla_put* functions ensure that your data will be stored in a
* portable way.
*/
nla_put_u32(msg, SAI_LENGTH, 18);
nla_put_string(msg, SAI_NAME, "Just a test");
return msg;
}
int main(int argc, char **argv)
{
struct nl_msg *msg;
prepare_socket();
msg = prepare_message();
nl_send_auto(sk, msg); /* Send message */
nlmsg_free(msg);
nl_socket_free(sk);
return 0;
}
This code should work starting from kernel 4.10. (I tested it in 4.15.) The kernel API was somewhat different before that.
I left a pocket version of my test environment (with makefiles and proper error handling and everything) in my Dropbox, so you can run it easily.
I am writing a small analysis tool using libpcap that sniffs traffic on an ethernet device and performs some sort of analysis on the received packets. In order to do so, I have the obvious libpcap loop:
void packet_loop(u_char *args, const struct pcap_pkthdr *header,
const u_char *packetdata) {
int size = (int)header->len;
//Before we map the buffer to the ethhdr struct,
//we check if the size fits
if (ETHER_HDR_LEN > size)
return;
const struct ethhdr *ethh = (const struct ethhdr *)(packetdata);
//If this protocol is IPv4 and the packet size is bigger than
//ETH hdr size
if (ETHERTYPE_IP == ntohs(ethh->h_proto)) {
//Before we map the buffer to the iph struct,
//we check if the size fits
if (ETHER_HDR_LEN + (int)sizeof(struct iphdr) > size)
return;
const struct iphdr *iph = (const struct iphdr*)
(packetdata + sizeof(struct ethhdr));
//If this protocol isn't UDP and the header length
//isn't 5 (20bytes)
if (IPPROTO_UDP != iph->protocol && 5 != iph->ihl)
return;
//eval_udp(packetdata, size);
const struct udphdr *udph = (const struct udphdr*)
(packetdata + sizeof(struct ethhdr) +
sizeof(struct iphdr));
if (DATA_SRCPORT == ntohs(udph->uh_sport) &&
DATA_DESTPORT == ntohs(udph->uh_dport)) {
analyse_data(packetdata);
}
}
}
that calls the follwoing code snipped on receival of a specific packet type. As you can see, I am using a static variable to keep track of the previous packet, in order to compare two.
void analyse_data(const uint8_t *packet)
{
if (!packet)
return;
static const uint8_t *basepacket;
//If there was no packet to base our analysis on, we will wait for one
if (!basepacket) {
basepacket = packet;
return;
}
const struct dataheader *basedh = (const struct dataheader *)
(__OFFSETSHERE__ + basepacket);
const struct dataheader *dh = (const struct dataheader *)
(__OFFSETSHERE__ + packet);
printf("%d -> %d\n", ntohs(basedh->sequenceid),
ntohs(dh->sequenceid));
basepacket = packet;
return;
}
struct dataheader is a regular struct, just like etthdr. I would expect a constant printout like:
0 -> 1
1 -> 2
2 -> 3
Unfortunately, I get a different printout, which is mostly right. But around every 20th-40th packet, I see the following behavior (example):
12->13
13->14
0->15
15->16
...
It is maybe interesting to note that this does NOT occcur, when I receive only packets of the specific type I look after (8-10 Mbit/s). Nevertheless, as soon as I use my tool in the "regular" network environment (around 100Mbit/s), I get this behavior. I checked my if statement, that filters the packet it works flawlessly (checking UDP source and destination ports). Wireshark also shows me that there is not a single packet on those ports that is not of that specific type.
libpcap controls the packet data it passes in to your packet_loop. Once packet_loop returns, you have no guarantee what the pointers for the packet data point to - libpcap could throw the packet away, or it could reuse the same space for a new packet.
This means if you want to compare 2 packets, you must make a copy of the 1. packet - you cannot save the pointer from one call to packet_loop and expect that pointer to be valid and point to the same packet in future calls to packet_loop. So your code could be changed to e.g.
void analyse_data(const uint8_t *packet, int size )
{
if (!packet)
return;
static const uint8_t basepacket[1024*64];
static int has_basepacket;
//If there was no packet to base our analysis on, we will wait for one
if (!has_basepacket){
if (size < sizeof basepacket) {
memcpy(basepacket, packet, size);
has_basepacket = 1;
}
return;
}
...
Also, make sure your verify the sizes everywhere. Just because the ethernet type says it is an IPv4 packet, doesn't mean you can trust it to contain a full IP packet. Just because the IP header says it is 20 bytes, doesn't mean you can trust it to contain a full IP packet, and so on for all the layers you attempt to decode.
I'm having problems with a client-server communication made with writev()/readv().
I have two struct, header and data defined like this:
typedef struct {
int op;
int key;
} message_hdr_t;
typedef struct {
int len;
char *data;
} message_data_t;
The server does (in short):
message_hdr_t h = {1, 11};
message_data_t d;
d.len = 3;
strcpy(d.data, "msg");
struct iovec tosend[2];
tosend[0].iov_base = &h;
tosend[0].iov_len = sizeof(message_hdr_t);
tosend[1].iov_base = &d;
tosend[1].iov_len = sizeof(message_data_t);
writev(socket, tosend, 2);
close(socket);
The client (in short):
struct iovec received[2];
readv(socket, received, 2);
message_hdr_t header;
header.op = ((message_hdr_t *) received[0].iov_base)->op;
header.key = ((message_hdr_t *) received[0].iov_base)->key;
printf("Received op: %i, key: %i\n",header.op,header.key;
close(socket);
But the client gets a segfault because received[0].iov_base is NULL. Why?
The socket is correctly opened and the client is correctly connected to the server. It's an AF_UNIX socket.
First, in your server code, you are writing a pointer. This makes no sense. You don't want to transmit pointers over the wire. To transmit a string, you have to do something like this:
char* message = ...;
message_hdr_t h = {1, 11};
uint32_t message_length = strlen(message);
struct iovec tosend[3];
tosend[0].iov_base = &h;
tosend[0].iov_len = sizeof(message_hdr_t);
tosend[1].iov_base = &message_length;
tosend[1].iov_len = sizeof(message_length);
tosend[2].iov_base = message;
tosend[2].iov_len = message_length;
(You may want to move the string length to the message header and save one element of the vector, and make the protocol more readable).
Second, readv won't allocate memory for you, or divine out how many bytes you want to read. It's your job to correctly initialize iov_base and iov_len in the IO vector passed to readv. In order to read a dynamically-allocated variable-size string, you probably want to read twice. First, read a part of the message that contains the length of the string, then allocate the string, and read the rest of the message.