Bug 53996 - shmget fails on duplicate ftok
Summary: shmget fails on duplicate ftok
Status: RESOLVED FIXED
Alias: None
Product: APR
Classification: Unclassified
Component: APR (show other bugs)
Version: 1.4.6
Hardware: PC Linux
: P2 major (vote)
Target Milestone: ---
Assignee: Apache Portable Runtime bugs mailinglist
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-10-12 13:06 UTC by Dick Snippe
Modified: 2014-04-19 12:21 UTC (History)
0 users



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Dick Snippe 2012-10-12 13:06:13 UTC
One of our 2.4.3 apache stopped working after a graceful restart, leaving this error message:

[Fri Oct 12 00:00:01.782399 2012] [auth_digest:notice] [pid 15960:tid 140576559888112] AH01757: generating secret for digest authentication ...
[Fri Oct 12 00:00:01.782459 2012] [auth_digest:error] [pid 15960:tid 140576559888112] (17)File exists: AH01762: Failed to create shared memory segment on file /e/fp/smooto2a/scratch/authdigest_shm.15960
[Fri Oct 12 00:00:01.782482 2012] [auth_digest:error] [pid 15960:tid 140576559888112] (17)File exists: AH01760: failed to initialize shm - all nonce-count checking, one-time nonces, and MD5-sess algorithm disabled
[Fri Oct 12 00:00:01.782487 2012] [:emerg] [pid 15960:tid 140576559888112] AH00020: Configuration Failed, exiting

In our case we are running multiple apache instances on the same server and it turned out that 2 instances have a ftok() collision on their authdigest_shm
files.

The current shared memory segment belongs to the "smooti2a" instance and when
"smooto2a" tried to start it failed with:
17725 open("/e/fp/smooto2a/scratch/authdigest_shm.17725", O_WRONLY|O_CREAT|O_EXCL|0x80000, 0666) = 7
17725 stat("/e/fp/smooto2a/scratch/authdigest_shm.17725", {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
17725 shmget(0x10600aa, 1000, IPC_CREAT|IPC_EXCL|0600) = -1 EEXIST (File exists)

I wrote a small C program to display the ftok on an arbitrary file and ran that on both authdigest_shm files:
$ ftok /e/fp/smooto2a/scratch/authdigest_shm.17725 /e/fp/smooti2a/scratch/authdigest_shm.13024 
/e/fp/smooto2a/scratch/authdigest_shm.17725 10600aa
/e/fp/smooti2a/scratch/authdigest_shm.13024 10600aa

The inode numbers of both files happen to be very similar:
$ ls -i  /e/fp/smooto2a/scratch/authdigest_shm.17725 /e/fp/smooti2a/scratch/authdigest_shm.13024
 8388778 /e/fp/smooti2a/scratch/authdigest_shm.13024
16777386 /e/fp/smooto2a/scratch/authdigest_shm.17725

This can be seen when the inode numbers are displayed in hex:
$ printf "%07x\n%07x\n" 8388778 16777386
08000aa
10000aa

The similar inode numbers are possibly caused by our choice of filesystem (xfs)

So it would seem that the warning in the ftok(3) manpage applies:
       Of course no guarantee can be given that the resulting key_t is unique.
       Typically, a best effort attempt combines the given proj_id  byte,  the
       lower  16 bits of the i-node number, and the lower 8 bits of the device
       number into a 32-bit result.  Collisions may easily happen, for example
       between files on /dev/hda1 and files on /dev/sda1.

When browsing through the apr code (shmem/unix/shm.c) it appears that
shmkeys are always generated with proj_id == 1:

        /* ftok() (on solaris at least) requires that the file actually
         * exist before calling ftok(). */
        shmkey = ftok(filename, 1);
        if (shmkey == (key_t)-1) {
            return errno;
        }

        if ((new_m->shmid = shmget(shmkey, new_m->realsize,
                                   SHM_R | SHM_W | IPC_CREAT | IPC_EXCL)) < 0) {
            return errno;
        }

Perhaps ftok could be made to iterate over a number of proj_id's and use the first proj_id where shmget succeeds?
However, that would require addinional logic in the apr_shm_remove function,
because it also uses ftok to calculate the shmkey to remove.
What would be needed is that the shmkey is stored somewhere when it is created and the stored value of shmkey is used when the time has arrived to destroy
the shared memory segment.
Comment 1 Jim Jagielski 2013-11-16 22:50:41 UTC
Thanks for the report... a simple way could be to stat the file and use possibly the UID as the prod_id. Or create apr_shm_ftok() to generate the key and bypass ftok completely.
Comment 2 Jim Jagielski 2013-11-17 14:30:07 UTC
Starting with APR 1.5.1, ftok uses an APR hash of the filename for the prom_id value, reducing the possibility of collisions.
Comment 3 Jim Jagielski 2014-01-24 22:14:36 UTC
Until we can expose the ftok prod_id used, we need to stay with 1 which has been the assumed value for a LOOOONG time :/
Comment 4 Jeff Trawick 2014-04-19 12:21:42 UTC
This is fixed in apr 1.5.1, which is being rolled out now and will be announced in a couple of days.