Coverity static analysis code defect - c

We use Coverity to detect vulnerabilities in our code. Basically this is the code snippet:
static int vendor_request(
const struct OFPHDR *oh,
size_t length,
const struct OFPUTIL_MT **typep
)
{
const struct OFPSM *osr;
ovs_be32 vendor;
osr = (const struct OFPSM *) oh;
memcpy(&vendor, ((char*)osr + sizeof(struct OFPSM)), sizeof( vendor ));
if (vendor == htonl(VENDOR_A))
return (functionA(oh, typep));
if (vendor == htonl(VENDOR_B))
return (functionB(oh, length, typep));
else
return 0;
}
Here,
sizeof(struct OFPSM) = 12 bytes.
sizeof(struct OFPHDR) = 8 bytes.
Coverity says:
CID xxxxx (#1 of 2): Out-of-bounds access (OVERRUN)
1. overrun-buffer-val: Overrunning struct type OFPHDR of 8 bytes by passing it to a function which accesses it at byte offset 12. Pointer osr indexed by constant 12U through dereference in call to memcpy.
Basically struct OFPHDR is a PDU on top of TCP layer, it's size is 8 bytes but it can vary depending upon what type of OFP message it is. Coverity says that I'm dereferencing *oh at byte offset index 12 which is out-bound-access index.
But I don't understand the problem since I'm typecasting OFPHDR to proper structure which is of 12 bytes and then dereferencing it. So, how could this error be avoided?

This cast:
osr = (const struct OFPSM *) oh;
is breaking the strict aliasing rules since it is casting to an incompatible type.
It's clear they are incompatible since you say:
sizeof(struct OFPSM) = 12 bytes.
sizeof(struct OFPHDR) = 8 bytes.

But I don't understand the problem since I'm typecasting OFPHDR to proper structure which is of 12 bytes and then dereferencing it.
Coverity is trying to save you from a path where perhaps you only allocated/read in sizeof OFPHDR bytes and yet you attempt to access beyond that allocation. You can see two reasonable possibilities taking you there: your vendor == htonl(VENDOR_A) logic could be implemented incorrectly or the values that you read from the network were maliciously crafted/in error.
Your cast supposes information about the implementation of the caller that coverity thinks you can't be certain about in vendor_request.
So, how could this error be avoided?
You could avoid it by changing vendor_request like so:
typedef union {
struct OFPHDR oh;
struct OFPSM osm;
} son_of_OFPHDR;
static int vendor_request(
const son_of_OFPHDR *oh,
size_t length,
const struct OFPUTIL_MT **typep
)
This explicitly tells compilers, static checkers, and humans that the oh input may be an OFPHDR or could be an OFPSM.
Everyone who agrees to take a son_of_OFPHDR * has an implicit pledge from callers that memory for the entire structure has been allocated. And everywhere son_of_OFPHDRs show up with automatic storage duration, sufficient memory will be allocated there.

Everyone, thanks for the answers.
#PeterSW: The structs are incompatible yes, but as I mentioned OFPHDR is a PDU on top of TCP layer, it's size is variable. The information which we need to extract(vendor) from that pointer lies on its 12th byte offset.
This is solved by typecasting it to correct structure which has size enough to envelop more than 12 bytes and includes that element(vendor):
struct OFPVSM {
struct OFPSM osm;
ovs_be32 vendor; /* Vendor ID:
/* Followed by vendor-defined arbitrary additional data. */
};
Here,
sizeof(struct OFPVSM) = 16 bytes.
Solution in git diff format:
- const struct OFPSM *osr;
+ const struct OFPVSM *osr;
- osr = (const struct OFPSM *) oh;
+ osr = (const struct OFPVSM*) oh;
Sorry for not mentioning a vital info:
struct OFPSM actually comprises of struct OFPHDR
struct OFPSM{
struct OFPHDR header;
ovs_be16 type;
ovs_be16 flags;
};
"vendor" lies at the end of struct OFPSM.

Related

Type casting struct pointer

I'm trying to get into Socket programming and came across an article at https://www.tenouk.com/Module43a.html I'm having difficulty understanding as how a char array is cast into struct pointer
char buffer[PCKT_LEN];
struct ipheader *ip = (struct ipheader *) buffer;
//some code here
ip->iph_ihl = 5;
ip->iph_ver = 4;
ip->iph_tos = 16;
As per my understanding, pointer ip will now hold the address of buffer and values for members of struct ipheader will now be stored in buffer. Please help understanding the same. If I'm right, then how would we be able to print values stored in buffer?
You understanding is correct. The pointer *ip will point to buffer. char buffer[PCKT_LEN] is an array of size sizeof(char) * PCKT_LEN. Since a char is usually 1 byte long it is just a chunk of memory of PCKT_LEN bytes. PCKT_LEN is defined to be 8192
The amount of bytes needed to store a struct ipheader is much less than this. Try int a = sizeof(ipheader) and use a debugger to see the value assigned to a. For me it is 24 bytes, but it could be slightly different for you. This means that buffer can hold much more data than the struct ipheader needs. I haven't looked to deeply into the code, and I don't know much about socket programming. But one use for this could be to augment buffer with additional data outside of the struct. Since you know struct ipheader takes up sizeof(ipheader) bytes you will have sizeof(char)*8192 - sizeof(ipheader) left to augment the array.
Edit:
Upun further inspection, this is kinda what is happening:
struct ipheader *ip = (struct ipheader *) buffer;
struct udpheader *udp = (struct udpheader *) (buffer + sizeof(struct ipheader));
It tries to store the ip header at the beginning of the buffer, then it augments that same buffer with an udp header. By using buffer + sizeof(struct ipheader)
it makes sure that it stores the udp header after ipheader by offsetting buffer by sizeof(struct ipheader) bytes. Basically struct ipheader *ip points to the beginning of the buffer and struct udpheader *udp points to buffer + sizeof(struct ipheader). I hope this makes sense. Obviously there is still a lot of space left over in buffer so you could potentially augment it even further.
how a char array is cast into struct pointer
You can't do that safely. The code invokes undefined behavior:
char buffer[PCKT_LEN];
struct ipheader *ip = (struct ipheader *) buffer;
//some code here
ip->iph_ihl = 5;
ip->iph_ver = 4;
ip->iph_tos = 16;
That code violates the strict aliasing rule. That basically means memory that isn't a certain type of object can't be treated as being that type of object, with the exception that any non-char object can be treated as an array of char.
That's not what's happening in the posted code. In the posted code, a char array is being treated as if it were a struct ipheader.
The memory is not a struct ipheader - it's an array of char - so the code violates strict aliasing.
The casting from char * to struct ipheader * can also result in an improperly aligned object and violate 6.3.2.3 Pointers, paragraph 7:
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. ...
Code such as you've found here is unfortunately all too common as the x86-based machines that are the most common platform widely used by programmers are very forgiving of misaligned accesses, so such code tends to "work".
See Structure assignment in Linux fails in ARM but succeeds in x86 for an example of a platform where it doesn't work.

Cast void pointer to struct and move it given size

I got a binary file that contains 3 different structs which I'm suppose to read to my program. After I have read the first struct I store its size, and then I'm suppose to convert my void pointer + the first structs length to a struct ip_hdr * (which is the second struct) and then read all it's values.
But the problems is I don't understand how you move a void pointer. I have understood that the void pointers don't have the same arithmetic rules as like a int pointer.
I want to do something like this:
ptr = (struct ip_hdr *)ptr) + (ethRes));
But that doesn't work instead I get following error message:
Expression must be a pointer to a complete object type
Here is my code:
#pragma warning(disable: 4996)
#include <stdio.h>
#include <stdlib.h>
#include "framehdr.h"
#include <crtdbg.h>
int main()
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
FILE *fileOpen = fopen("C:\\Users\\Viktor\\source\\repos\\Laboration_3\\Laboration_3\\TCPdump", "rb");
//Pointers and variables
struct ethernet_hdr eth;
struct ethernet_hdr *ethPtr;
struct ip_hdr ip;
struct ip_hdr *ipPtr;
struct tcp_hdr tcp;
struct tcp_hdr *tcpPtr;
if (fileOpen == NULL)
{
printf("Error\n");
}
else
{
printf("Success\n");
}
char ethrr[10];
fscanf(fileOpen, "%s", ethrr);
int length = atoi(ethrr);
printf("Nr: %d\n", length);
void *ptr;
ptr = (void *)malloc(length);
fread(ptr, sizeof(eth), 1, fileOpen);
int ethRes = sizeof(((struct ethernet_hdr*)ptr)->dhost) +
sizeof(((struct ethernet_hdr*)ptr)->shost) +
sizeof(((struct ethernet_hdr*)ptr)->type);
printf("%d\n", ethRes);
printf("ptr1: %d\n", &ptr);
system("pause");
fclose(fileOpen);
return 0;
}
I now it's broken but I'm not done with it. Just need help with the pointers for now.
This should work, assuming the structure is compatible with whatever is in the file (in general saving structs "raw" to disk is a bad idea, the exact layout of a struct in memory is compiler-dependent and not stable enough to use as a file format):
const struct ip_hdr * const ip = (struct ip_hdr *) ((struct ethernet_hdr *) ptr + 1);
This adds "1" to a pointer of type ethernet_hdr, which will advance the actual pointer value by whatever size the Ethernet header structure has. The result is then cast to struct ip_hdr *.
I think this is what you wanted to do. You can do it by adding bytes to a char *, but what's the point?
You can't add directly to the void pointer, since pointer arithmetic is always in units of whatever is pointed at, and void has no size.
Here's an example of moving along an array of structures using a pointer to void.
The compiler doesn't know the type of object pointed to by a void* pointer.
So you have two choices. One is to convert it to a pointer to the 'correct' type and then add the number of elements you want to move. The other is to add the number of bytes you want to an unsigned char* (or similar).
The action happens on the lines marked [1] and [2] below.
#include <stdio.h>
typedef struct {
int payload;
double other;
} thingy;
int main(void) {
thingy athingy[2];//An array of two thingys.
void* voidptr=athingy; //a pointer to first thingy.
thingy* nextthingy=((unsigned char*)voidptr)+sizeof(thingy); //[A] next thingy points to second element of array.
thingy* altnext=((thingy*)voidptr)+1; //[B] Points to the same thing!
printf("voidptr==%p %zu\n",voidptr,sizeof(thingy));
printf("nextthingy==%p\n",nextthingy);
printf("altthingy==%p\n",altnext);
if(nextthingy==altnext){
printf("Same\n");
}else{
printf("Not same (oh dear)\n");
}
return 0;
}
Typical output:
voidptr==0x7ffd6909d660 4
nextthingy==0x7ffd6909d664
altthingy==0x7ffd6909d664
Same
The actual values may vary.
Caveat
If I understand the question, the requirement is to move through a number of different structs read together.
That may be problematic because of alignment. It's beyond the scope of this question to go into detail but C may place or require padding between members or objects of different type to ensure they are aligned on the architecture. It's very common for example for 4 byte integers to lie on memory addresses that numerically divide by 4. That simplifies hardware and improves performance.
It's not clear from the fragment provided that the objects read in will be aligned and further copying of data and shuffling may be required.
That may have been taken into account but that can't be seen from the information provided.
What may help is the often overlooked offsetof(,) macro defined in stddef.h.
That returns the offset of a member within a type (taking internal padding into consideration). For example there is in general no guarantee (above) that:
voidptr+sizeof(payload)==((unsigned char*)voidptr)+offsetof(thingy,other)

Access first variable of a structure from a pointer that points to a different variable in the structure

Consider the following code fragment:
struct data_t {
int data1;
int data2;
struct data_t *next;
size_t size;
int data3;
int data4;
};
int *ptr;
struct data_t data;
...
ptr = &data.data4;
Now using pointer, which is set to point to the last element in the structure, how can one use that pointer to access the first element in the structure (data1)?
Normally, what I would do in this case is back up the pointer by so many words to point to that element, but there is a problem. The pointer variable next in the middle of the structure has a varying size depending on the platform. If this is running on a 32-bit platform, then the pointer is 4 bytes while on a 64-bit platform, the pointer takes up 8 bytes. A similar issue happens with the size_t datatype as well.
Although not clear in the example, the structure is the header to a block of memory that is variable in size and is part of a linked list. AKA a free list in a memory allocator. Other than using some kind of an initialization that calculates the size of the pointer itself, is there a portable way of getting the address of the first element of the structure?
You can use offsetof to know how far a member is from the start of the structure. In this case:
struct data_t *p = (struct data_t *)( (char *)ptr - offsetof(struct data_t, data4) );
Obviously this requires you to know that the pointer is pointing at a data4 already, there's no way to autodetect that or anything. And, of course, it would be preferable to use a code design where you pass around the struct data * in the first place.

Pointer manipulation to access elements in a struct

Given the below simple code, where you have process_payload is given a pointer to the payload portion of the packet, how do you access the header portion? Ideally the caller should simply give a pointer to full packet from beginning, but there are cases where you don't have the beginning of the message and need to work backwards to get to the header info. I guess this question becomes a understanding of walking through the memory layout of a struct.
The header computes to 8 bytes with sizeof operation. I assume Visual C++ compiler added 3 bytes padding to header.
The difference between pptr and pptr->payload is decimal 80 (not sure why this value??) when doing ptr arith (pptr->payload - pptr). Setting ptr = (struct Packet*)(payload - 80) works but seems more a hack. I don't quite understand why subtracting sizeof(struct header) doesn't work.
Thanks for any help you can give.
struct Header
{
unsigned char id;
unsigned int size;
};
struct Packet
{
struct Header header;
unsigned char* payload;
};
void process_payload(unsigned char* payload);
int main()
{
struct Packet* pptr = (struct Packet*)malloc(sizeof(struct Packet));
pptr->payload = (unsigned char*)malloc(sizeof(unsigned char)*10);
process_payload(pptr->payload);
return 1;
}
// Function needs to work backwards to get to header info.
void process_payload(unsigned char* payload)
{
// If ptr is correctly setup, it will be able to access all the fields
// visible in struct Packet and not simply payload part.
struct Packet* ptr;
// This does not work when intuitively it should?
ptr = (struct Packet*)(payload - sizeof(struct Header));
}
It's because in main you allocate two pointers, and pass the second pointer to the process_payload function. The two pointers are not related.
There are two ways of solving this problem, where both include a single allocation.
The first solution is to used so called flexible arrays, where you have an array member last in the structure without any size:
struct Packet
{
struct Header header;
unsigned char payload[];
};
To use it you make one allocation, with the size of the structure plus the size of the payload:
struct Packet *pptr = malloc(sizeof(struct Packet) + 10);
Now pptr->payload is handled like a normal pointer pointing to 10 unsigned characters.
Another solution, which is a mix of your current solution and the solution with flexible arrays, is to make one allocation and make the payload pointer to point to the correct place in the single allocated memory block:
struct Packet
{
struct Header header;
unsigned char *payload;
};
// ...
struct Packet *pptr = malloc(sizeof(struct Packet) + 10);
pptr->payload = (unsigned char *) ((char *) pptr + sizeof(struct Packet);
Note that in this case, to get the Packet structure from the payload pointer, you have to use sizeof(Packet) instead of only sizeof(Header).
Two things to note about the code above:
I don't cast the result of malloc
sizeof(char) (and also the size of unsigned char) is specified to always be one, so no need for sizeof

Given the absolute address of the flexible array member in a struct, how can I get the absolute address of the struct?

See the struct I used bellow. I wish to solve this problem in a portable way.
The code I used for finding the absolute address of the struct was: (char*)data - sizeof(struct block); (where data is the address to the data in the struct block). It did not work on this struct.
I made a test program seen bellow where the last assert fails.
If I change unsigned int free:1; to unsigned int free; both prints will print 12 and thus sizeof has given me the expected result.
Thanks in advance.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
struct block {
size_t size;
struct block* next;
unsigned int free:1;
char data[];
};
int main(void)
{
struct block* avail;
struct block* b;
avail = malloc(sizeof(struct block) + 10);
printf("%zu \n", sizeof(struct block)); // prints 12
printf("%zu\n", avail->data - (char*)&avail->size); //prints 9
b = (struct block*)((char*)avail->data - 9);
assert(b == avail);
b = (struct block*)((char*)avail->data - sizeof(struct block));
assert(b == avail);
return 0;
}
EDIT: seems like I found the answer here on stack overflow:
how to get struct's start address from its member's address
It gives me correct absolute address.
The only guarantees you have regarding the layout (and size) of
struct block {
size_t size;
struct block* next;
unsigned int free:1;
char data[];
};
are that the addresses of the members (resp. the unit containign the bit-field) are increasing in the order of their listing, the members are suitably aligned for their types, and there's no padding at the start of the struct, so a pointer to the struct, suitably converted yields a pointer to its first member. The compiler is free to insert more padding between the members than needed for alignment.
However, usually, the padding inserted is only what is needed for alignment. Also the size and alignment requirements of size_t and struct block* are in most implementations the same, both 4 bytes on a 32 bit system and 8 bytes on a 64 bit system. Then the size of struct block is a multiple of k = sizeof(size_t), and the first k bytes are occupied by the size member, the next k bytes by the next pointer.
After that comes an unsigned bit-field of width 1. Such a small bit-field fits into any unit of storage, thus the implementation is free to choose a unit of storage of any size for it. Natural choices would be
one byte, since it's the smallest possible unit,
sizeof(int) bytes, since " A ‘‘plain’’ int object has the natural size suggested by the architecture of the execution environment".
Now, if the unit to contain the bit-field is chosen to have the size of one byte, as was the case for your implementation (and mine), the data member is typically placed directly after that, at an offset of 2*k+1 bytes, since the alignment of char is 1. If the unit for the bit-field is chosen to be int-sized, the offset of data will most likely be 2*k + sizeof(int), which on 32-bit systems is probably equal to sizeof(struct block), but not on 64-bit systems.
You can with very high probability bring the implementation to make
offsetof(struct block, data) == sizeof(struct block)
by inserting an unnamed bit-field of appropriate width (CHAR_BIT * sizeof(size_t) - 1) between free and data, but the only way that is portable and guaranteed to work is
struct block *b_addr = (struct block*)((char*)(avail->data) - offsetof(struct block, data));
as stated in Greg Hewgill's answer to the linked question.
sizeof(struct block) - sizeof(char*) should give you the size of the struct block, not including the data field. So, if you have a pointer to data, you should reach the beginning of the structure.
b = (struct block*)((char*)avail->data - (sizeof(struct block) - sizeof(char*));
assert(b == avail);
I have not tested it, though.

Resources