There is no means for a non-root process to become root (beyond exploits), so yes, you need a separate process.
This is inherited unchanged from linux - the difference being that there's no direct way to launch an android application process as root from the launcher, since that sends an intent to zygote which forks off and privilege-reduces a child that specializes into an application process. (There may be a roundabout method to manually create an application process, but you'd have to have an applications process to do it, so it would by definition be a secondary process. And it would be inefficient as an application that was not a child of zygote would not inherit the shared mapping of system libraries, and so would have to load its own unique copies into memory)
ioctl() is just another syscall, and only requires root if the access permissions to that fd (from its device file) does. Obviously that's the case for the ones you want to use, but others are unpriveleged. For example the majority of Android framework IPC is ultimately implemented with Binder ioctl's, and they are commonly used to control a network socket.