How to Restrict Access to Certain Files for a Certain Process

Can I restrict access to certain files for a certain process?

You can use chroot to set the root directory of your process tree. This means however, that all dependencies of that process must be available in it's new root.

There are a number of packages that can help you setup chroot-environments for your needs. Google is your friend ;)


Some pointers on building a chroot environment

When builing a chroot for some program or daemon you have to have a complete environment for the program you want to chroot. This means you have to provide a minimum system in a directory. That might contain:

  • A shell and some shell utilities, or a variant of busybox. (this encompasses the next step too, if you aren't planning on deploying one single static executable that is).
  • Libc and other dependent shared libraries.
    • You need to check shared library dependencies using ldd or objdump. Every library that appears has to be in your private root directory. This step might be repeated several times for every executable and library you need. Note that some libraries, which are linked explicitly at runtime using dlopen need to be checked separately.
  • Depending on what you plan to chroot a minimal /dev tree.
    • If you plan to chroot a daemon process this may well be needing some minimal files in /dev such as random or zero. You can create those with the mknod command. Please refer to the mknod documentation, as well as the linux documentation on which major/minor numbers which device should have.
  • Also depending on what you plan to chroot is a minimal /etc. Files needed therein are:
    • A minimal passwd and shadow (not your system passwd/shadow).
    • A minimal mtab containing /.
    • A minimal group (again, not your system group file).

You have to start somewhere, so it's best to start with the prerequisites for you program. Refer to your documentation for specifics.

Restrict Access To Certain File From Other Programs And Users While Running

You can change the last parameter from System.IO.FileShare.ReadWrite to System.IO.FileShare.None.

That locks the file in location exclusively as long as this stream is open and no other app can read, modify or delete that file except your own FileStream.

In fact this isn't only true for other apps - even your own app can't open another FileStream of that file. So keep it open as long as you need but don't forget to correctly dispose the FileStream after use.

On Windows, how to restrict access to a folder, sub folder and files by only some applications (not users)

The Windows security model is per-user, not per-application. So there is no built-in way to restrict access to files based on which application is making the request.

The proper solution is for a server program (either running on an actual server, or as a system service on the local machine) to have exclusive access to the files (which works because the server program will be running as a different user) and for the client application (the application the end users run) to make all requests via the server. The server can then vet the requests to make sure they are not destructive before carrying them out.

Possible ad-hoc solutions would include a system service that hands out access to the files to your application (via handle duplication) or a file system filter driver. These approaches could be bypassed easily enough, but might be adequate against common-variety viruses that are not targeting your application specifically.

How to block access to a file to other functions within same process?

It sounds like you're injecting a library into a process that has a different constrained memory model and your library is incompatible. You could try using dup2() to move your own handles to really high values and hope it works.

Prevent other processes and users from accessing a file

You can do it changing access privileges BUT I strongly suggest to simply keep them open (just be careful to flush the stream after each batch write).

In the first part I try to address directly your question ("How to prevent...") but in the second part I tried to outline a different approach (make your application resilient: keep a backup).

How to prevent...

Assuming that you're running on Windows to avoid other users to mess with them you should:

  • Set the hidden attribute. By default hidden files are hidden and many users won't even see them. If you can do it at directory level then even better.

  • Change ACL to deny Full access to Users and Administrators group. Better if you cherry pick and just leave Read permissions. By default Windows pick the most restrictive policy, even when an user belongs to two group, then this will effectively stop everyone to write that file (if you deny also Read permissions then they won't even be able to see its content but see later).

  • Create a special group (with the required permissions, and only those) with one single user. Be sure that user isn't automatically added to the Users group.
  • Change your application to impersonate that user when writing those files. If you left the Read permissions in-place then code for reading isn't affected.

Don't forget to check with different versions and editions of Windows (HomeUsers keep bouncing in my mind.) If your application is a Windows Service then things may be slightly easier, see eryksun's comment.

You can experiment with all these things simply using Windows Explorer, just find the right balance but don't forget that each single installation is a different world and only God knows what the environment is (but he doesn't know why).

Few obvious drawbacks:

  • An administrator can ALWAYS do what he wants then they may find those files and revert permissions. I think (I'm not sure) that System Installer has some special privileges to prevent this but I'm not sure (and I can't imagine how to do it).
  • Installation is way more complicate (and you will need one if you don't have). You may do it when application is executed first time but then you will need administrative privileges (just once but probably worse.)
  • Your code is more complex.
  • More setup means more things that may go wrong, balance this with the effort of your technical support team.
  • Updates (and tech support job) will be more complicate.
  • Users with certain privileges won't be affected (see another comment) but this is really a good thing and you shouldn't every try to circumvent it.

Backup is the key!

Don't forget that if they really want to break your application then they will just delete the application directory...

I think, but I don't know your specific use-case, that maybe you're approaching the problem from the wrong angle. If what you want to prevent the user to corrupt your data files (intentionally or not) then what you need is a BACKUP. Save a copy in a different location each time your write them, mark it as hidden and live happy. If they're not too big you may even save content directly inside Windows Registry. For encrypted/hashed/checksummed files your application can easily detect when they're broken or missing: just restore backup and you're done.

How to restrict write access to a Linux directory by process attributes?

Run a local logging daemon as root. Have it listen on an Unix domain socket (typically /var/run/my-logger.socket or similar).

Write a simple logging library, where event messages are sent to the locally running daemon via the Unix domain socket. With each event, also send the process credentials via an ancillary message. See man 7 unix for details.

When the local logging daemon receives a message, it checks for the ancillary message, and if none, discards the message. The uid and gid of the credentials tell exactly who is running the process that has sent the logging request; these are verified by the kernel itself, so they cannot be spoofed (unless you have root privileges).

Here comes the clever bit: the daemon also checks the PID in the credentials, and based on its value, /proc/PID/exe. It is a symlink to the actual process binary being executed by the process that send the message, something the user cannot fake. To be able to fake a message, they'd have to overwrite the actual binaries with their own, and that should require root privileges.

(There is a possible race condition: a user may craft a special program that does the same, and immediately exec()s a binary they know to be allowed. To avoid that race, you may need to have the daemon respond after checking the credentials, and the logging client send another message (with credentials), so the daemon can verify the credentials are still the same, and the /proc/PID/exe symlink has not changed. I would personally use this to check the message veracity (by the logger asking for confirmation for the event, with a random cookie, and have the requester respond with both the checksum and the cookie whether the event checksum is correct. Including the random cookie should make it impossible to stuff the confirmation in the socket queue before exec().)

With the pid you can do also further checks. For example, you can trace the process parentage to see how the human user has connected by tracking parents till you detect a login via ssh or console. It's a bit tedious, since you'll need to parse /proc/PID/stat or /proc/PID/status files, and nonportable. OSX and BSDs have a sysctl call you can use to find out the parent process ID, so you can make it portable by writing a platform-specific parent_process_of(pid_t pid) function.

This approach will make sure your logging daemon knows exactly 1) which executable the logging request came from, and 2) which user (and how connected, if you do the process tracing) ran the command.

As the local logging daemon is running as root, it can log the events to file(s) in a root-only directory, and/or forward the messages to a remote machine.

Obviously, this is not exactly lightweight, but assuming you have less than a dozen events per second, the logging overhead should be completely neglible.



Related Topics



Leave a reply



Submit