LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 07-19-2011, 09:16 AM   #1
pulkit_m
LQ Newbie
 
Registered: Jul 2011
Posts: 6

Rep: Reputation: Disabled
How to detect opening of a file using a C program?


Can anyone tell me how to detect if a file is being opened by any application so that i can block it just before opening it...

Actually i am working on android and using iNotify in JNI to detect the OPENING of a file...but the file is getting opened before the iNotify detects it..and therefore its displaying the contents of the file unmodified ..
The actual requirement is that if anyone is trying to open the file it should be modified by my program and then the modified file should be opened.
 
Old 07-19-2011, 09:32 AM   #2
ButterflyMelissa
Senior Member
 
Registered: Nov 2007
Location: Somewhere on my hard drive...
Distribution: Manjaro
Posts: 2,766
Blog Entries: 23

Rep: Reputation: 411Reputation: 411Reputation: 411Reputation: 411Reputation: 411
I'd write a wrapper around the opening action. I wonder if you could use dazuko for that...
 
Old 07-19-2011, 09:55 AM   #3
bigearsbilly
Senior Member
 
Registered: Mar 2004
Location: england
Distribution: Mint, Armbian, NetBSD, Puppy, Raspbian
Posts: 3,515

Rep: Reputation: 239Reputation: 239Reputation: 239
can you make the file a pipe?
you have a process waiting to write the pipe
which activates when the reader comes along?
 
Old 07-19-2011, 10:16 AM   #4
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Get a lease on the target file using fcntl(), and your process will receive a signal (SIGIO by default) when another process tries to open the file. The process must either be running as root, or as the same user as the owner of the file, for the lease to be granted. You have a limited time to yield the lease to let the other process continue opening the file, or the kernel will break the lease anyway.

If you have a number of files, use the Audit subsystem to filter all related syscalls. Your application then works similar to an audit daemon, and will need superuser privileges in practice. I'm not sure if the android kernels have the audit subsystem enabled or not; it is if CONFIG_AUDIT and CONFIG_AUDITSYSCALL are enabled in the kernel config.
 
Old 07-20-2011, 02:25 AM   #5
pulkit_m
LQ Newbie
 
Registered: Jul 2011
Posts: 6

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by Nominal Animal View Post
Get a lease on the target file using fcntl(), and your process will receive a signal (SIGIO by default) when another process tries to open the file. The process must either be running as root, or as the same user as the owner of the file, for the lease to be granted. You have a limited time to yield the lease to let the other process continue opening the file, or the kernel will break the lease anyway.

If you have a number of files, use the Audit subsystem to filter all related syscalls. Your application then works similar to an audit daemon, and will need superuser privileges in practice. I'm not sure if the android kernels have the audit subsystem enabled or not; it is if CONFIG_AUDIT and CONFIG_AUDITSYSCALL are enabled in the kernel config.
-------------------------------------------------------------------------------------------------------------------------
Thanx for the answer!!
Using F_GETLEASE with fcntl(int fd, int cmd,...) needs file desriptor and we cannot get fd without opening the file...!!
My requirement is that the file should be truncated by my program before getting opened..

Last edited by pulkit_m; 07-20-2011 at 03:39 AM.
 
Old 07-20-2011, 10:58 AM   #6
Reuti
Senior Member
 
Registered: Dec 2004
Location: Marburg, Germany
Distribution: openSUSE 15.2
Posts: 1,339

Rep: Reputation: 260Reputation: 260Reputation: 260
Is the application dynamically linked or are you providing the application and could provide a version using the mentioned wrapper? You could load a library beforehand by defining it in LD_PRELOAD and replace the call to fopen with another function, which can check the filename first and deny the access or call the real function. Yes, it’s not foolproof, but maybe an option.
 
Old 07-20-2011, 02:30 PM   #7
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
If you have a recent enough kernel (2.6.37 or newer), you can use the fanotify interface instead. (Check for CONFIG_FANOTIFY in your kernel configuration.)

Here is a working example you can try. The fanotify interface was originally intended for use by virus scanners, but it should match your needs also. It is not just a notification like inotify (although both now use the same kernel code); it intercepts and either allows or disallows the access. In your case, you can just truncate the file before allowing a open-for-write to proceed.
 
Old 07-21-2011, 12:25 AM   #8
pulkit_m
LQ Newbie
 
Registered: Jul 2011
Posts: 6

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by Nominal Animal View Post
If you have a recent enough kernel (2.6.37 or newer), you can use the fanotify interface instead. (Check for CONFIG_FANOTIFY in your kernel configuration.)

Here is a working example you can try. The fanotify interface was originally intended for use by virus scanners, but it should match your needs also. It is not just a notification like inotify (although both now use the same kernel code); it intercepts and either allows or disallows the access. In your case, you can just truncate the file before allowing a open-for-write to proceed.
Unfortunately I am working on android 2.1 with kernel 2.6.29...so fanotify won't work!!
 
Old 07-21-2011, 04:29 AM   #9
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
The real issue here is that notification is not enough. You need to intercept all attempts to truncate or open the files for writing.

I'm assuming you want to let any process read the contents, but truncate the file whenever someone opens it for writing. If you wanted to truncate the files whenever anyone opens it at all, you can just unlink() the file right now, and create an empty file in its place. Any process still having the old file open can keep reading and writing to their file; the changes are just going to be discarded when the file is closed. If more than one process has the old file open, they will still see each others' changes, too.

In later kernels, fanotify would have worked well for this scenario.

You can set the LD_PRELOAD environment variable to point to a custom dynamic library, which overrides the file open functions that might have to truncate the file before returning to the actual program. Here is an example. There are a number of functions to override (at least fopen(), fopen64(), freopen(), freopen64(), open(), openat(), open64(), openat64(), __open_2(), __open64_2(), __openat_2(), __openat64_2()) from the C library, but they're most just variants of each other (with compatibility details). The library is trivial to create. If the target is one of the special files and the file open mode warrants it, the override function truncates the target file automatically.

You could also write a filesystem in user space (FUSE). The fusexmp example should be very close to what you'd need; just add the truncation logic. You can bind-mount files and directories on your filesystem to anywhere in the directory tree, so they really can exist anywhere in the directory tree. If your kernel config has CONFIG_FUSE_FS=y, then you can use FUSE. (Based on quick Googling, there seem to be other FUSEs written for Android too.)

If kernel modules are not out of question, it should not be too difficult to write a suitable Linux Security Module. After all, it only needs to intercept open() and openat() calls (since fopen() et cetera is implemented in the C library on top of those). If the mode is O_RDWR or O_WRONLY, and the filename matches (you can do a lookup or fstat() and check the device and inode numbers against a table), truncate the file (via ftruncate()).

Opening the files read-only, and getting a read lease using fcntl() (to catch file modification attempts like opening for read-write or write-only), and keeping the files open does work, but you cannot reliably truncate a file before the opener proceeds. I just tested this with a small C program. The problem is that the truncate(), ftruncate(), and open(O_TRUNC) will error with EAGAIN/EWOULDBLOCK until the lease is released, even if the same process owns the lease. When you release the lease, all openers can immediately proceed, and may be able to access the file contents before the file is truncated. Things like appending (open(O_APPEND)) may cause the old file to be replaced by zero bytes (NULs), with the appended data starting at the old size.

Mandatory file locks only block file reads and/or writes, not opening them. Even if you used a mandatory write lock, a writer would eventually write wherever they originally intended. If the file was truncated in the mean time, you just get a lot of zero bytes before that point. Also, you would need to add the mand mount option to /etc/fstab for each filesystem that may contain such files, and clear the group execute bit but set the set-group-ID bit (g-x,g+s) for each such file. Messy.

In Linux, the lease program can unlink() the file before the open() succeeds, and even replace it with a new file, but the open() will still continue with the old file, old length, and old contents. It just won't be attached to the same file name anymore. All changes will of course be lost, as the file will not be accessible by the old name anymore. (In Linux and Unix, you can unlink() an open file, but keep reading it and writing to it. Although it won't show up in file lists, the data is still stored on the disk normally, and all processes that already had it open at unlink() time can still see all changes to it. They are traditionally used for temporary files, because they will vanish when the program exists. They can be recovered by other processes belonging to the same user, by reading /proc/pid/fd/descriptor.)

Hope this helps.

Last edited by Nominal Animal; 07-21-2011 at 04:31 AM.
 
1 members found this post helpful.
Old 07-21-2011, 09:36 AM   #10
pulkit_m
LQ Newbie
 
Registered: Jul 2011
Posts: 6

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by Nominal Animal View Post
The real issue here is that notification is not enough. You need to intercept all attempts to truncate or open the files for writing.

I'm assuming you want to let any process read the contents, but truncate the file whenever someone opens it for writing. If you wanted to truncate the files whenever anyone opens it at all, you can just unlink() the file right now, and create an empty file in its place. Any process still having the old file open can keep reading and writing to their file; the changes are just going to be discarded when the file is closed. If more than one process has the old file open, they will still see each others' changes, too.

In later kernels, fanotify would have worked well for this scenario.

You can set the LD_PRELOAD environment variable to point to a custom dynamic library, which overrides the file open functions that might have to truncate the file before returning to the actual program. Here is an example. There are a number of functions to override (at least fopen(), fopen64(), freopen(), freopen64(), open(), openat(), open64(), openat64(), __open_2(), __open64_2(), __openat_2(), __openat64_2()) from the C library, but they're most just variants of each other (with compatibility details). The library is trivial to create. If the target is one of the special files and the file open mode warrants it, the override function truncates the target file automatically.

You could also write a filesystem in user space (FUSE). The fusexmp example should be very close to what you'd need; just add the truncation logic. You can bind-mount files and directories on your filesystem to anywhere in the directory tree, so they really can exist anywhere in the directory tree. If your kernel config has CONFIG_FUSE_FS=y, then you can use FUSE. (Based on quick Googling, there seem to be other FUSEs written for Android too.)

If kernel modules are not out of question, it should not be too difficult to write a suitable Linux Security Module. After all, it only needs to intercept open() and openat() calls (since fopen() et cetera is implemented in the C library on top of those). If the mode is O_RDWR or O_WRONLY, and the filename matches (you can do a lookup or fstat() and check the device and inode numbers against a table), truncate the file (via ftruncate()).

Opening the files read-only, and getting a read lease using fcntl() (to catch file modification attempts like opening for read-write or write-only), and keeping the files open does work, but you cannot reliably truncate a file before the opener proceeds. I just tested this with a small C program. The problem is that the truncate(), ftruncate(), and open(O_TRUNC) will error with EAGAIN/EWOULDBLOCK until the lease is released, even if the same process owns the lease. When you release the lease, all openers can immediately proceed, and may be able to access the file contents before the file is truncated. Things like appending (open(O_APPEND)) may cause the old file to be replaced by zero bytes (NULs), with the appended data starting at the old size.

Mandatory file locks only block file reads and/or writes, not opening them. Even if you used a mandatory write lock, a writer would eventually write wherever they originally intended. If the file was truncated in the mean time, you just get a lot of zero bytes before that point. Also, you would need to add the mand mount option to /etc/fstab for each filesystem that may contain such files, and clear the group execute bit but set the set-group-ID bit (g-x,g+s) for each such file. Messy.

In Linux, the lease program can unlink() the file before the open() succeeds, and even replace it with a new file, but the open() will still continue with the old file, old length, and old contents. It just won't be attached to the same file name anymore. All changes will of course be lost, as the file will not be accessible by the old name anymore. (In Linux and Unix, you can unlink() an open file, but keep reading it and writing to it. Although it won't show up in file lists, the data is still stored on the disk normally, and all processes that already had it open at unlink() time can still see all changes to it. They are traditionally used for temporary files, because they will vanish when the program exists. They can be recovered by other processes belonging to the same user, by reading /proc/pid/fd/descriptor.)

Hope this helps.
Thanx for the reply!!
 
Old 07-21-2011, 02:10 PM   #11
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Forgot to mention:

If the modifications will never change the file size -- for example, if you only modify some fixed-length string or value, like a time stamp --, you can achieve this with fcntl() leases, quite reliably.

(When the controlling program is run as a normal user, it can only do that for files owned by the same user. If it is run as root, it can do that for all files. The maximum number of files the controlling program can keep open is pretty big, sysconf(_SC_OPEN_MAX), usually 1024. So you should be able to keep leases on maybe a thousand files, I think.)

If you can describe the modifications, I could modify the GNU C program I wrote to investigate the issue, to show you exactly how it can be done.

Last edited by Nominal Animal; 07-21-2011 at 02:17 PM.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Long file names on Linux file server jumbled when opening on 16-bit PC program. brandonhughesj General 3 03-04-2009 07:53 AM
Text file default opening program - have set, and it still ignores me! sandaili Linux - Newbie 1 09-09-2008 02:12 PM
Program opening off screen garf12 Linux - Newbie 1 03-06-2004 08:58 PM
Program Not opening Neo22589 Linux - Software 22 03-10-2003 10:32 PM
opening a d/l program purelific Linux - Newbie 4 03-31-2002 11:10 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 08:44 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration