Linker adds extra padding in section? - c

I am using GCC and am trying to get the linker to create an array of data objects from different files in a custom section. I have added this section to the linker script:
.mydata :
{
__mydata_start = .;
KEEP (*(.mydata))
__mydata_end = .;
}
Here is my data structure:
struct my_type_t {
unsigned char a;
size_t b;
void *c;
const void *d;
const void *e;
const char *f;
};
I am on a 64-bit platform, and sizeof(struct my_type_t) gives 48. However, the linker seems to want to align these structures to 64-bytes.
My declarations:
struct my_type_t a1 __attribute__((section(".mydata"))) = {
1, 2, (void *)3, (void *)4, (void *)5, (void *)6,
};
struct my_type_t a2 __attribute__((section(".mydata"))) = {
7, 8, (void *)9, (void *)10, (void *)11, (void *)12,
};
Linker output:
$ gcc -o ldtest ldtest.c -Wl,-Tlink.ld
$ objcopy -Obinary -j .mydata ldtest mydata
$ hd mydata
00000000 01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 |................|
00000010 03 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 |................|
00000020 05 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000040 07 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 |................|
00000050 09 00 00 00 00 00 00 00 0a 00 00 00 00 00 00 00 |................|
00000060 0b 00 00 00 00 00 00 00 0c 00 00 00 00 00 00 00 |................|
If I instead declare it as an array:
struct my_type_t a1[2] __attribute__((section(".mydata"))) = {
{
1, 2, (void *)3, (void *)4, (void *)5, (void *)6,
},
{
7, 8, (void *)9, (void *)10, (void *)11, (void *)12,
},
};
There is no padding, as expected:
00000000 01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 |................|
00000010 03 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 |................|
00000020 05 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 |................|
00000030 07 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 |................|
00000040 09 00 00 00 00 00 00 00 0a 00 00 00 00 00 00 00 |................|
00000050 0b 00 00 00 00 00 00 00 0c 00 00 00 00 00 00 00 |................|
Why is the linker adding extra padding beyond what the compiler thinks is necessary, and how can I get rid of it?

I don't know why it wants it aligned on 64-byte, but you can do:
struct my_type_t {
unsigned char a;
size_t b;
void *c;
const void *d;
const void *e;
const char *f;
} __attribute__ ((aligned (64)));
To make gcc automatically pad each struct to the nearest higher 64-byte address and make sizeof(struct my_type_t) also include the padding. This makes operations like this work correctly:
struct my_type_t *s = &__mydata_start;
s++; // Jump to next entry
s[0]; // First entry
s[1]; // Second entry

Related

C hexadecimal formatting giving me extra digits

I've been working on a small program to dump the hex values of a file, similar to od or hexdump, and I've ran into an issue when printing the values. For certain hex values, mostly ones with alphabetical characters as their second digit, it prints with 6 extra f digits before printing the actual number, instead of just printing a 2-width value like I had specified. I have confirmed that the values themselves are not unexpected in any way, it's the printing that's messing it up.
Code:
int main(int argc, char* argv[]) {
FILE* dataFile = fopen(argv[1], "rb");
int byteCount = 0;
char currentByte = fgetc(dataFile);
while (currentByte != EOF) {
printf("%08d", byteCount);
do {
//print as hex
printf(" %02x ", currentByte);
//set up for next loop
currentByte = fgetc(dataFile);
byteCount++;
} while (currentByte != EOF && (byteCount) % 16 != 0);
printf("\n");
}
printf("%08d\n", byteCount);
}
Output:
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
00000016 03 00 3e 00 01 00 00 00 10 6b 00 00 00 00 00 00
00000032 40 00 00 00 00 00 00 00 08 23 02 00 00 00 00 00
00000048 00 00 00 00 40 00 38 00 0d 00 40 00 1f 00 1e 00
00000064 06 00 00 00 04 00 00 00 40 00 00 00 00 00 00 00
00000080 40 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00
00000096 ffffffd8 02 00 00 00 00 00 00 ffffffd8 02 00 00 00 00 00 00
00000112 08 00 00 00 00 00 00 00 03 00 00 00 04 00 00 00
00000128 18 03 00 00 00 00 00 00 18 03 00 00 00 00 00 00
00000144 18 03 00 00 00 00 00 00 1c 00 00 00 00 00 00 00
00000160 1c 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00
00000176 01 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00
00000192 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000208 fffffff8 34 00 00 00 00 00 00 fffffff8 34 00 00 00 00 00 00
Does anyone know what's going on here?
There are several problems here.
char is entirely unsuitable to hold raw binary data, because it has implementation-defined signedness and it often a signed type, see Is char signed or unsigned by default?. In fact char should only ever be used for text strings. Instead, you would normally use uint8_t. However... :
The EOF constant is of type int, so if you intend to compare something against EOF, it must be type int. fgetc is guaranteed to return characters as if they were unsigned char but converted to int - as it happens, int is large enough to hold all values of an unsigned char so int can be used here.
%x specifier for printf expects an unsigned int.
Fixes:
char currentByte -> int currentByte
printf(" %02x ", currentByte); -> printf(" %02x ", (unsigned int)currentByte);.
You must always check if fopen was successful and also fclose the file pointer when done. Also note that calling fopen directly on argv with no input sanitation is not acceptable in a professional program. You don't even know if argv[1] exists - the program needs a whole lot more error handling overall.

My program cannot read and display contents in a file

I have an assignment that I need to create a program to read (in binary mode) a file and then display them out on the screen. I run it in the command line mode. Here is my source code:
#include <stdio.h>
#include <stdlib.h>
#define MAXWORD 130
typedef struct Node node;
struct Node
{
int stt;
char name[50];
char phonenumber[20];
char email[50];
};
int checktoread(FILE *datain)
{
return (datain == NULL);
}
int readfile(FILE *datain, node *item)
{
int i = 0;
while(fread(&item[i], sizeof(node), 1, datain)>0)
{
i++;
}
return i;
}
void display(node *item, int max)
{
int i = 0;
for(; i < max; i++)
{
printf("%-3d%-30s%-20s%-30s\n", item[i].stt, item[i].name, item[i].phonenumber, item[i].email);
}
}
int main(int argv, char *argc[])
{
if (argv != 2)
{
printf("Wrong syntax\nCorrect Syntax: readfile <source file>\n");
exit(1);
}
FILE *fp = fopen(argc[1], "rb");
if(checktoread(fp))
{
printf("The source file is unable to be opened\n");
exit(1);
}
node *person = (node*) malloc(30*sizeof(person));
int maxline = readfile(fp, person);
printf("%d\n", maxline);
display(person, maxline);
fclose(fp);
free(person);
return 0;
}
My problem is this file do not return or display anything. There is no syntax error here, I confirm. I don't know where I get wrong. Actually, I think it get wrong in the step that convert data from a file into an array.
The file starts like this
0 1 2 3 4 5 6 7 8 9 A B C D E F
0000:0000 01 00 00 00 4A 6F 65 79 4D 61 74 68 65 6C 00 00
0000:0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0060 00 00 00 00 00 00 00 00 30 33 38 35 37 38 38 30
0000:0070 36 30 00 00 00 00 00 00 00 00 00 00 6A 6F 65 79
0000:0080 6D 61 74 68 65 6C 40 67 6D 61 69 6C 2E 63 6F 6D
0000:0090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:00A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:00B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:00C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:00D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:00E0 02 00 00 00 53 63 6F 74 74 79 4A 61 63 6B 00 00
0000:00F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

AF_XDP: `BPF_MAP_TYPE_XSKMAP` only has entries with `Operation not supported`

This is all my XDP / BPF kernel code:
struct bpf_map_def SEC("maps") xsks_map = {
.type = BPF_MAP_TYPE_XSKMAP,
.key_size = sizeof(int),
.value_size = sizeof(int),
.max_entries = 64, /* Assume netdev has no more than 64 queues */
};
struct bpf_map_def SEC("maps") rx_queue_pckt_counter_map = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(int),
.value_size = sizeof(unsigned long),
.max_entries = 48,
};
SEC("xdp_sock")
int xdp_sock_prog(struct xdp_md *ctx) {
int index = ctx->rx_queue_index;
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
void *pos = data;
struct ethhdr *eth = (struct ethhdr*)(pos);
if(eth + sizeof(struct ethhdr) <= data_end) {
if(bpf_ntohs(eth->h_proto) == ETH_P_IP) {
struct iphdr *iph = (struct iphdr*)(pos + sizeof(struct ethhdr));
if(iph + sizeof(struct iphdr) <= data_end) {
if(iph->protocol == IPPROTO_UDP) {
const __u16 iph_sz_in_bytes = iph->ihl * 4;
if(iph + iph_sz_in_bytes <= data_end) {
struct udphdr *udh = (struct udphdr*)(pos + sizeof(struct ethhdr) + iph_sz_in_bytes);
if(udh + sizeof(struct udphdr) <= data_end) {
void *rec = bpf_map_lookup_elem(&rx_queue_pckt_counter_map, &index);
if(rec) {
long *pckt_counter_val = (long*)(rec);
*pckt_counter_val += 1;
} else {
return XDP_PASS;
}
if (bpf_map_lookup_elem(&xsks_map, &index)) {
const int ret_val = bpf_redirect_map(&xsks_map, index, 0);
bpf_printk("RET-VAL: %d\n", ret_val);
return ret_val;
}
}
}
}
}
}
}
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
I am trying to filter all IP-UDP packets and send them into user-space. I also count the number of packets arriving for each RX-Queue (indicated by ctx->rx_queue_index).
My program compiles fine but for whatever reason I don't receive any packets in my user-space program. I already talked about this in another post of mine: AF_XDP: No packets from multicast although steered on RX-Queue 0
I executed sudo ethtool -N eth20 flow-type udp4 action 0 beforehand to steer all packets onto RX-Queue 0.
I can see all bpf maps currently active via
$ sudo bpftool map list
32: lpm_trie flags 0x1
key 8B value 8B max_entries 1 memlock 4096B
33: lpm_trie flags 0x1
key 20B value 8B max_entries 1 memlock 4096B
34: lpm_trie flags 0x1
key 8B value 8B max_entries 1 memlock 4096B
35: lpm_trie flags 0x1
key 20B value 8B max_entries 1 memlock 4096B
36: lpm_trie flags 0x1
key 8B value 8B max_entries 1 memlock 4096B
37: lpm_trie flags 0x1
key 20B value 8B max_entries 1 memlock 4096B
125: array name rx_queue_pckt_c flags 0x0
key 4B value 8B max_entries 48 memlock 4096B
126: xskmap name xsks_map flags 0x0
key 4B value 4B max_entries 64 memlock 4096B
But I think only 125 and 126 are related to my program.
The queue-steering works because with sudo bpftool map dump id 125 I get:
key: 00 00 00 00 value: 99 1a cc 04 00 00 00 00
key: 01 00 00 00 value: 00 00 00 00 00 00 00 00
key: 02 00 00 00 value: 00 00 00 00 00 00 00 00
key: 03 00 00 00 value: 00 00 00 00 00 00 00 00
key: 04 00 00 00 value: 00 00 00 00 00 00 00 00
key: 05 00 00 00 value: 00 00 00 00 00 00 00 00
key: 06 00 00 00 value: 00 00 00 00 00 00 00 00
key: 07 00 00 00 value: 00 00 00 00 00 00 00 00
key: 08 00 00 00 value: 00 00 00 00 00 00 00 00
key: 09 00 00 00 value: 00 00 00 00 00 00 00 00
key: 0a 00 00 00 value: 00 00 00 00 00 00 00 00
key: 0b 00 00 00 value: 00 00 00 00 00 00 00 00
key: 0c 00 00 00 value: 00 00 00 00 00 00 00 00
key: 0d 00 00 00 value: 00 00 00 00 00 00 00 00
key: 0e 00 00 00 value: 00 00 00 00 00 00 00 00
key: 0f 00 00 00 value: 00 00 00 00 00 00 00 00
key: 10 00 00 00 value: 00 00 00 00 00 00 00 00
key: 11 00 00 00 value: 00 00 00 00 00 00 00 00
key: 12 00 00 00 value: 00 00 00 00 00 00 00 00
key: 13 00 00 00 value: 00 00 00 00 00 00 00 00
key: 14 00 00 00 value: 00 00 00 00 00 00 00 00
key: 15 00 00 00 value: 00 00 00 00 00 00 00 00
key: 16 00 00 00 value: 00 00 00 00 00 00 00 00
key: 17 00 00 00 value: 00 00 00 00 00 00 00 00
key: 18 00 00 00 value: 00 00 00 00 00 00 00 00
key: 19 00 00 00 value: 00 00 00 00 00 00 00 00
key: 1a 00 00 00 value: 00 00 00 00 00 00 00 00
key: 1b 00 00 00 value: 00 00 00 00 00 00 00 00
key: 1c 00 00 00 value: 00 00 00 00 00 00 00 00
key: 1d 00 00 00 value: 00 00 00 00 00 00 00 00
key: 1e 00 00 00 value: 00 00 00 00 00 00 00 00
key: 1f 00 00 00 value: 00 00 00 00 00 00 00 00
key: 20 00 00 00 value: 00 00 00 00 00 00 00 00
key: 21 00 00 00 value: 00 00 00 00 00 00 00 00
key: 22 00 00 00 value: 00 00 00 00 00 00 00 00
key: 23 00 00 00 value: 00 00 00 00 00 00 00 00
key: 24 00 00 00 value: 00 00 00 00 00 00 00 00
key: 25 00 00 00 value: 00 00 00 00 00 00 00 00
key: 26 00 00 00 value: 00 00 00 00 00 00 00 00
key: 27 00 00 00 value: 00 00 00 00 00 00 00 00
key: 28 00 00 00 value: 00 00 00 00 00 00 00 00
key: 29 00 00 00 value: 00 00 00 00 00 00 00 00
key: 2a 00 00 00 value: 00 00 00 00 00 00 00 00
key: 2b 00 00 00 value: 00 00 00 00 00 00 00 00
key: 2c 00 00 00 value: 00 00 00 00 00 00 00 00
key: 2d 00 00 00 value: 00 00 00 00 00 00 00 00
key: 2e 00 00 00 value: 00 00 00 00 00 00 00 00
key: 2f 00 00 00 value: 00 00 00 00 00 00 00 00
Found 48 elements
As you can see, only the counter for RX-Queue 0 is greater than 0.
But, if I take a look at the BPF_MAP_TYPE_XSKMAP (which is used to transfer packets into user-space), I get:
$ sudo bpftool map dump id 126
key:
00 00 00 00
value:
Operation not supported
key:
01 00 00 00
value:
Operation not supported
key:
02 00 00 00
value:
Operation not supported
key:
03 00 00 00
value:
Operation not supported
key:
04 00 00 00
value:
Operation not supported
...
key:
3e 00 00 00
value:
Operation not supported
key:
3f 00 00 00
value:
Operation not supported
Found 0 elements
Is the message Operation not supported an indicator why I don't receive any packets in my user-space program? Or is it just not possible to receive the value during runtime? I also find it strange to see Found 0 elements.
Any ideas what is wrong here?
This is simply because maps of type BPF_MAP_TYPE_XSKMAP do not support lookup from user space (you'd get addresses from kernel space, which does not make sense from user space point of view and might be a security issue).
So because attempting the lookup returns -EOPNOTSUPP, bpftool is unable to show the values. It could error out and print nothing, but instead we made it print the keys it finds, and print the error messages we get for the values.
As for the Found 0 elements, the count is for the elements that bpftool could retrieve without any error, so it's only logical that it remains at zero in this case.
So nothing seems wrong in your case, I do not believe this output is related to your issue with the missing packets.

Cannot read struct from binary file

I am trying to read the contents of a binary file into a struct, but each time I print out the contents of my struct, I get a pretty strange output. Below is the struct I am trying to set:
struct student {
char name[32];
unsigned int age;
SEX sex;
float gpa;
struct course *courses;
struct student *next;
}
With the course struct defined as:
struct course {
char grade;
unsigned int number;
struct course *next;
}
And SEX defined as:
typedef enum _SEX {MALE = 'M', FEMALE = 'F', OTHER = 'O'} SEX;
Right now, my function is as follows:
void read_bin(char *filename){
FILE *file;
struct student myStudent;
file = fopen(filename, "rb");
if(file == NULL){
printf("Unable to open file!");
return;
}
fread(&myStudent, sizeof(struct student), 1, file);
printf("\nName: %s, Age: %d", myStudent.name, myStudent.age);
fclose(file);
}
But I keep on getting this strange output:
Age: 0
With name not even showing up and age set to an incorrect number. I thought this might be due to padding, so I tried using
fread(&myStudent.name, sizeof myStudent.name, 1, file);
fread(&myStudent.age, sizeof myStudent.age, 1, file);
So that it reads each individual element and pads as needed. However, I get the same output. When I ran hexdump to see what exactly I was dealing with, this is what came out:
f0 0d 03 00 00 00 46 72 65 64 00 00 00 00 00 00 |......Fred......|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00 00 00 00 00 00 1d 00 00 00 4d 00 00 00 cd cc |..........M.....|
4c 40 01 00 00 00 44 02 00 00 41 4a 6f 65 00 00 |L#....D...AJoe..|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00 00 00 00 00 00 00 00 00 00 00 16 00 00 00 4d |...............M|
00 00 00 33 33 73 40 03 00 00 00 6e 00 00 00 42 |...33s#....n...B|
dc 00 00 00 41 54 01 00 00 41 53 61 72 61 68 00 |....AT...ASarah.|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00 00 00 00 00 00 00 00 00 00 16 00 00 00 46 00 |..............F.|
00 00 00 00 40 40 03 00 00 00 78 00 00 00 42 dc |....##....x...B.|
00 00 00 41 4a 01 00 00 43 |...AJ...C|
Any help would be greatly appreciated -- I've been stuck on this function for awhile.
Depending on the filetype the first few bytes can be a fileheader, here information can be stored like version numbers, length of the data etc.
As for the pointers, that won't work like others pointed out since pointers are adresses, not actual relevant data.
You want to fseek to sizeof(fileheader), before you start reading the file.
Also be wary that structs are padded in C and that the order in which you declared the elements in the struct might not be the order the compiler decided for it.

How to detect buffer overflow in C for this particular case,

I think this code should produce a buffer overflow error but apparently, this prints fine.. is there anyway to detect it has overflown?
Valgrind didn't picked it up either...
static void e(void) {
char buffer[5];
char data1[] = "abc";
char data2[] = "de";
memcpy(buffer, data1, sizeof(data1));
// strcat appends data2 to buffer and adds '\0' at the end dest
strcat(buffer, data2);
//printf("%s\n", buffer);
}
The -fsanitize=address of gcc is the option you're looking for. E.g.:
$ cat test.cpp
#include <stdio.h>
#include <string.h>
static void e(void) {
char buffer[5];
char data1[] = "abc";
char data2[] = "de";
memcpy(buffer, data1, sizeof(data1));
// strcat appends data2 to buffer and adds '\0' at the end dest
strcat(buffer, data2);
//printf("%s\n", buffer);
}
int main() {
e();
}
$ g++ test.cpp -o a -fsanitize=address -g3
$ ./a
=================================================================
==21537== ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffd1d8c0313 at pc 0x7f96ebedd94b bp 0x7ffd1d8c0260 sp 0x7ffd1d8bfa20
WRITE of size 3 at 0x7ffd1d8c0313 thread T0
#0 0x7f96ebedd94a (/usr/lib/x86_64-linux-gnu/libasan.so.0.0.0+0xe94a)
#1 0x40091b (/tmp/a+0x40091b)
#2 0x400959 (/tmp/a+0x400959)
#3 0x7f96ebb2bec4 (/lib/x86_64-linux-gnu/libc-2.19.so+0x21ec4)
#4 0x400748 (/tmp/a+0x400748)
Address 0x7ffd1d8c0313 is located at offset 163 in frame <e> of T0's stack:
This frame has 3 object(s):
[32, 35) 'data2'
[96, 100) 'data1'
[160, 165) 'buffer'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
(longjmp and C++ exceptions *are* supported)
Shadow bytes around the buggy address:
0x100023b10010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023b10020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023b10030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023b10040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
0x100023b10050: f1 f1 03 f4 f4 f4 f2 f2 f2 f2 04 f4 f4 f4 f2 f2
=>0x100023b10060: f2 f2[05]f4 f4 f4 00 00 00 00 00 00 00 00 00 00
0x100023b10070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023b10080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023b10090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023b100a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023b100b0: 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 righ 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
ASan internal: fe
==21537== ABORTING

Resources