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.
Related
I am developing a program in C that requires temporary use of some capabilities that require elevation to acquire and would rather not just have users issue sudo because it will be one time setup.
How would I go about granting capabilities such as CAP_CHOWN to enable changing file ownership or similar actions guarded by a capability?
A note on possible duplicates
When I asked this before it got closed as a duplicate. The question that was cited as the original question isn't the same question I had posted. I want a very specific set of capabilities, not root access.
The most common method to do provide extra capabilities to a process is to assign filesystem capabilities to its binary.
For example, if you want the processes executing /sbin/yourprog to have the CAP_CHOWN capability, add that capability to the permitted and effective sets of that file: sudo setcap cap_chown=ep /sbin/yourprog.
The setcap utility is provided by the libcap2-bin package, and is installed by default on most Linux distributions.
It is also possible to provide the capabilities to the original process, and have that process manipulate its effective capability set as needed. For example, Wireshark's dumpcap is typically installed with CAP_NET_ADMIN and CAP_NET_RAW filesystem capabilities in the effective, permitted, and inheritable sets.
I dislike the idea of adding any filesystem capabilities to the inheritable set. When the capabilities are not in the inheritable set, executing another binary causes the kernel to drop those capabilities (assuming KEEPCAPS is zero; see prctl(PR_SET_KEEPCAPS) and man 7 capabilities for details).
As an example, if you granted /sbin/yourprog only the CAP_CHOWN capability and only in the permitted set (sudo setcap cap_chown=p /sbin/yourprog), then the CAP_CHOWN capability will not be automatically effective, and it will be dropped if the process executes some other binary. To use the CAP_CHOWN capability, a thread can add the capability to its effective set for the duration of the operations needed, then remove it from the effective set (but keep it in the permitted set), via prctl() calls. Note that the libcap cap_get_proc()/cap_set_proc() interface applies the changes to all threads in the process, which may not be what you want.
For temporarily granting a capability, a worker sub-process can be used. This makes sense for a complex process, as it allows delegating/separating the privileged operations to a separate binary. A child process is forked, connected to the parent via an Unix domain stream or datagram socket created via socketpair(), and executes the helper binary that grants it the necessary capabilities. It then uses the Unix domain stream socket to verify the identity (process ID, user ID, group ID, and via the process ID, the executable the other end of the socket is executing). The reason a pipe is not used, is that an Unix domain stream socket or datagram socketpair socket is needed to use the SO_PEERCRED socket option to query the kernel the identity of the other end of the socket.
There are known attack patterns that need to be anticipated and thwarted. The most common attack pattern is causing the parent process to immediately execute a compromised binary after forking and executing the privileged child process, timed just right so the capabled child process trusts the other end is its proper parent executing the proper binary, but in fact control has been transferred to a completely different, compromised or untrustworthy binary.
The details on exactly how to do this securely are a software engineering question much more than a programming question, but using socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fdpair) and verifying the socket peer is the parent process still executing the expected binary more than just once at the beginning, are the key steps needed.
The simplest example I can think of is using prctl() and CAP_NET_BIND_SERVICE filesystem capability only in the permitted set, so that an otherwise unprivileged process can use a privileged port (1-1024, preferably a system-wide subset defined/listed in a root or admin-owned configuration file somewhere under /etc) to provide a network service. If the service will close and reopen its listening socket when told to do so (perhaps via SIGUSR1 signal), the listening socket cannot simply be created once at the beginning then dropped. It is a pretty good match for the "keep in permitted set, but only add to effective set of the thread that actually needs it, then drop it immediately afterwards" pattern.
For CAP_CHOWN, an example program might acquire it into its effective and permitted sets via the filesystem capability, but use a trusted configuration file (root/admin modifiable only) to list the ownership changes it is allowed to do based on the real user and group identity running the process. Consider a dedicated "sudo"-style "chown" utility, intended for say organizations to allow team leads to shift file ownership between their team members, but one that does not use sudo.)
It is not realistically possible to gain capabilities during runtime. The capabilities need to be already set before your software is started.
Some API functions like capset and cap_set_proc exist, but don't expect magic because the situation in which you could gain more capabilities will be both rare and a security oversight.
There are a few general ways of giving your software the required capabilities.
Set a specific capability on your binary with the setcap tool.
Use sudo to call your program. You already mentioned this yourself.
Set the setuid bit on your binary and set ownership to root. In this particular case that will be largely equivalent to calling your program with sudo.
Create a utility program that you apply one of the other methods on. Typically you would find such utility in a place like /usr/libexec. You then call the utility as a subprocess. I would consider this unnecessarily complex for simple situations. However, depending on the situations, this may be preferred over having a potential security risk of your software constantly running with too many privileges.
The first method should be considered the desired way. Your software should drop the capability as soon as it no longer requires it.
The CAP_CHOWN could be used for example to change ownership of /etc/shadow. The new owner could then change password for other users such as root, so effectively it could be equivalent to granting all capabilities. Hence, this capability is -like many others- potentially dangerous.
I want to make a program that will gather information about the keystrokes of a user (keycode, press and release times) and will use them as a biometric for authenticating the user continuously. My approach is to gather the keystrokes using a kernel module (because you can't just kill a kernel module), than the kernel module will send the information to another process that will analyze the data gathered by the kernel module, it will save it to a database and will return an answer to the kernel (the user is authenticated or not) and the kernel will lock the computer if the user is not authenticated. the whole module will not be distributed.
my questions are:
1. How can I call a process from the kernel and also send him the data?
2. how can I return a message to the kernel from the process?
#basile-starynkevitch 's answer and his arguments notwithstanding there is an approach you can take that is perfectly correct and technically allowed by the linux kernel.
Register a keyboard notifier call back function using the kernel call register_keyboard_notifier() in your kernel module. As a matter of fact it's designed for exactly this!
Your notifier call back function will look something like:
int keysniffer_callback(struct notifier_block *notifier_block,
unsigned long scancode,
void *param)
{
// do something with the scancode
return NOTIFY_OK;
}
See https://www.kernel.org/doc/Documentation/input/notifier.txt for starters.
I want to make a program that will gather information about the keystrokes of a user
That should go in practice into your display server, which you did not mention (Xorg, Wayland, MIR, ...?). Details matter a big lot!
My approach is to gather the keystrokes using a kernel module
I strongly believe this is a wrong approach, you don't need any kernel module.
I want to make a program that gathers data about the user keystrokes
Then use ordinary Unix machinery. The keyboard is some character device (and you could have several keyboards, or none, or some virtual one...) and you could read(2) from it. If you want to code a keylogger, please tell that explicitly.
(be aware that a keylogger or any other cyberspying activity can be illegal when used without consent and without permission; in most countries, that could send you to jail: in France, Article 323-1 du Code PĂ©nal punishes that by at least 2 years of jail; and most other countries have similar laws)
the kernel module will send the information to another process [....] it will save it to a database
This is practically very difficult to get (and you look confused). Databases are in user-land (e.g. some RDBMS like PostGresSQL, or some library accessing files like sqlite). Notice that a kernel driver cannot (easily and reliably) even access to files.
All application programs (and most daemons & servers) on Linux are started with execve(2) (e.g. by some unix shell process, or by some daemon, etc...), and I see no reason for you to make an exception. However, some programs (mostly init, but also a few others, e.g. /sbin/hotplug) are started by the kernel, but this is exceptional (and should be avoided, and you don't need that).
How can I call a process from the kernel
You should not do that. I see no reason for your program to avoid being started by execve from some other process (perhaps your init, e.g. systemd).
and also send him the data?
Your process, as all other processes, is interacting with the kernel thru system calls (listed in syscalls(2)). So your application program could use read(2), write(2), poll(2) etc.. Be aware of netlink(7).
how can I return a message to the kernel from the process?
You don't. Use system calls, initiated by application code.
the kernel will lock the computer if the user is not authenticated.
This does not have any sense. Screen locking is a GUI artefact (so is not done by kernel code, but by ad-hoc daemon processes). Of course some processes do continue to run when locking is enabled. And many processes are daemons or servers which don't belong to "the" user (and continue to run when "the computer is locked"). At heart, Linux & POSIX is a multi-user and multi-tasking operating system. Even on a desktop Linux system used by a single physical person, you have dozens of users (i.e. uid-s many of them specialized to a particular feature, look into your /etc/passwd file, see passwd(5)) and more than a hundred processes (each having its pid), use top(1) or ps(1) as ps auxw to list them.
I believe you have the wrong approach. Take first several days or weeks to understand more about Linux from the application point of view. So read some book about Linux programming, e.g. ALP or something newer. Read also something like: Operating Systems: Three Easy Pieces
Be aware that in practice, most Linux systems having a desktop environment are using some display server. So the (physical) keyboard is handled by the X11 or Wayland server. You need to read more about your display server (with X11, things like EWMH).
Hence, you need to be much more specific. You are likely to need to interact with the display server, not the kernel directly.
At last, a rule of thumb is to avoid bloating your kernel with extra and useless driver code. You very probably can do your thing in userland entirely.
So, spend a week or more reading about OSes & Linux before coding a single line of code. Avoid kernel modules, they will bite you, and you probably don't need them (but you might need to hack your display server or simply your window manager; of course details are different with X11 and with Wayland). Read also about multiseat Linux systems.
At last, most Linux distributions are made of free software, whose source code you can study. So take time to look into the source code of relevant software for your (ill-defined) goals. Use also strace(1) to understand the system calls dynamically done by commands and processes.
I am attempting to have a bunch of independent programs intelligently allocate shared resources among themselves. However, I could have only one program running, or could have a whole bunch of them.
My thought was to mmap a virtual file in each program, but the concurrency is killing me. Mutexes are obviously ineffective because each program could have a lock on the file and be completely oblivious of the others. However, my attempts to write a semaphore have all failed, since the semaphore would be internal to the file, and I can't rely on only one thing writing to it at a time, etc.
I've seen quite a bit about named pipes but it doesn't seem to be to be a practical solution for what I'm doing since I don't know how many other programs there will be, if any, nor any way of identifying which program is participating in my resource-sharing operation.
You could use a UNIX-domain socket (AF_UNIX) - see man 7 unix.
When a process starts up, it tries to bind() a well-known path. If the bind() succeeds then it knows that it is the first to start up, and becomes the "resource allocator". If the bind() fails with EADDRINUSE then another process is already running, and it can connect() to it instead.
You could also use a dedicated resource allocator process that always listens on the path, and arbitrates resource requests.
Not entirely clear what you're trying to do, but personally my first thought would be to use dbus (more detail). Should be easy enough within that framework for your processes/programs to register/announce themselves and enumerate/signal other registered processes, and/or to create a central resource arbiter and communicate with it. Readily available on any system with gnome or KDE installed too.
The pcap_lookupdev() fills in the errbuf variable when run as non-root user, while the same functions returns the value of the first available network interface when run as root.
Is this access disabled by the OS or the library. I think it is the OS. What is the right answer?
This is not a homework question
In general, when it comes to accessing files, devices and other services provided by the OS, access models in Unix (and, thus, Linux) are implemented in the OS.
Userspace programs are expected to just try whatever they want to do and gracefully handle any error condition by e.g. informing the user with a message.
This has several advantages:
Maintainability: Access policy enforcement remains with the OS and can be configured uniformly. The administrator that wants to restrict access to a resource does so once, rather than having to configure this library here, than that library there, then...
Configurability: The administrator can configure as simple or complex an access policy they need without being limited by each userspace implementation.
Security: Userspace programs should not in general be trusted with enforcing access policy. It would be like having a wolf guard the sheep.
EDIT:
In your case, pcap needs low-level access to the network interface. Due to the security implications (capturing network traffic, generating arbitrary network packets etc), such access is limited to privileged users only. On Linux, for example, pcap needs the CAP_NET_RAW capability to be available to the user.
Many of the pcap functions require root privileges in order to work correctly. Might this be the problem?
It mostly depends on OS. Not all pcap functions require root privilege on all OS.
Ref to Reference Manual Pages, all special privilege requirements are listed respectively.
The user, administrators and support staff need detailed runtime and monitoring information from a daemon developed in C.
In my case these information are e.g.
the current system health, like throughput (MB/s), already written data, ...
the current configuration
I would use JMX in the Java world and the procfs (or sysfs) interface for a kernel module. A log file doesn't seem to be the best way.
What is the best way for such a information interface for a C daemon?
I thought about opening a socket and implementing a bare-metal http or xmlrpc server, but that seems to be overkill. What are alternatives?
You can use a signal handler in your daemon that reacts to, say USR1, and dumps information to the screen/log/net. This way, you can just send the process a USR1 signal whenever you need the info.
You could listen on a UNIX-domain socket, and write regularly write the current status (say once a second) to anyone who connects to it. You don't need to implement a protocol like HTTP or XMLRPC - since the communication will be one-way just regularly write a single line of plain text containing the state.
If you are using a relational database anyway, create another table and fill it with the current status as frequent as necessary. If you don't have a relational database, write the status in a file, and implement some rotation scheme to avoid overwriting a file that somebody reads at that very moment.
Write to a file. Use a file locking protocol to force atomic reads and writes. Anything you agree on will work. There's probably a UUCP locking library floating around that you can use. In a previous life I found one for Linux. I've also implemented it from scratch. It's fairly trivial to do that too.
Check out the lockdev(3) library on Linux. It's for devices, but it may work for plain files too.
I like the socket idea best. There's no need to support HTTP or any RPC protocol. You can create a simple application specific protocol that returns requested information. If the server always returns the same info, then handling incoming requests is trivial, though the trivial approach may cause problems down the line if you ever want to expand on the possible queries. The main reason to use a pre-existing protocol is to leverage existing libraries and tools.
Speaking of leveraging, another option is to use SNMP and access the daemon as a managed component. If you need to query/manage the daemon remotely, this option has its advantages, but otherwise can turn out to be greater overkill than an HTTP server.