2

I am running a process (Process A) which opens a file with read only access mode. Then it pauses, causing the process to stay running and keep the file descriptor open. Later, if any of the below is possible, it will resume after some time and continue operation.

I want to know if any of these are possible:

  1. Can we create another process (Process B) with superuser privileges, which can access Process A's open file descriptor and change its access mode to read and write ?
  2. Can we modify the file descriptor of Process A, from within the process (I mean within its code) from read only to read and write?
  3. Can I create a loadable kernel module that access the process A using its process ID (PID) and check for open file descriptors and change their permissions to read and write?

I have searched the forums countless number of times, but didn't find anything specific to my problem. I also found out about the fcntl() system call. But this doesn't allow us to modify the status flag of a file descriptor.

  • The real question is, why do you want this? Sounds like a case of the [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) – davmac Nov 07 '16 at 16:05
  • Possible duplicate of [Reopen a file descriptor with another access?](https://stackoverflow.com/questions/14514997/reopen-a-file-descriptor-with-another-access) Anything is possible with kernel modules :-) – Ciro Santilli OurBigBook.com Sep 19 '17 at 10:47

2 Answers2

1

You can't. Permissions are locked in place at the time when a file descriptor is opened and it would be almost impossible to ensure the security of the system if they could be changed at run time. You could make a kernel module that changes this, but it would pretty much be a death sentence to the stability and security of the system.

What you can do and what is normally done is to open the file again with different permissions and replace the file descriptor with dup2.

Art
  • 19,807
  • 1
  • 34
  • 60
1

3 first, since it's easiest: Can it be done in the kernel? Certainly … in theory, you can do “almost anything” there.

Both #2 and #1 come down to the question as to whether the file descriptor is re-openable.

In the most common case — the fd refers to a regular file stream in the local filesystem, the pathname of which has a directory link to which has not been altered — you can simply open the same pathname from another process. EG: If A opens /home/user/foo.log read-only, then either A or B can simply open the same pathname read-write in future.

Since you're asking, I'll assume it's not that easy. Perhaps the pathname may have been altered (eg, the file may have been unlinked), or perhaps the fd is a reference to another type of stream, like a shell pipeline, FIFO, or network socket connection.

As you probably noticed, fcntl does not allow escalation of privileges:

F_SETFL (int)

Set the file status flags to the value specified by arg. File access mode (O_RDONLY, O_WRONLY, O_RDWR) and file creation flags (i.e., O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC) in arg are ignored.

This is, of course, a security precaution to protect against escalation of privileges in a process that may have opened the file under temporarily elevated or changed permissions.

However, it seems that you may have a chance to open a new, duplicate stream based upon a pathname if you know the file descriptor number and the process ID of Process A.

The /proc filesystem contains virtual file entries which represent open streams. Under /proc/ pid /fd/ fd you can find a pathname to the currently-open stream. Given sufficient permissions, you can open that stream.

reader.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int
main (int argc, char** argv) {
  FILE* f = fopen("/tmp/foo", "r"); 
  while(1) {
    sleep(10);
  }
}

writer.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int
main (int argc, char** argv) {
  /* sane PID passed in */
  if (2 != argc) exit(1);
  if (5 > strlen(argv[1])) exit(2);
  for(size_t ci = 0; argv[ci]; ++ci) {
    if (! ( ('0' <= argv[1][ci]) && (argv[1][ci] <= '9') ) ) exit(3);
  }

  /* note we know FD=3 so it's hard-coded */
  char path[100];
  int n = snprintf(path, 99, "/proc/%s/fd/3", argv[1]);
  if (n < 0) exit (4);

  FILE* f = fopen(path, "rw+");
  fprintf(f, "written\n");
  exit(0);
}

shell test

⇒ cc reader.c -o reader
⇒ cc writer.c -o writer
⇒ echo XXXXXXXXXXXX > /tmp/foo
⇒ cat /tmp/foo
XXXXXXXXXXXX
⇒ ./reader &
[1] 20709
⇒ ./writer 20709
⇒ cat /tmp/foo
written
XXXX
BRPocock
  • 13,638
  • 3
  • 31
  • 50
  • This is a very good explanation but my goal is something else. I want to modify the access permission given as a capability on a open file descriptor from read only to read and write. – sensei374121 Nov 09 '16 at 20:34