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

We've got a situation where it would be advantageous to limit write access to a logging directory to a specific subset of user processes. These particular processes (say, for example, telnet and the like) have been modified by us to generate a logging record whenever a significant user action takes place (like a remote connection, etc). What we do not want is for the user to manually create these records by copying and editing existing logging records.
syslog comes close but still allows the user to generate spurious records, SELinux seems plausible but has a terrible reputation of being an unmanageable beast.
Any insight is appreciated.

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.

Generally there's two ways of doing this. One, run these processes as root and write protect the directory (mentioned mainly for historical purposes). Then no one but root can write there. The second, and more secure is to run them as another user (not root) and give that user, but no one else, write access to the log directory.

The approach we went with was to use a setuid binary to allow write access to the logging directory, the binary was executable by all users but would only allow a log record to be written if the parent process path as defined by /proc/$PPID/exe matched the subset of modified binary paths we placed on the system.

Related

Restarting inetd should effect instances of all inetd controlled processes

When I am sending HUP signal to inetd so that it rereads the new inetd.conf file, what I want is, the processes controlled by the inetd process should also restart, so that it can read the new command line parameters added to the inetd.conf file as part of the change.
I know I can search for the running process and kill it, but is there a standard way to do this. I could not find anything over the Internet.
The standard inetd included in NetBSD does not manage the processes it starts (except for single-threaded services, i.e. those with "wait" flags) -- it just starts them. Each child process services one active connection and then exits when done (i.e. when the connection is closed). In the general case it would be very unwise to kill such processes early without very good reason -- for example consider the case where your current login session (where you tell inetd to reload) was opened to a service controlled by inetd (e.g. sshd).
If you really want to kill processes handling active current connections then you will have to write some helper script of your own to do that, though perhaps pkill will suffice.

How to update internal state of nginx' module runtime?

Lets suppose I wish to write a nginx module that blocks clients by IP.
In order to do so, on initialization stage i read a file with IP addresses
that I have to block (black list) and store it in module's context.
Now I wish to update the black list without restarting nginx.
One of the possible solutions, is to add a handler on specific location.
e.g. if uri "/block/1.2.3.4" requested, my handler adds ip address 1.2.3.4 to the black list.
However, nginx runs several workers as separated processes, so only one particular worker will updated.
What is a common pattern to cope such problems?
But nginx does not require a restart (nor any downtime) in order to change the configuration!
See:
http://nginx.org/en/docs/control.html#reconfiguration
In order for nginx to re-read the configuration file, a HUP signal should be sent to the master process. The master process first checks the syntax validity, then tries to apply new configuration, that is, to open log files and new listen sockets. If this fails, it rolls back changes and continues to work with old configuration. If this succeeds, it starts new worker processes, and sends messages to old worker processes requesting them to shut down gracefully. Old worker processes close listen sockets and continue to service old clients. After all clients are serviced, old worker processes are shut down.
As an administrator, it would be my expectation that all modules would, in fact, be controlled in this way, too.
(Of course, if you require a lot of changes to the configuration very often, a different solution might be more appropriate.)
You give an explicit example of blocking access by IP. Are you sure you require a new module in order to accomplish the task? It would seem that a combination of the following standard directives might suffice already:
http://nginx.org/r/deny && http://nginx.org/r/allow
http://nginx.org/r/geo
http://nginx.org/r/map
http://nginx.org/r/if && http://nginx.org/r/return
If you're able to move the black list outside of the module's context, perhaps to a system file, a KV store, or SHM, that would allow each process to talk to a central source blacklist. I believe shmat() and futex will do the job and the overhead will be negligible.

Limit access to a pipe to a process (Windows)

Is it possible to limit access to a named pipe by process (either image name, or process ID would work)?
The context here is a Filter Minidriver which has to communicate with a user-space service that would do most of the business logic. Since this communication is security-sensitive, I'd like to protect it from external interference, while by default it seems the named pipe, created by the driver can be communicated with by any user-space process that knows the name of the pipe (which is trivial to discover by static or dynamic analysis).
This is what I already know: Pipes are securable objects in Windows, and as such, they have a security descriptor. This security descriptor can contain a DACL, which is supposed to limit access to the object. I have searched extensively for documentation and examples of conditional ACEs, which I hoped could do what I want, but I failed to find anything related.
EDIT: I have accepted MSalters' answer. It is generally accepted that SYSTEM == ring0 and while code signing of drivers may seem like it matters, SYSTEM can disable code signing easily, so there is no need for privilege escalation from SYSTEM to ring0 - they're already the same. On the other hand, even the default security descriptor (in the minifilter driver context - see FltBuildDefaultSecurityDescriptor) contains a restriction so that only SYSTEM and Administrators can access the object, so no further action is necessary (or possible, it seems).
Image names are not secured anyway, anyone can create a "Notepad.EXE". And a process ID is just a number and can be reused, so that's no protection either. Besides, there are many ways in which you can smuggle a DLL inside another process, so even if you knew that a particular process was running your EXE, you still wouldn't know if it was running just your EXE.
The Windows security model uses the notion of security principals (user and system accounts). Those are directly supported by ACL's, and those are protected against spoofing. It makes sense if your filter driver refuses to talk to just anyone, but it's willing to talk to process A of user X, it should be willing to talk to any process of user X.

How to release Linux lock files for unique daemon process and multiple users

I have a deamon of which only one instance should be running at a time. The daemon is part of a larger application. I made this happen this way:
open() /tmp/prog.pid with O_CREAT | O_RDWR, permissions 0666. The permissions actually become 0664, probably because of umask (?)
flock() on the file descriptor returned by open(), with LOCK_EX | LOCK_NB
This is all I had first. My daemon exits on SIGTERM and SIGINT, but it turned out that the lock was not released upon exit. I realized with help of man 1 flock (strangely not in man 2 flock) that manually unlocking might be necessary if "the enclosed command group may have forked a background process which should not be holding the lock". This is exaclty the case since I am working on a daemon, so I now unlock manually at exit.
Now to my problem: there are several users who might be running the daemon.
If user1 is running the daemon, I want user2 to be able to kill it and restart it as themselves.
The locked file /tmp/prog.pid has permissions 0664, owner user1, group user1.
A stop script prog_stop kills all the processes involved in the application (it requires superuser rights, I'm ok with that). It also kills the daemon. When user2 runs prog_stop, the lock is released (I believe), but user2 cannot start its own daemon process, because it is neither owner of the lock file, nor in its group.
Several possible solutions:
make the lock file 0666, writeable to all. Dangerous.
create a group in which users need to be in order to run the application. This requires that all users start the application with this group, probably with help of newgrp. Easy to forget, not easy to enforce that people do this. Possibly set the current group in the scripts used to start the application?
completely delete the lock file in prog_stop. Drawback: I open the file from a C file, where the path string is defined. I need to write (and maintain!) the exact same file name with path in the stop script.
Lock files for daemons must be very common. What is the standard way to deal with this problem?
The standard way for lock files is to turn the daemon into a service and require sudo (or becoming root by other means) to start and stop it.
Now you can give the file a certain group; users in this group can then modify it. They can use newgrp but it's better to add them to the group with usermod --append --groups=foo bar (to add user bar to the group foo; the user keeps her original GID and all other groups they had). After a relog, you can validate this with id bar.
This is all very tedious. When I need something like that, I create a socket. Sockets are killed with the process that created them (so no cleanup necessary). Sockets can also be used to communicate with the running daemon (give me your status, shutdown, maybe even restart, ...).
I'm using a default port number which I compile into the application but I also use an environment variable to override the default.
Just make sure that you create a socket which listens on localhost; otherwise anyone on the Internet might be able talk to it.

UNIX sockets: Is it possible to spoof getsockopt() SO_PEERCRED?

Is there a (compatible) way to spoof (as root) the unix socket (file system sockets) peer credentials which can be obtained by getsockopt(), option SO_PEERCRED?
Background:
I need to connect to a server application (which I cannot modify) which checks the UID of the process which connects to it via SO_PEERCRED. I'd like to spoof the information in order to be able to connect to the application as root, too.
UPDATE
To clarify the question:
I'm searching for a non-invasive way that the server sees a specific peer UID/GID.
Solutions are discouraged which need to alter the kernel (or take the use of kernel modules) or which changes the server process or its loading/linking process in any way (LD_PRELOAD, system call interceptions etc.).
Basically, the solution should work when running on any linux (or unix in general) server without any special requirements. The server process might already be running.
You're on the right lines. A root process has the privileges to spoof things like this, the problem is just that SO_PEERCRED provides no mechanism or API for a process to specify what identity should be to presented to the peer.
Two things you can do:
Temporarily drop root (setreuid(desired,-1)) when you make the connect call. A unix-domain connection is stamped with the credentials of the peer at the time the process called connect (and listen going the other way). SO_PEERCRED does not tell you the credentials of the peer at the current moment. Then you can resume root.
Better, use another API. The message-passing API lets a process pick what identify to present to a peer. Call sendmsg with a struct cmsg that contains the credentials you want to send. The kernel will ignore the credentials specified by an unprivileged user and always make sure the other side sees the actual identity, but a privileged process can pretend to be anyone else. This is a better match for your needs, because dropping and regaining root is a perilous activity and in this case unnecessary. Google for "SCM_CREDENTIALS" (or "man -K" for it on your system) to get code samples.
No. The reason is that the mechanism that provides the UID and GID of the peer is internal to the kernel, and you can't spoof the kernel! The kernel uses the PID of the peer to deduce the effective credentials of the peer. This happens when one side does a connect on the socket. See the call to copy_peercred() from unix_stream_connect() in net/unix/af_unix.c. There isn't any way that the peer can change the data it sends or the socket that will convince the kernel that the peer's PID isn't what it is. This is different from AF_INET sockets where the kernel has no internal knowledge of the peer's process and can only see the data in the IP packet headers that the peer sends.
The only thing that you can do to get this effect is to set the effective UID of the peer process to root or whatever UID/GID you want, and for that you need either root password or sudo privileges.

Resources