-1

I was reading a very interesting article about Kerberos credential stealing. And in the PoC the author has the following line:

struct inotify_event *event = (struct inotify_event *)&buffer[i];

where buffer is defined as

char buffer[BUF_LEN];

What I wanted to know is how this typecasting above works, and how is it different from

(struct notify *)buffer[i];

While I'm aware that the types being casted would be char * and char, respectively, I can't wrap my head on why and how the author is casting that to a struct and subsequently accessing it's members

Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
unc4nny
  • 11
  • 3
    `(type *)var` is casting the value of `var` itself. `(type *)&var` is casting *the pointer to* `var`. – MikeCAT Feb 03 '21 at 13:23
  • C or C++? Pick one or ask 2 different questions. C++ supports operator overloading, so the code could be doing anything. – Aykhan Hagverdili Feb 03 '21 at 13:24
  • Why the author is doing the cast to access the members? How would you access the members? – klutt Feb 03 '21 at 13:45
  • `struct inotify_event *event = (struct inotify_event *)&buffer[i];` is undefined behavior as it's a strict aliasing violation. – Andrew Henle Feb 03 '21 at 14:00
  • @AndrewHenle Strictly speaking it is not, until the lvalue is de-referenced as a struct type (or any member of the struct not compatible with the effective type). Though of course, why would you do this cast if the intention wasn't to de-reference the pointer. – Lundin Feb 03 '21 at 14:02
  • @Lundin Yes, it's not a strict aliasing violation until it's dereferenced, but there's also no guarantees in C that the value of `&buffer[i]` can even be stored in a `struct inotify_event *`. Any alignment restrictions are also relevant when the pointer is converted, not only when it's dereferenced. An architecture where `struct` pointers must be 8-byte aligned, for example, could `SIGSEGV` or similar just assigning a misaligned pointer. And then when it's dereferenced, those operations also need to meet any alignment restrictions on every dereference operation. Many opportunities for UB... – Andrew Henle Feb 03 '21 at 14:12

2 Answers2

1

Difference between (type *)var and (type *)&var

Former converts the value of var into a pointer to type. This may be reasonable when var contains a value that represents address of a type object. Given that var in your case is a char, it is probably not reasonable to reinterpret its value as a pointer.

Latter converts a pointer to the var into a pointer to type. This may be reasonable when var and its siblings represent a value that you wish to interpret as type.

eerorika
  • 232,697
  • 12
  • 197
  • 326
1

(type*)var is generally a compiler error except if var is an integer type. Integers may be converted to pointers by a special rule C17 6.3.2.3/5:

An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.

As for casting the address of a char buffer to a pointer as in (struct inotify_event *)&buffer[i], the pointer conversion itself is allowed by C. Though this code is most likely a bug. There are several problems with this conversion:

  • buffer[i] is not necessarily aligned, if not it's a misaligned access bug.
  • Pointer types do not necessarily have the same size as the content pointed-at. And vice versa. For example storing a 32 bit value in a 64 bit pointer works, but not the other way around. That's why uintptr_t is the only safe integer type to use for such conversions.
  • Should you de-reference this struct pointer or any of its members, it is likely a strict aliasing violation bug. What is the strict aliasing rule?

In case the article described a dirty hack, well then, it is just that. Dirty hacks aren't very stable or portable. Otherwise, if the article described the correct way of doing things, the author was probably not very familiar with intermediate level C programming.

Lundin
  • 195,001
  • 40
  • 254
  • 396