I wrote this testing code, and find that this program can always read the file successfully even after I canceled the read permission when running getchar()
.
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/types.h>
int main(){
int f = open("a.txt",O_RDONLY);
uint8_t data[200];
printf("Got %d from read", pread(f, (void *)data, 200, 0));
getchar();
printf("Got %d from read", pread(f, (void *)data, 200, 0));
}
This program printed
Got 9 from read
twice, even though I use chmod a-r a.txt
during pausing.
I'm pretty sure that I'm just a normal user and my process doesn't have CAP_DAC_OVERRIDE; why doesn't the second pread()
return any error?
My guess is, when doing read/write, kernel only check file permission on open file description, which is created with open()
, and don't change even I changed the file permission on the underlying filesystem.
Is my guess correct?
Extra question:
-
If I'm right about this, then how about mmaped regions?
-
Do kernel only check permissions recorded in page table when I
read/write/execute that mmaped region? -
Is that true inode data stored in filesystem is only used when
creating open file description and mmap region?
Best Answer
Yes, permissions are only checked at open time and recorded. So you can't write to a file descriptor that you opened for read-only access regardless of if you are potentially able to write to the file.
The kernel consults in-memory inodes rather than the ones stored in the filesystem. They differ in the reference count for open files, and mount points get the inode of the mounted file.
Same. (PROT_* flags passed to
mmap()
equivalent to O_RDWR / O_RDONLY / O_WRONLY flags passed toopen()
).I'm not sure when else it could check permissions recorded in the page table :-). As far as I understand your question: yes.
Inode permissions are also checked for metadata operations, e.g.
mkdir()
(and similarlyopen()
with O_CREAT).And don't forget
chdir()
, which is different from anyopen()
call. (Or at least, it is different from anyopen()
call on current Linux).I'm not sure about SELinux-specific permissions.