I'm trying to send some data from inside an iptables target to userspace via netlink. The code below results in the kernel crashing, without generating an oops.
Sometimes it would crash immediately, and sometimes after running for a while. It doesn't seem to matter whether there is a userspace application listening on the socket or not.
This has occurred on a 2.6.15 and 2.6.19 kernel. It is compiled with SMP, but was running on a uniprocessor system.
The problem appeared to be related to the netlink_unicast() call, since commenting it out (and replacing it with a nlmsg_free()) stops the kernel from crashing.
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <net/ip.h>
#include <net/tcp.h>
#include <net/netlink.h>
...
static unsigned int monitor_target(
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const struct xt_target *target,
const void* targinfo)
{
static int seq = 0;
struct sk_buff *skb = *pskb;
struct sk_buff *nl_skb = NULL;
void *nl_head = NULL;
int ret_val = 0;
int msg_len = 0;
char *data = NULL;
struct monitor_hdr hdr;
if (skb)
{
msg_len = sizeof(struct monitor_hdr) + ntohs(skb->nh.iph->tot_len);
/* create the buffer */
if ((nl_skb = alloc_skb(nlmsg_total_size(msg_len), GFP_ATOMIC)) == NULL)
return IPT_CONTINUE;
/* create the netlink headers */
if ((nl_head = nlmsg_put(nl_skb, MONITOR_PID, seq++, 0, msg_len, 0)) == NULL)
goto target_netlink_failure;
data = nlmsg_data(nl_head);
/* add monitor header data */
hdr.eth_in = (skb->nf_bridge && skb->nf_bridge->physindev ?
skb->nf_bridge->physindev->ifindex : 0);
hdr.eth_out = (skb->nf_bridge && skb->nf_bridge->physoutdev ?
skb->nf_bridge->physoutdev->ifindex : 0);
hdr.nfmark = skb->nfmark;
memcpy(data, &hdr, sizeof(struct monitor_hdr));
data += sizeof(struct monitor_hdr);
/* add ip packet */
memcpy(data, skb->nh.iph, ntohs(skb->nh.iph->tot_len));
data += ntohs(skb->nh.iph->tot_len);
/* finalize the message */
nlmsg_end(nl_skb, nl_head);
/* send the message */
if ((ret_val = nlmsg_unicast(monitor_sock, nl_skb, PID)) != 0);
goto target_netlink_failure;
}
return IPT_CONTINUE;
target_netlink_failure:
nlmsg_free(nl_skb);
printk(KERN_ERR "Failed to send packet to monitor\n");
return IPT_CONTINUE;
}
...Any help would be appreciated. Thank you.