0

Suppose I have implemented file_operations such as read, write, open, release, flush etc. and I wrote userspace application which calls these routines. In character driver, Userspace application communicate through /dev interface node.

for example - (/dev/diagnostics_1000_1-4:2.1) and I am bit surprise another application call our driver routines and we don't have control on those application.

Do they really call flush system call which directly/indirectly mapped to our function pointer ".flush"?

Snippet below -

[Wed Aug 16 23:07:02 2022] UserspaceOpen:448 PID = 291098, Pname = MyApp
[Wed Aug 16 23:07:02 2022] Diagnostics_1000: UserspaceOpen:461  - Interface is 3
....
[Tue Aug 16 23:07:38 2022] UserspaceRead:1182 PID = 25460, Pname = MyApp
[Tue Aug 16 23:07:38 2022] UserspaceFlush:622 PID = 25470, Pname = lsb_release
[Tue Aug 16 23:07:38 2022] UserspaceFlush:631 Wrong process:: PID = 25470, Pname = lsb_release, and pDev->pName = MyApp
[Tue Aug 16 23:07:38 2022] UserspaceFlush:622 PID = 25469, Pname = sh
[Tue Aug 16 23:07:38 2022] UserspaceFlush:631 Wrong process:: PID = 25469, Pname = sh, and pDev->pName = MyApp
[Tue Aug 16 23:07:38 2022] UserspaceWrite:1394  PID = 25463, Pname = MyApp
[Tue Aug 16 23:07:38 2022] UserspaceWrite_bulk_callback:1241  PID = 25428, Pname = VizCompositorTh
[Tue Aug 16 23:07:39 2022] UserspaceRead:1182 PID = 25460, Pname = MyApp

You can see that MyApp opens the interface "diagnostics_1000_1-4:2.1" but UserspaceFlush driver routines also called by lsb_release and sh process in the middle of operation and breaking the code flow. Though lsb_release and sh process haven't open the interface but somehow they triggered Flush operation.

We fixed the code by comparing the process name and continues if it matches otherwise return error code.

UserspaceFlush:631 Wrong process:: PID = 25469, Pname = sh, and pDev->pName = MyApp

Is there any design flaw? I want to understand what I am missing conceptually and how we can make it secure.

How to make sure that flush routine get called by the same process always i.e MyApp and file descriptor get closed by same application i.e MyApp because files actually opened by MyApp only.

shashank arora
  • 1,176
  • 11
  • 14
  • 1
    Aren't those processes calling `sync`? – dimich Aug 17 '22 at 15:59
  • @dimich, Yes, calls were synchronous. Do you have any idea?? – shashank arora Aug 17 '22 at 16:43
  • 3
    Is MyApp calling `system()` to run commands, or something similar (such as `fork()` and `exec()`)? You may be seeing the effect of inherited file descriptors getting closed. – Ian Abbott Aug 17 '22 at 16:45
  • If you make your device look like a disk then it should act like a disk. As @dimich points out, a `sync` command will send a flush command to all disks. This is typical when about to power off the system. – stark Aug 17 '22 at 16:51
  • @stark OP mentioned "character driver" though. I'm not sure if that would be affected by `sync`. Maybe for tape drives? – Ian Abbott Aug 17 '22 at 16:56
  • I missed seeing that in the shown code – stark Aug 17 '22 at 16:58
  • I guess `UserspaceWrite_bulk_callback` is being called asynchronously and could be called from an arbitrarily random process context. – Ian Abbott Aug 17 '22 at 17:04
  • @shashankarora i mean they probably call `sync()` system call to flush all buffers including yours. Does `UserspaceFlush` occures after you run `sync` in terminal? – dimich Aug 17 '22 at 17:17
  • 1
    None process may call a function from `file_operations` without opening that file (via `.open`) or obtaining a duplicate of the file descriptor via `fork` (clone) mechanism. If you observe the opposite behavior.. then something wrong with your observations, that is with **your code** (user and/or kernel one). – Tsyvarev Aug 17 '22 at 17:56
  • @IanAbbott, might possible, MyApp application is too big and I am not the owner of that app. I need to check with app owner. Can you describe more? – shashank arora Aug 18 '22 at 17:27
  • 2
    "Can you describe more?" - The `flush` file operation (if set) is called every time a file descriptor associated with the open file description is closed. File descriptors are duplicated into child processes by `fork()`. Those copied file descriptors will be closed at some point, either before or after the child process calls one of the `exec` family of functions. If they are closed after calling `exec` then the name you see in the debug log will be the name of the program spawned as a child process by MyApp. – Ian Abbott Aug 18 '22 at 18:18
  • The short answer to the question in tittle: **yes**. The Linux kernel has many ABIs, IOCTL is only one of many. – 0andriy Aug 20 '22 at 17:04
  • @IanAbbott, Yes you are right. Hats off to you. This is exactly what is happening. I found out when I ran MyApp with strace utility. calling "execve("/bin/sh", ["sh", "-c", "lsb_release -d -s"]" and copied file descriptor gets closed by spawned child process which in result triggers flush operation of driver. – shashank arora Sep 09 '22 at 09:40
  • @IanAbbott, it is a design flaw. What exactly we should use to clear read/notify lists operations ? – shashank arora Sep 09 '22 at 20:00
  • You are probably limited to using the system calls that MyApp is already calling and whether those occur close to where you expect the `flush` file operation to occur. Possibilities may include the `fsync()` or `fdatasync()` system calls that are both handled by the `fsync` file operation. – Ian Abbott Sep 12 '22 at 09:50
  • @IanAbbott, how to make sure that flush gets called by MyApp always (i.e main process who actually opened the file, get the file descriptor which is MyApp in our case) and get the file descriptor closed by MyApp only? – shashank arora Nov 23 '22 at 12:43
  • 1
    @shashankarora Your application can set the `O_CLOEXEC` flag on the file during `open()` or by adding the letter `e` to the file mode during `fopen()` (non-standard, but supported in glibc), or by setting the flag on the file descriptor later with `fcntl()`'s `F_SETFL` operation before spawning the child program. You will still get the `flush` system call on the file from the child process before it executes the child program, but the child program won't be able to do anything nasty to the file because its copy of the file descriptor will no longer be valid. – Ian Abbott Nov 23 '22 at 13:30
  • Yes you were right @IanAbbott. thanks for you help – shashank arora Jul 26 '23 at 11:52

0 Answers0