I have written a kernel module that creates a /proc file and reads values written into it from a user program,say user.c
Now I want restrict permissions for this /proc file.I have restricted permissions based on userid using the 'current' kernel variable by checking current->euid.
My question: Is there a way to restrict this based on the program too? i.e. only user.c should be able to write to this proc file and not any other program.I could not find any parameters in task_struct that would help me do this. Can you please suggest a way to do this?
In your proc writer implementation (that is, inside the kernel module) the best you can do is check the value of current (a struct task *), which holds (among other things) valuable fields such as comm (16-character argv[0]), pid, uid, etc (Basically, everything you see in /proc//status. You can also check the original exe name (like you see in /proc//exe), to see if it's a well known path. You can then return an error.
Caveat: Anyone could rename their opening process to be one of your "allowed" programs, if you go by "comm", and there are ways to defeat the "exe" protection. This will only make it slightly harder, but not impossible for someone to get around. A more comprehensive and stronger solution would require you to peek at the user mode memory of the program, which is possible, but too complicated for a brief answer.
Note: Permission parameters won't work, don't even bother. They go by classic UNIX ACL, which is u/g/o - so you can't filter by PID.
Related
Are there guidelines regarding how to share a Snakemake workflow among multiple users on the same data under Linux, or is the whole thing considered bad practice?
Let me explain in case it's not clear:
Suppose user A executes a workflow in directory dir/. Assume the workflow terminates successfully, and he/she then properly sets file/directory permissions recursively on all output and intermediate files and the .snakemake/ subdirectory for other users to read/write, of course.
User B subsequently navigates to dir/, adds input files to the workflow, then executes it. Can anything go wrong?
TL;DR: I'm asking about non-concurrent execution of the same workflow by distinct users on the same system, and on the same data on disk. Is Snakemake designed for such use cases?
It's possible to run snakemake --nolock which will prevent locking of the directory, so multiple runs can be made from inside the same directory. However, without lock, there's now an opening for errors due to concurrent runs trying to modify the same files. It's probably OK, if you are certain that this will be avoided, e.g. if you are in constant communication with another user about which files will be modified.
An alternative option is to create a third directory/path, and put all the data there. This way you can work from separate directories/path and avoid costly recomputes.
I would say that from the point of view of snakemake, and workflow management in general, it's ok for user B to add or update input files and re-run the pipeline. After all, one of the advantages of a workflow management system is to update results according to new input. The problem is that user A could find her results updated without being aware of it.
From the top of my head and without more detail this is what I would suggest. Make snakemake read the list of input files from a table (pandas comes in handy for this) or from some configuration file. Keep this sample sheet under version control (with git/github) together with the Snakefile and other source code.
When users update the working directory with new files, they will also need to update the sample sheet in order for snakemake to "see" the new input and other users will know about it via version control. I prefer this setup over dumping files in a directory and letting snakemake process whatever is in there.
Is it possible to execute a method as a different user in Linux (or SELinux specifically)? The programs that I have run in individual sandboxes, each with a different user and process id. I have a situation where I have to execute a branch of code as a different user and with different process id to prevent the access of the memory and disk space of the code that's spawning it.
If not possible, can you throw some light on how much of the kernel code has to be changed to achieve it? (I understand its subjective. Alternatively, if you can suggest what and how to go about it, that will be much helpful).
Protecting some resources from other codes executing on the same machine is precisely what lead to the process and UID invention.
If you are searching for a mechanism that looks like a simple function call, I would say it's impossible because it requires the memory to be shared between the caller and the callee. However, using fork/exec (or wrappers like system()) will give you some isolation as long as you deal with parameters/results using system objects like program parameters or pipes.
Although, the fact that *nix user is meant to protect processes from one-another, requires that an explicit relationship be built between two users to have one user act on behalf of the other.
Actually, you may want to:
define a sudoers policy which gives the right to your first user to run a command (or a particular command) as the second one.
use popen() (or system()) in your first program to call the less privileged code.
if any, pass the parameters and parse the result from stdout
As an extra, you may use the same binary for both executions, this way, all the code can be at the same location.
The title may seem trivial, but this isn't as easy as it sounds. You can't just check the permissions on the file, because the file may not exist, and you may have the necessary permissions to create it and then write to it. But only if you have write permissions on the directory, and maybe execute permissions, and maybe permissions for all the parent directories. Or maybe not. I'm not sure.
So, given a filename, what are all the cases that I need to account for in order to correctly test whether I could open and write to a file with that filename? This isn't specific to any one programming language. I just want the logic. But examples in real programming languages are welcome.
Such a test wouldn't necessarily be very useful -- you're just setting yourself up
for a race condition, if the file becomes unwriteable for some reason between your check
and the write attempt. (Some other process could change the permissions, move or delete
the parent directory, use up the last free space on the device, etc...)
I'd just go ahead and attempt the write, and be diligent about checking for errors
at each step (opening, each write attempt, closing) where an operation could conceivably
fail.
It depends on the owner of the process who runs the program, whether the owner has permissions to write to that directory or not. For example, apache running as www user may not be able to write to a directory owned by root and no permissions for other or group.
You may do it hit or trail way, like try creating the file to see if it's successful or not, in case it fails to catch the proper error code and like no permission or directory full and take corrective action.
You may programmatically check if the user has permissions to write into directory if the directory has space, if the file already exists etc. By using certain apis the system exposes and the language exposes, this much better approach taking care of cases rather than handling failure cases.
in my Mac software I need decrypt a file and, after I do my operations on it, I will remove it. My problem is: Where can I put this file? I don't want show it to the user.
The following API will give you a directory path that is "out of the way":
NSTemporaryDirectory();
Do you mean "decrypt a file in a place the user can't access?" Any place your app can write to, the user can see. And in theory, a user can access any bit or byte on a computer to which they have physical access.
There are obfuscations and such that reduce the odds a user will come across sensitive data, but they are meant for particular situations.
Can you tell us more about your end goal here? Are you trying to implement a DRM/copy protection scheme? Are you trying to prevent cheating in a game? Do you just not trust your user? What?
I think your best bet would be to keep it in memory.
If that's not an option, it depends on what you want to do with it. It's possible you can open a temporary file, and immediately delete it - keeping the valid filehandle open, but not keeping a link to it on the disk.
Another option, perhaps - can you get your secondary program to read from STDIN or a pipe? You could then decrypt the file and pass it's content via a pipe? Clearly, the more complex this process is, the more weak links it might have, but sometimes you just have to get things working.
I'm running a very computationally intensive scientific job that spits out results every now and then. The job is basically to just simulate the same thing a whole bunch of times, so it's divided among several computers, which use different OSes. I'd like to direct the output from all these instances to the same file, since all the computers can see the same filesystem via NFS/Samba. Here are the constraints:
Must allow safe concurrent appends. Must block if some other instance on another computer is currently appending to the file.
Performance does not count. I/O for each instance is only a few bytes per minute.
Simplicity does count. The whole point of this (besides pure curiosity) is so I can stop having every instance write to a different file and manually merging these files together.
Must not depend on the details of the filesystem. Must work with an unknown filesystem on an NFS or Samba mount.
The language I'm using is D, in case that matters. I've looked, there's nothing in the standard lib that seems to do this. Both D-specific and general, language-agnostic answers are fully acceptable and appreciated.
Over NFS you face some problems with client side caching and stale data. I have written an OS independent lock module to work over NFS before. The simple idea of creating a [datafile].lock file does not work well over NFS. The basic idea to work around it is to create a lock file [datafile].lock which if present means file is NOT locked and a process that wants to acquire a lock renames the file to a different name like [datafile].lock.[hostname].[pid]. The rename is an atomic enough operation that works well enough over NFS to guarantee exclusivity of the lock. The rest is basically a bunch of fail safe, loops, error checking and lock retrieval in case the process dies before releasing the lock and renaming the lock file back to [datafile].lock
The classic solution is to use a lock file, or more accurately a lock directory. On all common OSs creating a directory is an atomic operation so the routine is:
try to create a lock directory with a fixed name in a fixed location
if the create failed, wait a second or so and try again - repeat until success
write your data to the real data file
delete the lock directory
This has been used by applications such as CVS for many years across many platforms. The only problem occurs in the rare cases when your app crashes while writing and before removing the lock.
Why not just build a simple server which sits between the file and the other computers?
Then if you ever wanted to change the data format, you would only have to modify the server, and not all of the clients.
In my opinion building a server would be much easier than trying to use a Network file system.
Lock File with a twist
Like other answers have mentioned, the easiest method is to create a lock file in the same directory as the datafile.
Since you want to be able to access the same file over multiple PC the best solution I can think of is to just include the identifier of the machine currently writing to the data file.
So the sequence for writing to the data file would be:
Check if there is a lock file present
If there is a lock file, see if I'm the one owning it by checking that its content has my identifier.
If that's the case, just write to the data file then delete the lock file.
If that's not the case, just wait a second or a small random length of time and try the whole cycle again.
If there is no lock file, create one with my identifier and try the whole cycle again to avoid race condition (re-check that the lock file is really mine).
Along with the identifier, I would record a timestamp in the lock file and check whether it's older than a given timeout value.
If the timestamp is too old, then assume that the lock file is stale and just delete it as it would mea one of the PC writing to the data file may have crashed or its connection may have been lost.
Another solution
If you are in control the format of the data file, could be to reserve a structure at the beginning of the file to record whether it is locked or not.
If you just reserve a byte for this purpose, you could assume, for instance, that 00 would mean the data file isn't locked, and that other values would represent the identifier of the machine currently writing to it.
Issues with NFS
OK, I'm adding a few things because Jiri Klouda correctly pointed out that NFS uses client-side caching that will result in the actual lock file being in an undetermined state.
A few ways to solve this issue:
mount the NFS directory with the noac or sync options. This is easy but doesn't completely guarantee data consistency between client and server though so there may still be issues although in your case it may be OK.
Open the lock file or data file using the O_DIRECT, the O_SYNC or O_DSYNC attributes. This is supposed to disable caching altogether.
This will lower performance but will ensure consistency.
You may be able to use flock() to lock the data file but its implementation is spotty and you will need to check if your particular OS actually uses the NFS locking service. It may do nothing at all otherwise.
If the data file is locked, then another client opening it for writing will fail.
Oh yeah, and it doesn't seem to work on SMB shares, so it's probably best to just forget about it.
Don't use NFS and just use Samba instead: there is a good article on the subject and why NFS is probably not the best answer to your usage scenario.
You will also find in this article various methods for locking files.
Jiri's solution is also a good one.
Basically, if you want to keep things simple, don't use NFS for frequently-updated files that are shared amongst multiple machines.
Something different
Use a small database server to save your data into and bypass the NFS/SMB locking issues altogether or keep your current multiple data files system and just write a small utility to concatenate the results.
It may still be the safest and simplest solution to your problem.
I don't know D, but I thing using a mutex file to do the jobe might work. Here's some pseudo-code you might find useful:
do {
// Try to create a new file to use as mutex.
// If it's already created, it will throw some kind of error.
mutex = create_file_for_writing('lock_file');
} while (mutex == null);
// Open your log file and write results
log_file = open_file_for_reading('the_log_file');
write(log_file, data);
close_file(log_file);
close_file(mutex);
// Free mutex and allow other processes to create the same file.
delete_file(mutex);
So, all processes will try to create the mutex file but only the one who wins will be able to continue. Once you write your output, close and delete the mutex so other processes can do the same.