> The problem with an ioctl is that ioctls are not namespaced and so a buggy userspace program might end up being tricked into killing a process (if the ioctl overlaps).

I am not sure what is the threat model here -- it If we have a buggy userspace program which can be tricked into opening arbitrary files by an un-authorized user, it is already game over. What you do after is irrelevant -- the writes would damage the system, reads would leak info. The fact that they won't be able to kill processes does not help much if they could overwrite /sbin/init instead. As Tycho Andersen said in [0], "It seems completely theoretical to me."

> ioctl also doesn't have exceptionally sane error reporting, especially when we're comparing it to syscalls.

I could be wrong here, but I thought that most ioctl's do not generally cause the program to crash, they just fail with meaningful error code. On the other hand, syscalls will cause the process to segfault.

>> I am literally two characters away from invoking all sorts of dangerous commands like "kill all processes", "shutdown machine" and so on.

> Can you explain what you mean?

Sure, let's say this goes in, and I want to use it ASAP. Libc takes ages to update, so I have no wrappers. I am using Python. What are my options?

Option 1: File

f = open('/proc/%d/kill' % pid, 'w')
...
f.write("9")
f.close()

What kind of mistakes I can make? I can mistype '/proc/%d/kill' format string, I can write() the wrong thing.

What is the worst that could happen? I will get nice exception (like "File not found" during open or "Invalid operation") during close. In the the worst case, I write to "/proc/%d/mem" and damage the process instead, but this not very likely -- this typo is easy to spot. And it will only affect the process I want killed anyway.

Summary: Please give me that option!

Option 2: ioctl

PSKILLCTL = (0x80046A01 if sys.bits == 32 else 0x80046E01)
f = open('/proc/%d' % pid, 'w')
...
fcntl.ioctl(f, PSKILLCTL, 9)
f.close()

What kind of mistakes I can make? I can get the constant value wrong, I can get ioctl args wrong (maybe it needs pointer to integer)

What is the worst that could happen? ioctl will succeed but will do the wrong thing, i.e. not kill the process. Luckily, there are very few ioctls which /proc/%d supports, and none of them will have permanent effect. Yeah, maybe this will switch to non-blocking mode or we will get aio enabled on the handle -- who cares, we will close it right away.

Summary: meh, finding ioctl codes are annoying with all the macros but I can live with this.

Option 3: syscall

__NR_KILL_VIA_PID = (382 if sys.bits == 32 else 731)
libc = ctypes.CDLL(None)
f = open('/proc/%d' % pid, 'w')
...
libc.syscall(__NR_KILL_VIA_PID, f.fileno(), 9)
f.close()

What kind of mistakes I can make? I can get the constant value wrong, I can get syscall args wrong (maybe it needs a struct)

What is the worst that could happen? I reboot machine (sys_shutdown). I kill all processes on this tty (sys_vhangup). I mess up my entire process in a subtle way (sys_vfork, sys_modify_ldt). I break many other processes on the machine (sys_sethostname).

Summary: I really want to make sure I get this right. I feel this is like shaving with straight edge -- don't make mistakes.

Hopefully, I have explained my point. Note that this is from POV of python programmer -- I know that from the C land, it all looks different. But if we have Python-only packages, or a shell scripts, adding a new C program is a significant burden.

Could you elaborate why do you think writing to procfile will be worse? Especially if we already have writable /proc/%d/mem.

[0] https://lwn.net/ml/linux-kernel/20181119223954.GA4992@cisco/