shmctl IPC_RMID precludes further attachments?
I am trying to be proactive by making a shmctl call right after the first shmat call on a shared memory location. I want to do this so that if the creating process exits for some reason the shared memory will already be flagged for destruction. The problem happens when I want a sub-process to access that memory. I know the parent process doesn't detach before the sub-process tries to attach. A short example:
Code:
#include <sys/ipc.h> ta0kira |
Alright, I think I have a solution. The destruct flag doesn't preclude attachment, but does preclude shmget from returning an ID. This means that if the ID is extracted before setting the flag it can be used to attach whatever holds the number. This helps me out in that after the flag is set nothing can access that memory knowing the key alone.
The problem I have is that the PID of the sub-process must be the key. I guess my solution, pending a better one, will be to pass the ID to the sub-process via a pipe (for security) so it can map the shared segment. Having that segment's key the sub-processes PID would be a security hole had it not been for this obscurely-useful feature I was trying to defeat! Here is a modified version: Code:
#include <sys/ipc.h> |
There ain't no magic bullet to do it the way you're doing it.
Speaking of bullets, the difficulty of making a bulletproof way of avoiding abandoned shared memory segments is the reason that authorities such as W. Richard Stevens (of happy memory) advise using an alternative way of getting the job done. What he advises (and I've used to great effect) is something like this: Code:
#include <sys/mman.h> When I read the man page for mmap, the following explanation of MAP_SHARED made me nervous: Code:
MAP_SHARED Share this mapping with all other processes I tried it (Linux kernel 2.4.22), and that worry was unjustified. Modifications by one process did not change the data for the other. Hope this helps. |
I need the shared segment to last across exec calls. Can I mmap after forking using the phyle file descriptor?
What I think happens when you IPC_RMID is it turns the segment to IPC_PRIVATE. Nothing crash-worthy will happen between creating the segment and mapping it, so I think I'll just create it as private and mark it for destruction immediately after the first mapping. I don't quite understand how the mmap thing works. I am writing a server where each (local-machine) client will have its own shared memory segment that only it and the server should be able to access. The clients are started by the server via fork and exec, so normally they will inherit pipes on FDs 3-6 to communicate with the server. I'd planned on passing the shmid to the client via FD 6 which I believe will get the job done. Is there a way to create limitless independent segments the way you are saying without having a separate file for each segment, all of which can traverse an exec call? As it is now I use pairs of pipes which works fine, but as the server progresses I'll probably want the speed of shared memory. Thanks. ta0kira |
Alas, it will not survive an exec() call. Also, the parent must do it. I think my suggestion is irrelevant in your situation. Sorry.
|
Thanks anyway. I think I've got it figured out. I will look more into mmap, though, because the thought of backing shared memory with a character device intrigues me.
ta0kira |
Update: creating with IPC_PRIVATE and sending the shmid via a pipe allows me to flag the shared memory with IPC_RMID at the point I need to. It looks like that was the solution!
ta0kira |
Nevermind. That does not work.
ta0kira |
How about this?
That work? |
That is an interesting idea. As of now I am passing the ID via a pipe since I have one open to pass the forked PID to the new process. I have to do that since in some cases the execution will be a call to system() and the client will need to know the actual PID of the process the server started it under (can't set an env. variable after forking for the PID.) Making sure the client has the correct ID is arbitrary compared to preventing shared memory leaks, however.
It isn't a problem passing the ID to the client. What I've done now is made a static memory pool in the server which holds a table of IDs. The server registers the new shared segments with it and when they are no longer needed the table flags them with IPC_RMID and table has a destructor which flags all remaining IDs for destruction. I'm registering a cleanup handler for all handleable signals which normally cause termination, so anything short of SIGKILL should be safe. As an extra measure of caution and security, the client itself flags the ID. In case you are wondering, the clients are "supposed" to use a library provided for IPC. There is no way to enforce that, however, and no matter how hard I try, someone can still hack it in their own program. I don't mind if someone's client doesn't work because they hacked the client lib, but I still need to protect the server from them. Or more accurately, reasonably protect my users' systems from 3rd-party clients they may choose to run. ta0kira |
Still having problems with shm! It seems that abnormal termination doesn't decrement the attached process count on the shared memory. That means that if a client crashes, it doesn't matter if the segment is flagged if it doesn't use a handler.
Can you, by chance, use mmap in the way you suggested with a pipe? I will try to come up with a test program and I'll let you know. ta0kira edit: Nevermind, I was right the first time. It was a program bug that happened when I was converting to dual-mode (pipe + shared memory) in the server. |
Regarding my original question, here is what I've figured out.
The POSIX standard doesn't allow for attaching to IPC_RMID-flagged memory. Linux is supposed to allow it, but on my machine it doesn't work. When a segment is created using IPC_PRIVATE it gets a random key which no one knows. When a segment is flagged with IPC_RMID, any associated key is set to 0x00. The shmid is still intact, but apparently the kernel doesn't like to attach memory that has a 0x00 key associated with it. I derived most of this info from ipcs and man shmat. ta0kira |
I'm a little confused here, which is perfectly fine, because there are several pieces to this situation. When you say:
Quote:
Quote:
By the way, have you considered executing some shm cleanup code every once in a while (say, just after you harvest a child process or just before you fire up a new one)? Something like this? Code:
wally:~/sunday$ cat membgone.c |
Quote:
Quote:
ta0kira |
Another point:
I seem to remember (correct me if I'm wrong) that part of your security model is for a shared segment's key to be hidden from others. But /proc will show to anyone every key and every ID for every shared memory segment, along with the uid of the creator. Does this affect your security model? If so, and if different clients run as different users (or even if they don't), consider the possibility of the server creating the shared memory segments to enforce the idea that the protection mode of each shared memory segment should be 600, not 666. Just a thought. |
All times are GMT -5. The time now is 08:02 PM. |