How to send a UDP packet from inside linux kernel - linux

I'm modifying the UDP protocol such that when connect() is called on a UDP socket, in addition to finding the route, a "Hello" packet is also sent to the destination.
From the UDP proto structure, I figured out that the function ip4_datagram_connect does the job of finding the route to the destination. Now at the end of this function, I need to send the Hello packet.
I don't think I can use udp_sendmsg() as it's used for copying and sending data from the userspace.
I think udp_send_skb() should be used to sent the hello. My problem is I don't know how to create an appropriate skbuff to store the Hello message (it should be a proper udp datagram) to be passed on to udp_send_skb(). I've tried this
int quic_connect(struct sock *sk, struct flowi4 *fl4, struct rtable *rt){
struct sk_buff *skb;
char *hello;
int err = 0, exthdrlen, hh_len, datalen, trailerlen;
char *data;
hh_len = LL_RESERVED_SPACE(rt->dst.dev);
exthdrlen = rt->dst.header_len;
trailerlen = rt->dst.trailer_len;
datalen = 200;
//Create a buffer to be send without fragmentation
skb = sock_alloc_send_skb(sk,
exthdrlen + datalen + hh_len + trailerlen + 15,
MSG_DONTWAIT, &err);
if (skb == NULL)
goto out;
skb->ip_summed = CHECKSUM_PARTIAL; // Use hardware checksum
skb->csum = 0;
skb_reserve(skb, hh_len);
skb_shinfo(skb)->tx_flags = 1; //Time stamp the packet
/*
* Find where to start putting bytes.
*/
data = skb_put(skb, datalen + exthdrlen);
skb_set_network_header(skb, exthdrlen);
skb->transport_header = (skb->network_header +
sizeof(struct iphdr));
err = udp_send_skb(skb, fl4);
However, this gives me errors in the kernel log
BUG: unable to handle kernel NULL pointer dereference at 0000000000000018
IP: [<ffffffff81686555>] __ip_local_out+0x45/0x80
PGD 4f4dd067 PUD 4f4df067 PMD 0
Oops: 0000 [#1] SMP
Modules linked in:
CPU: 0 PID: 3019 Comm: client Not tainted 3.13.11-ckt39-test006 #28
Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
task: ffff8800598df6b0 ti: ffff880047022000 task.ti: ffff880047022000
RIP: 0010:[<ffffffff81686555>] [<ffffffff81686555>] __ip_local_out+0x45/0x80
RSP: 0018:ffff880047023d78 EFLAGS: 00010287
RAX: 0000000000000001 RBX: ffff880047008a00 RCX: 0000000020000000
RDX: 0000000000000000 RSI: ffff880047008a00 RDI: ffff8800666fde40
RBP: ffff880047023d88 R08: 0000000000003200 R09: 0000000000000001
R10: 0000000000000000 R11: 00000000000001f9 R12: ffff880047008a00
R13: ffff8800666fde80 R14: ffff880059aec380 R15: ffff880059aec690
FS: 00007f5508b04740(0000) GS:ffff88007fc00000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
CR2: 0000000000000018 CR3: 000000004f561000 CR4: 00000000000406f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Stack:
ffff880047023d80 ffff880047008a00 ffff880047023da0 ffffffff8168659d
ffffffff81c8f8c0 ffff880047023db8 ffffffff81687810 0000000000000000
ffff880047023df8 ffffffff816ac6be 0000000000000020 ffff880047008a00
Call Trace:
[<ffffffff8168659d>] ip_local_out+0xd/0x30
[<ffffffff81687810>] ip_send_skb+0x10/0x40
[<ffffffff816ac6be>] udp_send_skb+0x14e/0x3d0
[<ffffffff816b0e9e>] quic_connect+0x6e/0x80
[<ffffffff816aa3ff>] __ip4_datagram_connect+0x2bf/0x2d0
[<ffffffff816aa437>] ip4_datagram_connect+0x27/0x40
[<ffffffff816b8748>] inet_dgram_connect+0x38/0x80
[<ffffffff8161fd97>] SYSC_connect+0xc7/0x100
[<ffffffff817ed471>] ? __schedule+0x341/0x8c0
[<ffffffff816206e9>] SyS_connect+0x9/0x10
[<ffffffff817f8d42>] system_call_fastpath+0x16/0x1b
Code: c8 00 00 00 66 c1 c0 08 66 89 47 02 e8 d5 e0 ff ff 48 8b 53 58 b8 01 00 00 00 48 83 e2 fe 48 81 3d 9d 0e 64 00 f0 73 cc 81 74 26 <4c> 8b 42 18 49 c7 c1 f0 45 68 81 c7 04 24 00 00 00 80 31 c9 48
RIP [<ffffffff81686555>] __ip_local_out+0x45/0x80
RSP <ffff880047023d78>
CR2: 0000000000000018
---[ end trace 474c5db1b9b19a03 ]---
So my question is, what else do I need to fill in my skbuff before it can be handled properly by udp_send_skb. Or am I missing something else here?

There is a bug in your code.
if (skb_tailroom(hbuff) > 30) {
printk(" Enough room for QUIC connect message\n");
hello = kmalloc(30, GFP_ATOMIC); //You allocate slub memory
hello = "Hello from QUIC connect"; //You let 'hello' point to a string,
//which is stored somewhere else.
//At this point, your slub memory
//allocated is lost.
memcpy(__skb_put(hbuff, 30), hello, 30);
kfree(hello); //You try to free the memory pointed by
//hello as slub memory, I think this is
// why you get mm/slub.c bug message.
} else
You can change your code like this:
if (skb_tailroom(hbuff) > 30) {
printk(" Enough room for QUIC connect message\n");
memcpy(__skb_put(hbuff, 30), "Hello from QUIC connect", 30);
} else

I just used the functions ip_make_skb followed by ip_send_skb. Since ip_make_skb is used to copy data from user space and I didn't need to do that, I just used a dummy pointer and provided the length to be copied as Zero (+sizeof udphdr, as required by this function). It's a dirty way to do it, but it works for now.
My code:
int quic_connect(struct sock *sk, struct flowi4 *fl4, struct rtable *rt, int oif){
struct sk_buff *skb;
struct ipcm_cookie ipc;
void *hello = "Hello";
int err = 0;
ipc.opt = NULL;
ipc.tx_flags = 1;
ipc.ttl = 0;
ipc.tos = -1;
ipc.oif = oif;
ipc.addr = fl4->daddr;
skb = ip_make_skb(sk, fl4, ip_generic_getfrag, hello, sizeof(struct udphdr),
sizeof(struct udphdr), &ipc, &rt,
0);
err = PTR_ERR(skb);
if (!IS_ERR_OR_NULL(skb)){
err = udp_send_skb(skb, fl4);
}
return err;
}

Related

BPF verifier rejects code: "invalid bpf_context access"

I'm trying to write a simple socket filter eBPF program that can access the socket buffer data.
#include <linux/bpf.h>
#include <linux/if_ether.h>
#define SEC(NAME) __attribute__((section(NAME), used))
SEC("socket_filter")
int myprog(struct __sk_buff *skb) {
void *data = (void *)(long)skb->data;
void *data_end = (void *)(long)skb->data_end;
struct ethhdr *eth = data;
if ((void*)eth + sizeof(*eth) > data_end)
return 0;
return 1;
}
And I'm compiling using clang:
clang -I./ -I/usr/include/x86_64-linux-gnu/asm \
-I/usr/include/x86_64-linux-gnu/ -O2 -target bpf -c test.c -o test.elf
However when I try to load the program I get the following verifier error:
invalid bpf_context access off=80 size=4
My understanding of this error is that it should be thrown when you try to access context data that hasn't been checked to be within data_end, however my code does do that:
Here is the instructions for my program
0000000000000000 packet_counter:
0: 61 12 50 00 00 00 00 00 r2 = *(u32 *)(r1 + 80)
1: 61 11 4c 00 00 00 00 00 r1 = *(u32 *)(r1 + 76)
2: 07 01 00 00 0e 00 00 00 r1 += 14
3: b7 00 00 00 01 00 00 00 r0 = 1
4: 3d 12 01 00 00 00 00 00 if r2 >= r1 goto +1 <LBB0_2>
5: b7 00 00 00 00 00 00 00 r0 = 0
which would imply that the error is being caused by reading the pointer to data_end? However it only happens if I don't try to check the bounds later.
This is because your BPF program is a “socket filter”, and that such programs are not allowed to do direct packet access (see sk_filter_is_valid_access(), where we return false on trying to read skb->data or skb->data_end for example). I do not know the specific reason why it is not available, although I suspect this would be a security precaution as socket filter programs may be available to unprivileged users.
Your program loads just fine as a TC classifier, for example (bpftool prog load foo.o /sys/fs/bpf/foo type classifier -- By the way thanks for the standalone working reproducer, much appreciated!).
If you want to access data for a socket filter, you can still use the bpf_skb_load_bytes() (or bpf_skb_store_bytes()) helper, which automatically does the check on length. Something like this:
#include <linux/bpf.h>
#define SEC(NAME) __attribute__((section(NAME), used))
static void *(*bpf_skb_load_bytes)(const struct __sk_buff *, __u32,
void *, __u32) =
(void *) BPF_FUNC_skb_load_bytes;
SEC("socket_filter")
int myprog(struct __sk_buff *skb)
{
__u32 foo;
if (bpf_skb_load_bytes(skb, 0, &foo, sizeof(foo)))
return 0;
if (foo == 3)
return 0;
return 1;
}
Regarding your last comment:
However it only happens if I don't try to check the bounds later.
I suspect clang compiles out the assignments for data and data_end if you do not use them in your code, so they are no longer present and no longer a problem for the verifier.

Why hrtimer causing a deadlock of soft interrupt?

I want to use hrtimer, but the module can't work. the source codes is:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/hrtimer.h>
#define US_TO_NS(usec) ((usec) * 1000)
#define MS_TO_US(msec) ((msec) * 1000)
#define MS_TO_NS(msec) ((msec) * 1000 * 1000)
DEFINE_PER_CPU(struct hrtimer, send_hr_timer);
enum hrtimer_restart hrtimer_send_skb(struct hrtimer *timer)
{
ktime_t ktime;
int cpu;
unsigned long delay_in_ms = 10000L; //unsigned long delay_in_us = 5000L;
ktime = ktime_set(0, MS_TO_NS(delay_in_ms));
//ktime = ktime_set(0, US_TO_NS(delay_in_us));
cpu = get_cpu(); printk(KERN_INFO "hrtimer is on:%d", cpu);
hrtimer_forward(&per_cpu(send_hr_timer, cpu), ktime_get(), ktime);
put_cpu();
return HRTIMER_RESTART;
//return HRTIMER_NORESTART;
}
void init_hr_timer(void)
{
ktime_t ktime;
int cpu;
unsigned long delay_in_ms = 100L;
ktime = ktime_set(0, MS_TO_NS(delay_in_ms));
for_each_online_cpu(cpu) {
hrtimer_init(&per_cpu(send_hr_timer, cpu), CLOCK_MONOTONIC, HRTIMER_MODE_REL);
per_cpu(send_hr_timer, cpu).function = &hrtimer_send_skb;
hrtimer_start(&per_cpu(send_hr_timer, cpu), ktime, HRTIMER_MODE_REL);
}
}
void del_hr_timer(void)
{
int cpu;
for_each_online_cpu(cpu) {
/* del hrtimer. */
hrtimer_cancel(&per_cpu(send_hr_timer, cpu));
}
}
static int minit(void)
{
int rc = 0;
printk("Start %s.\n", THIS_MODULE->name);
init_hr_timer();
return rc;
}
static void mexit(void)
{
printk("Exit %s.\n", THIS_MODULE->name);
del_hr_timer();
}
When I install the module, something is error, the messages is:
BUG: soft lockup - CPU#22 stuck for 67s! [migration/22:92]
Modules linked in: ws_hrtimer(U) wscubic(U) wsfasttcp(U) 8021q garp stp llc autofs4 cpufreq_ondemand acpi_cpufreq freq_table mperf be2iscsi iscsi_boot_sysfs ib_iser rdma_cm ib_cm iw_cm ib_sa ib_mad ib_core ib_addr iscsi_tcp bnx2i cnic uio ipv6 cxgb3i libcxgbi cxgb3 mdio libiscsi_tcp libiscsi scsi_transport_iscsi ext3 jbd dm_mirror dm_multipath video output sbs sbshc power_meter wsrelay(U) wsgetsnd(U) parport sg acpi_pad ses enclosure igb dca sb_edac edac_core i2c_i801 i2c_core pata_acpi ata_generic iTCO_wdt iTCO_vendor_support dm_raid45 dm_memcache xor dm_region_hash dm_log dm_mod usb_storage ata_piix isci libsas shpchp mpt2sas scsi_transport_sas raid_class ext4 mbcache jbd2 [last unloaded: microcode]
CPU 22
Modules linked in: ws_hrtimer(U) wscubic(U) wsfasttcp(U) 8021q garp stp llc autofs4 cpufreq_ondemand acpi_cpufreq freq_table mperf be2iscsi iscsi_boot_sysfs ib_iser rdma_cm ib_cm iw_cm ib_sa ib_mad ib_core ib_addr iscsi_tcp bnx2i cnic uio ipv6 cxgb3i libcxgbi cxgb3 mdio libiscsi_tcp libiscsi scsi_transport_iscsi ext3 jbd dm_mirror dm_multipath video output sbs sbshc power_meter wsrelay(U) wsgetsnd(U) parport sg acpi_pad ses enclosure igb dca sb_edac edac_core i2c_i801 i2c_core pata_acpi ata_generic iTCO_wdt iTCO_vendor_support dm_raid45 dm_memcache xor dm_region_hash dm_log dm_mod usb_storage ata_piix isci libsas shpchp mpt2sas scsi_transport_sas raid_class ext4 mbcache jbd2 [last unloaded: microcode]
Pid: 92, comm: migration/22 Not tainted 2.6.32-358.6.1.ws5.b.5.2.8 #1 Inspur SA5212H2/SA5212H2
RIP: 0010:[<ffffffff810c6709>] [<ffffffff810c6709>] stop_machine_cpu_stop+0x59/0x100
RSP: 0018:ffff880874733de0 EFLAGS: 00000293
RAX: 0000000000000001 RBX: ffff880874733e10 RCX: 0000000000000028
RDX: ffffffff81c059e0 RSI: 0000000000000018 RDI: ffffffff81c059e0
RBP: ffffffff8100ba8e R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000
R13: 0000000000000000 R14: ffff881074f0e040 R15: 0000000000000082
FS: 0000000000000000(0000) GS:ffff88089c540000(0000) knlGS:0000000000000000
CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003b
CR2: 000000373c89ac00 CR3: 0000000001a85000 CR4: 00000000000407e0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Process migration/22 (pid: 92, threadinfo ffff880874732000, task ffff880874731540)
Stack:
0000001674733e00 ffff88089c550840 ffff880874731540 ffffffff810c66b0
<d> ffff8806fa783e68 ffff8806fa783dd8 ffff880874733ee0 ffffffff810c68d5
<d> 0000000000000000 0000002165ed0d57 0000000000000082 ffff880874415ca0
Call Trace:
[<ffffffff810c66b0>] ? stop_machine_cpu_stop+0x0/0x100
[<ffffffff810c68d5>] ? cpu_stopper_thread+0xa5/0x170
[<ffffffff8105a992>] ? default_wake_function+0x12/0x20
[<ffffffff8104e1eb>] ? __wake_up_common+0x5b/0x90
[<ffffffff810c6830>] ? cpu_stopper_thread+0x0/0x170
[<ffffffff810c6830>] ? cpu_stopper_thread+0x0/0x170
[<ffffffff81090ce6>] ? kthread+0x96/0xa0
[<ffffffff8100bfca>] ? child_rip+0xa/0x20
[<ffffffff81090c50>] ? kthread+0x0/0xa0
[<ffffffff8100bfc0>] ? child_rip+0x0/0x20
Code: 18 48 85 c0 0f 84 9b 00 00 00 0f a3 18 19 c0 85 c0 41 0f 95 c6 31 c0 45 31 ff eb 0d 66 0f 1f 44 00 00 83 fb 04 74 3b 89 d8 f3 90 <41> 8b 5c 24 20 39 c3 74 ee 83 fb 02 74 49 83 fb 03 74 54 f0 41
Call Trace:
[<ffffffff810c66b0>] ? stop_machine_cpu_stop+0x0/0x100
[<ffffffff810c68d5>] ? cpu_stopper_thread+0xa5/0x170
[<ffffffff8105a992>] ? default_wake_function+0x12/0x20
[<ffffffff8104e1eb>] ? __wake_up_common+0x5b/0x90
[<ffffffff810c6830>] ? cpu_stopper_thread+0x0/0x170
[<ffffffff810c6830>] ? cpu_stopper_thread+0x0/0x170
[<ffffffff81090ce6>] ? kthread+0x96/0xa0
[<ffffffff8100bfca>] ? child_rip+0xa/0x20
[<ffffffff81090c50>] ? kthread+0x0/0xa0
[<ffffffff8100bfc0>] ? child_rip+0x0/0x20
please help me, thank you.

Why my spi test C code get this result?

At the bottom is the spi test code (spitest.c) I used, and when running it on my linux kit, I got this result:
root#abcd-kit:/system # ./spitest
open device: /dev/spidev0.0
set spi mode: 0
set bits per word: 8
set max speed: 2000000 Hz (2 MHz)
the received data is below:
00 00 00 00 30 30
30 0A 00 00 00 00
00 00 00 00 2F 73
the received data is below:
00 00 00 00 30 30
30 0A 00 00 00 00
00 00 00 00 2F 73
...
dmesg output:
<7>[ 1254.714088] usif-spi e1100000.usif1: Pushing msg a8085ed0
<6>[ 1254.714367] SPI XFER :ae81c700 , Length : 18
<6>[ 1254.714404] TX Buf :a6207000 , TX DMA : (null)
<6>[ 1254.714425] RX Buf :92bf5000 , RX DMA : (null)
<6>[ 1254.714445] CS change:0, bits/w :8, delay : 0 us, speed : 2000000 Hz
<7>[ 1254.714471] TX--->:31 a5 bb 00 00 bb fc 76 80 84 1e 00 5c 29 7d 77
<7>[ 1254.714491] TX--->:44 b9
<7>[ 1254.714511] RX--->:00 00 00 00 30 30 30 0a 00 00 00 00 00 00 00 00
<7>[ 1254.714534] RX--->:2f 73
<7>[ 1254.714558] usif-spi e1100000.usif1: Msg a8085ed0 completed with status 0
<7>[ 1255.725936] usif-spi e1100000.usif1: Pushing msg a8085ed0
<6>[ 1255.726472] SPI XFER :ae81cc40 , Length : 18
<6>[ 1255.726604] TX Buf :a6207000 , TX DMA : (null)
<6>[ 1255.726656] RX Buf :92bf5000 , RX DMA : (null)
<6>[ 1255.726706] CS change:0, bits/w :8, delay : 0 us, speed : 2000000 Hz
<7>[ 1255.726773] TX--->:31 a5 bb 00 00 bb fc 76 94 29 7d 77 5c 29 7d 77
<7>[ 1255.726829] TX--->:44 b9
<7>[ 1255.726875] RX--->:00 00 00 00 30 30 30 0a 00 00 00 00 00 00 00 00
<7>[ 1255.726925] RX--->:2f 73
And the biggest problem is that I cannot get correct result from miso pin (read is wrong, can do write correctly). Whatever I do, e.g. connect miso to ground or 1.8V, it always give this kind of result. The fisrt 5 data are always zero (I think it is because tx buffer has size of 5 and it is half duplex), and then followed random data, even that I used memset() to set rx buffer data to be zero before each spi transfer. And if I stop the program and run it again, the data changed but they are still random.
How could I read correct data from miso pin?
Thanks!
spitest.c
/*
* SPI testing utility (using spidev driver)
*
* Copyright (c) 2007 MontaVista Software, Inc.
* Copyright (c) 2007 Anton Vorontsov <avorontsov#ru.mvista.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* Cross-compile with cross-gcc -I/path/to/cross-kernel/include
*/
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include "spidev.h"
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
static void pabort(const char *s)
{
perror(s);
abort();
}
static const char *device = "/dev/spidev0.0";
static uint8_t mode;
static uint8_t bits = 8;
static uint32_t speed = 2000000;
static uint16_t delay;
#define LENGTH 18
static void transfer(int fd)
{
int ret, i;
uint8_t tx[5] = {0x31, 0xa5, 0xbb};
uint8_t rx[LENGTH] = {0, };
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = LENGTH,
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits, //important, bits = 8 means byte transfer is possible
};
memset(rx, 0, LENGTH);
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
pabort("can't send spi message\n");
printf("the received data is below:\n");
for (ret = 0; ret < LENGTH; ret++) { //print the received data, by Tom Xue
if (!(ret % 6))
puts("");
printf("%.2X ", rx[ret]);
}
puts("");
}
int main(int argc, char *argv[])
{
int ret = 0;
int fd;
unsigned char rd_buf[32];
fd = open(device, O_RDWR);
if (fd < 0)
pabort("can't open device\n");
/*
* * spi mode
* */
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1)
pabort("can't set spi mode\n");
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
if (ret == -1)
pabort("can't get spi mode\n");
/*
* * bits per word
* */
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't set bits per word\n");
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't get bits per word\n");
/*
* * max speed hz
* */
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't set max speed hz\n");
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't get max speed hz\n");
printf("open device: %s\n", device);
printf("set spi mode: %d\n", mode);
printf("set bits per word: %d\n", bits);
printf("set max speed: %d Hz (%d MHz)\n", speed, speed/1000000);
while(1){
transfer(fd);
//read(fd, rd_buf, 4);
//printf("rd_buf = %s, %d, %d, %d, %d\n", rd_buf, rd_buf[0], rd_buf[1], rd_buf[2], rd_buf[3]);
//memset(rd_buf, 0, 10);
sleep(1);
}
close(fd);
return ret;
}
More:
My CPU is Intel Sofia-3gr, I guess its spec is not publicly released. I see the Tx data from my oscilloscope, and confirmed that TX is right.
I can also printk the pinmux/pinctrl setting (use ioremap and ioread32), it is also right. I say it right also because that I can see how to set it as SPI from those dts reference files, I just follow them.
Key:
I just find that the SPI TX interrupt is pending each time a spi transfer starts, but no SPI RX interrupt pending. Hence the spi driver code will not read the RX data at all. As the reason, I don't know.

dispatch queue causing sigabrt after a loop ends

I am getting a strange crash. I am writing data on bluetooth device. when the loop ends the app gets SIGABRT. I am not able to figure out the crash till now. Could someone help me to fix this ?
The app crashes in this function if the loop is called 2 times and it does not crash if it called 1 time.
BOOL success = [strongSelf.CronoDeviceObject.deviceHandler writeSettingsScreenData:data module:strongSelf.CronoDeviceObject.moduleNumber];
#pragma mark Button Save and cancel
- (IBAction)OkTaped:(id)sender{
//for submit
if ([self validateData]) {
[[ProgressHUD defaultHUD] setLoadingText:CVLocalizedString(#"Updating",nil)];
[[ProgressHUD defaultHUD]showInView:self.view];
[self performSelector:#selector(saveAllSettings) withObject:nil afterDelay:1.0];
}
}
- (void)saveAllSettings {
__weak __typeof__(self) weakSelf = self;
dispatch_queue_t queue = dispatch_queue_create("writesettings",NULL);
dispatch_async(queue, ^{
__strong __typeof__(self) strongSelf = weakSelf;
if (strongSelf.CronoDeviceObject) {
[strongSelf.CronoDeviceObject.deviceHandler writeFastWindUp:strongSelf.CronoDeviceObject.moduleNumber];
[strongSelf.CronoDeviceObject.deviceHandler writeLightOnOff:strongSelf.CronoDeviceObject.moduleNumber state:strongSelf.btnCheckBox2.selected?0x01:0x00];
strongSelf.CronoDeviceObject.lightState = (strongSelf.btnCheckBox2.selected)?0:1;
NSLog(#"Button Light is %#",([strongSelf.CronoDeviceObject isEnergySavingMode])?#"ON":#"Off");
NSString* semicolon =[NSString stringWithFormat:#";%#;%#;%#",strongSelf.BrandNametxtfld.text,strongSelf.ModalNametxtfld.text,[NSString stringWithFormat:#"%#;", strongSelf.WatchWinderNametxtfld.text]];
NSMutableData* data = [[NSMutableData alloc] initWithData:[semicolon dataUsingEncoding:NSUTF8StringEncoding]];
if ([strongSelf.CronoDeviceObject.deviceHandler respondsToSelector:#selector(writeSettingsScreenData:module:)]) {
BOOL success = [strongSelf.CronoDeviceObject.deviceHandler writeSettingsScreenData:data module:strongSelf.CronoDeviceObject.moduleNumber];
**//The app does not get here if the above function loop called 2 times but if it called 1 time it's working fine.**
if (success) {
dispatch_async(dispatch_get_main_queue(), ^{
__strong __typeof__(self) strongSelf = weakSelf;
self.CronoDeviceObject.Devicemodal.Brandname = strongSelf.BrandNametxtfld.text;
self.CronoDeviceObject.Devicemodal.modalName = strongSelf.ModalNametxtfld.text;
self.CronoDeviceObject.Devicemodal.winderName = strongSelf.WatchWinderNametxtfld.text;
// Update the UI
[[ProgressHUD defaultHUD]hideActivityIndicator];
[strongSelf.navigationController popViewControllerAnimated:YES];
});
}
}
}
});
}
- (BOOL) writeSettingsScreenData:(NSMutableData*) payload module:(Byte) module {
if (payload == nil) {
return false;
}
int numwrites = 1;
numwrites += (payload.length - 1)/32;
numwrites = (numwrites>8)?8:numwrites;
for(int i = 0; i < numwrites; i++){
//#try {
NSUInteger bufferLength = (payload.length - i*32);
Byte buff[32];
memset(buff, 0, 32);
[payload getBytes:&buff range:NSMakeRange(i*32, bufferLength)];
self.finalString = #"";
//rcvbuff = new StringBuffer(32);
self.chronoVisionMessage = [ChronoVisionMessage new];
//Set Line Address And Dir(R)
// chronoVisionMessage.setLineAddr(ChronoVisionMessage.LINE_BROADCAST);
// chronoVisionMessage.setLineDir(ChronoVisionMessage.LINE_WRITE);
//Set Module (communicnMstr/Address)
[self.chronoVisionMessage setModRsvd:(MODULE_BUSMASTER)];//set to 0
[self.chronoVisionMessage setModCh:(MODULE_BUSMASTER)];//set to default zero
if (module == 0) {
[self.chronoVisionMessage setModAddr:(MODULE_BROADCAST)];
}
else{
[self.chronoVisionMessage setModAddr:module];
}
//Set Register Access(R)/Addresss
[self.chronoVisionMessage setRegRw:REIGSTER_WRITE];
[self.chronoVisionMessage setRegType:REIGSTER_ACCESSTYPE1];//Access standard reg
[self.chronoVisionMessage setRegAddr:REIGSTER_ACCESSTYPE0];//set to 0
//[self.chronoVisionMessage setValueHi:REIGSTER_ACCESSTYPE0];//set to 0
[self.chronoVisionMessage setValueLo:((Byte)i)];//set to 0 to 7
[self.chronoVisionMessage setNewData:[NSMutableData dataWithBytes:buff length:32]];//set to 0
#try {
NSMutableData* header = [self.chronoVisionMessage getMessage];
NSMutableData* final = [[NSMutableData alloc] initWithBytes:[header bytes] length:[header length]];
[final appendBytes:buff length:32];
[self writeData:final];
int retryCount = 0;
while (!self.allDataReceived && retryCount<kTimeout) {
[NSThread sleepForTimeInterval:0.1];
}
//String allData = read(5000);
if(self.finalString.length == 0){
//_peripheral.setListener(null);
return false;
}
if ([self.finalString length] >= 8 && [self.finalString rangeOfString:#"\r"].location > 0) {
self.finalString = [self.finalString substringWithRange:NSMakeRange(0, [self.finalString rangeOfString:#"\r"].location)];
}
NSData *finalData = [self.finalString dataFromHex];
NSLog(#"final readBuff is %#",finalData);
if (i==(numwrites-1) && finalData.length >= 36) {
return true;
}
//free(buff);
}
#catch (NSException *exception) {
NSLog(#"Exception occured when writing user data %#",[exception description]);
}
}
return false;
}
here is an image after the crash
here is the back trace log
bt
* thread #12: tid = 0x13cf99, 0x3611c9aa libsystem_c.dylib`__abort + 102, queue = 'com.apple.root.default-qos', stop reason = EXC_BREAKPOINT (code=EXC_ARM_BREAKPOINT, subcode=0xdefe)
* frame #0: 0x3611c9aa libsystem_c.dylib`__abort + 102
frame #1: 0x3611cf94 libsystem_c.dylib`__stack_chk_fail + 180
frame #2: 0x0007a2d4 Chronovision`-[DeviceHandler writeSettingsScreenData:module:](self=0x17081990, _cmd=0x001069c2, payload=0x00000000, module='\x02') + 3028 at DeviceHandler.m:435
frame #3: 0x000d1f2c Chronovision`__34-[CVDetailViewController OkTaped:]_block_invoke(.block_descriptor=<unavailable>) + 400 at CVDetailViewController.m:357
frame #4: 0x002b219a libdispatch.dylib`_dispatch_call_block_and_release + 10
frame #5: 0x002bcc48 libdispatch.dylib`_dispatch_root_queue_drain + 1596
frame #6: 0x002bde20 libdispatch.dylib`_dispatch_worker_thread3 + 108
frame #7: 0x361fada8 libsystem_pthread.dylib`_pthread_wqthread + 668
(lldb)
Update
I ran the app in xcode 7.1.1 and I got the following log in console when the app crashes.
Dec 7 16:55:09 Rahuls-iPad Chronovision[1650] <Error>: ================================================================
==1650==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x088e06a0 at pc 0x0036f4a9 bp 0x088e02c4 sp 0x088dfe94
WRITE of size 42 at 0x088e06a0 thread T23
#0 0x36f4a7 in wrap_memmove (/private/var/mobile/Containers/Bundle/Application/33337E25-C69D-49F5-ABA1-5AD65673725C/Chronovision.app/Frameworks/libclang_rt.asan_ios_dynamic.dylib+0x2a4a7)
#1 0x287936b3 in <redacted> (/System/Library/Frameworks/Foundation.framework/Foundation+0x236b3)
#2 0x8a971 in -[DeviceHandler writeSettingsScreenData:module:] (/private/var/mobile/Containers/Bundle/Application/33337E25-C69D-49F5-ABA1-5AD65673725C/Chronovision.app/Chronovision+0x2d971)
#3 0x139eaf in __41-[CVDetailViewController saveAllSettings]_block_invoke (/private/var/mobile/Containers/Bundle/Application/33337E25-C69D-49F5-ABA1-5AD65673725C/Chronovision.app/Chronovision+0xdceaf)
#4 0x374e15 in __wrap_dispatch_async_block_invoke (/private/var/mobile/Containers/Bundle/Application/33337E25-C69D-49F5-ABA1-5AD65673725C/Chronovision.app/Frameworks/libclang_rt.asan_ios_dynamic.dylib+0x2fe15)
#5 0x853199 in _dispatch_call_block_and_release (/usr/lib/system/introspection/libdispatch.dylib+0x1199)
#6 0x85bd87 in _dispatch_queue_drain (/usr/lib/system/introspection/libdispatch.dylib+0x9d87)
#7 0x855ac3 in _dispatch_queue_invoke (/usr/lib/system/introspection/libdispatch.dylib+0x3ac3)
#8 0x85db19 in _dispatch_root_queue_drain (/usr/lib/system/introspection/libdispatch.dylib+0xbb19)
#9 0x85ee1f in _dispatch_worker_thread3 (/usr/lib/system/introspection/libdispatch.dylib+0xce1f)
#10 0x361fada7 in _pthread_wqthread (/usr/lib/system/libsystem_pthread.dylib+0xda7)
#11 0x361faafb in start_wqthread (/usr/lib/system/libsystem_pthread.dylib+0xafb)
Address 0x088e06a0 is located in stack of thread T23 at offset 128 in frame
#0 0x8a427 in -[DeviceHandler writeSettingsScreenData:module:] (/private/var/mobile/Containers/Bundle/Application/33337E25-C69D-49F5-ABA1-5AD65673725C/Chronovision.app/Chronovision+0x2d427)
This frame has 12 object(s):
[16, 24) 'r.i1'
[48, 56) 'r.i'
[80, 84) ''
[96, 128) 'buff'
[160, 168) '' <== Memory access at offset 128 partially underflows this variable
[192, 196) 'header'
[208, 212) 'final'
[224, 232) ''
[256, 264) ''
[288, 296) ''
[320, 324) 'finalData'
[336, 340) 'exception'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
(longjmp and C++ exceptions *are* supported)
Thread T23 created by T0 here:
<empty stack>
SUMMARY: AddressSanitizer: stack-buffer-overflow ??:0 wrap_memmove
Shadow bytes around the buggy address:
0x4111c080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x4111c090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x4111c0a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x4111c0b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x4111c0c0: 00 00 00 00 f1 f1 00 f2 f2 f2 00 f2 f2 f2 04 f2
=>0x4111c0d0: 00 00 00 00[f2]f2 f2 f2 00 f2 f2 f2 04 f2 04 f2
0x4111c0e0: 00 f2 f2 f2 00 f2 f2 f2 00 f2 f2 f2 04 f2 04 f3
0x4111c0f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x4111c100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x4111c110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x4111c120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap right redzone: fb
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==1650==ABORTING
I got the problem with xcode 7.1.1.
I don't know why xcode 6.2 was unable to detect the crash location.
The problem was in the range I was using in the function
- (BOOL) writeSettingsScreenData:(NSMutableData*) payload module:(Byte) module {
if (payload == nil) {
return false;
}
int numwrites = 1;
numwrites += (payload.length - 1)/32;
numwrites = (numwrites>8)?8:numwrites;
for(int i = 0; i < numwrites; i++){
//#try {
//Changed this
NSUInteger bufferLength = (payload.length - i*32);
Byte buff[32];
memset(buff, 0, 32);
[payload getBytes:&buff range:NSMakeRange(i*32, bufferLength)];
//To this
NSUInteger bufferLength = ((payload.length - i*32)>32)?32:(payload.length-i*32);
Byte buff[32];
memset(buff, 0, 32);
if (payload && payload.length > bufferLength) {
[payload getBytes:&buff range:NSMakeRange(i*32, bufferLength)];
}
self.finalString = #"";
//rcvbuff = new StringBuffer(32);
self.chronoVisionMessage = [ChronoVisionMessage new];
//Set Line Address And Dir(R)
// chronoVisionMessage.setLineAddr(ChronoVisionMessage.LINE_BROADCAST);
// chronoVisionMessage.setLineDir(ChronoVisionMessage.LINE_WRITE);
//Set Module (communicnMstr/Address)
[self.chronoVisionMessage setModRsvd:(MODULE_BUSMASTER)];//set to 0
[self.chronoVisionMessage setModCh:(MODULE_BUSMASTER)];//set to default zero
if (module == 0) {
[self.chronoVisionMessage setModAddr:(MODULE_BROADCAST)];
}
else{
[self.chronoVisionMessage setModAddr:module];
}
//Set Register Access(R)/Addresss
[self.chronoVisionMessage setRegRw:REIGSTER_WRITE];
[self.chronoVisionMessage setRegType:REIGSTER_ACCESSTYPE1];//Access standard reg
[self.chronoVisionMessage setRegAddr:REIGSTER_ACCESSTYPE0];//set to 0
//[self.chronoVisionMessage setValueHi:REIGSTER_ACCESSTYPE0];//set to 0
[self.chronoVisionMessage setValueLo:((Byte)i)];//set to 0 to 7
[self.chronoVisionMessage setNewData:[NSMutableData dataWithBytes:buff length:32]];//set to 0
#try {
NSMutableData* header = [self.chronoVisionMessage getMessage];
NSMutableData* final = [[NSMutableData alloc] initWithBytes:[header bytes] length:[header length]];
[final appendBytes:buff length:32];
[self writeData:final];
int retryCount = 0;
while (!self.allDataReceived && retryCount<kTimeout) {
[NSThread sleepForTimeInterval:0.1];
}
//String allData = read(5000);
if(self.finalString.length == 0){
//_peripheral.setListener(null);
return false;
}
if ([self.finalString length] >= 8 && [self.finalString rangeOfString:#"\r"].location > 0) {
self.finalString = [self.finalString substringWithRange:NSMakeRange(0, [self.finalString rangeOfString:#"\r"].location)];
}
NSData *finalData = [self.finalString dataFromHex];
NSLog(#"final readBuff is %#",finalData);
if (i==(numwrites-1) && finalData.length >= 36) {
return true;
}
//free(buff);
}
#catch (NSException *exception) {
NSLog(#"Exception occured when writing user data %#",[exception description]);
}
}
return false;
}

PCI driver to fetch MAC address

I was trying to write a pci driver which can display the MAC address of my Ethernet card.
Running a Ubuntu on VM and my Ethernet card is Intel one as follows
00:08.0 Ethernet controller: Intel Corporation 82540EM Gigabit Ethernet Controller (rev 02)
I was able to get the data sheet of the same from Intel website and as per data sheet it says IO address are mapped to Bar 2 (Refer to pg 87) and MAC can be read using RAL/RAH register which are at offset RAL (05400h + 8*n; R/W) and RAH (05404h + 8n; R/W)
2 18h IO Register Base Address (bits 31:2) 0b mem
Based on this information, i wrote a small PCI driver but i always get the MAC as fff and when i debugged further, i see io_base address is always zero.
Below is the code
1 /*
2 Program to find a device on the PCI sub-system
3 */
4 #define VENDOR_ID 0x8086
5 #define DEVICE_ID 0x100e
6
7 #include <linux/kernel.h>
8 #include <linux/module.h>
9 #include <linux/stddef.h>
10 #include <linux/pci.h>
11 #include <linux/init.h>
12 #include <linux/cdev.h>
13 #include <linux/device.h>
14 #include <asm/io.h>
15
16 #define LOG(string...) printk(KERN_INFO string)
17
18 #define CDEV_MAJOR 227
19 #define CDEV_MINOR 0
20
21
22 MODULE_LICENSE("GPL");
23
24 struct pci_dev *pci_dev;
25 unsigned long mmio_addr;
26 unsigned long reg_len;
27 unsigned long *base_addr;
28
29 int device_probe(struct pci_dev *dev, const struct pci_device_id *id);
30 void device_remove(struct pci_dev *dev);
31
32 struct pci_device_id pci_device_id_DevicePCI[] =
33 {
34 {VENDOR_ID, DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
35 };
36
37 struct pci_driver pci_driver_DevicePCI =
38 {
39 name: "MyPCIDevice",
40 id_table: pci_device_id_DevicePCI,
41 probe: device_probe,
42 remove: device_remove
43 };
44
45
46 int init_module(void)
47 {
48 //struct pci_dev *pdev = NULL;
49 int ret = 0;
50
51 pci_register_driver(&pci_driver_DevicePCI);
52
53 return ret;
54 }
55
56 void cleanup_module(void)
57 {
58 pci_unregister_driver(&pci_driver_DevicePCI);
59
60 }
61
62 #define REGISTER_OFFSET 0x05400
64 int device_probe(struct pci_dev *dev, const struct pci_device_id *id)
65 {
66 int ret;
67 int bar = 2; // Bar to be reserved
68 unsigned long io_base = 0;
69 unsigned long mem_len = 0;
70 unsigned int register_data = 0;
71
72 LOG("Device probed");
73
74 /* Reserve the access to PCI device */
75 ret = pci_request_region(dev, bar, "my_pci");
76 if (ret) {
77 printk(KERN_ERR "request region failed :%d\n", ret);
78 return ret;
79 }
80
81 ret = pci_enable_device(dev);
82 if (ret < 0 ) LOG("Failed while enabling ... ");
83
84 io_base = pci_resource_start(dev, bar);
85 mem_len = pci_resource_len(dev, bar);
86
87 request_region(io_base, mem_len, "my_pci");
88 register_data = inw(io_base + REGISTER_OFFSET);
89 printk(KERN_INFO "IO base = %lx", io_base);
90 printk(KERN_INFO "MAC = %x", register_data);
91
92 return ret;
93 }
94
95 void device_remove(struct pci_dev *dev)
96 {
97 pci_release_regions(dev);
98 pci_disable_device(dev);
99 }
100
lspci -x output of my card
00:08.0 Ethernet controller: Intel Corporation 82540EM Gigabit Ethernet Controller (rev 02)
00: 86 80 0e 10 07 00 30 02 02 00 00 02 00 40 00 00
10: 00 00 82 f0 00 00 00 00 41 d2 00 00 00 00 00 00
20: 00 00 00 00 00 00 00 00 00 00 00 00 86 80 1e 00
30: 00 00 00 00 dc 00 00 00 00 00 00 00 09 01 ff 00
Can any one let me know what am i doing wrong?
I've modified your code and commented on changes. I have removed all of your existing comments to avoid confusion, and have only modified your probe function.
/* We need a place to store a logical address for unmapping later */
static void* logical_address;
int device_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
int ret;
int bar_mask; /* BAR mask (this variable) and the integer BAR */
int requested_bar = 2; /* (this variable) are not the same thing, so give them */
/* separate variables */
resource_size_t io_base = 0; /* use kernel macros instead of built-in datatypes */
resource_size_t mem_len = 0;
unsigned int register_data = 0;
LOG("Device probed");
/* add this call to get the correct BAR mask */
bar_mask = pci_select_bars(dev, 0);
/* switched order - enable device before requesting memory */
ret = pci_enable_device(dev);
if (ret < 0 ) LOG("Failed while enabling ... ");
/* for this call, we want to pass the BAR mask, NOT the integer bar we want */
ret = pci_request_region(dev, bar_mask, "my_pci");
if (ret) {
printk(KERN_ERR "request region failed :%d\n", ret);
return ret;
}
/* it is in THESE calls that we request a specific BAR */
io_base = pci_resource_start(dev, requested_bar);
mem_len = pci_resource_len(dev, requested_bar);
/* you don't need to request anything again, so get rid of this line: */
/* request_region(io_base, mem_len, "my_pci"); */
/* you're missing an important step: we need to translate the IO address
* to a kernel logical address that we can actually use. Add a call to
* ioremap()
*/
logical_address = ioremap(io_base, mem_len);
/* we need to use the logical address returned by ioremap(), not the physical
* address returned by resource_start
*/
register_data = inw(logical_address + REGISTER_OFFSET);
printk(KERN_INFO "IO base = %lx", io_base);
printk(KERN_INFO "MAC = %x", register_data);
return ret;
}
You will need to add a corresponding call to iounmap() in your device_remove() routine. Take a look at the Intel E100E driver source code for some good examples.

Resources