copy_to/from_user use void pointers, meaning they are ignorant of any data types you pass. And given your example, even if they were aware of the data type, you still cannot trust your user: He could simply cast to the type you want:
struct bar *x;
copy_to_kernel_aware_of_foo((struct foo*)x);
Expecting the caller to have any kinds of root privileges or capabilities also does not solve your problem - root can also make mistakes or be evil.
Things that can help a bit:
- Only use
copy_to/from_user to copy around untyped byte buffers. Don't rely on kernel and user space having the same notion of complex data structures.
- If you only worry about data types being wrong by mistake, you might consider tagging your data structure so that it contains some magic values in between the 'real' data. This will not help you against the caller deliberately faking data, though.
- In terms of an attack surface, the attacker will probably not attack you by passing a wrong data type, but instead provide wrong values. There's nothing to help you instead of proper validation of all data that is passed to you from user space. Never trust anything without checking!