fix corrupt sysvipc timestamps on 32-bit archs with old kernels
authorRich Felker <dalias@aerifal.cx>
Fri, 13 Mar 2020 20:27:10 +0000 (16:27 -0400)
committerRich Felker <dalias@aerifal.cx>
Sun, 15 Mar 2020 01:23:37 +0000 (21:23 -0400)
kernel commit 4693916846269d633a3664586650dbfac2c5562f (first included
in release v4.14) silently fixed a bug whereby the reserved space
(which was later used for high bits of time) in IPC_STAT structures
was left untouched rather than zeroed. this means that a caller that
wants to read the high bits needs to pre-zero the memory.

since it's not clear that these operations are permitted to modify the
destination buffer on failure, use a temp buffer and copy back to the
caller's buffer on success.

src/ipc/msgctl.c
src/ipc/semctl.c
src/ipc/shmctl.c

index b043041a565a1c21bab03b616afb79c4e2a84e0d..9c11440641a99060c7f297c99ab914a14c913724 100644 (file)
@@ -9,6 +9,14 @@
 
 int msgctl(int q, int cmd, struct msqid_ds *buf)
 {
+#if IPC_TIME64
+       struct msqid_ds out, *orig;
+       if (cmd&IPC_TIME64) {
+               out = (struct msqid_ds){0};
+               orig = buf;
+               buf = &out;
+       }
+#endif
 #ifdef SYSCALL_IPC_BROKEN_MODE
        struct msqid_ds tmp;
        if (cmd == IPC_SET) {
@@ -32,6 +40,8 @@ int msgctl(int q, int cmd, struct msqid_ds *buf)
 #endif
 #if IPC_TIME64
        if (r >= 0 && (cmd&IPC_TIME64)) {
+               buf = orig;
+               *buf = out;
                IPC_HILO(buf, msg_stime);
                IPC_HILO(buf, msg_rtime);
                IPC_HILO(buf, msg_ctime);
index ed9827477aee81c032a0c7d29c9c8595ca64eed8..bbb97d7aed0637f68496dd61ebf277eed7e9b87d 100644 (file)
@@ -28,6 +28,14 @@ int semctl(int id, int num, int cmd, ...)
                arg = va_arg(ap, union semun);
                va_end(ap);
        }
+#if IPC_TIME64
+       struct semid_ds out, *orig;
+       if (cmd&IPC_TIME64) {
+               out = (struct semid_ds){0};
+               orig = arg.buf;
+               arg.buf = &out;
+       }
+#endif
 #ifdef SYSCALL_IPC_BROKEN_MODE
        struct semid_ds tmp;
        if (cmd == IPC_SET) {
@@ -51,6 +59,8 @@ int semctl(int id, int num, int cmd, ...)
 #endif
 #if IPC_TIME64
        if (r >= 0 && (cmd&IPC_TIME64)) {
+               arg.buf = orig;
+               *arg.buf = out;
                IPC_HILO(arg.buf, sem_otime);
                IPC_HILO(arg.buf, sem_ctime);
        }
index de3ce9d4d7d9f2cb1b15a5e9c29a33ce7c3716e8..1c9f78c2f11f5630142200274b5bb6ad0596e8a0 100644 (file)
@@ -9,6 +9,14 @@
 
 int shmctl(int id, int cmd, struct shmid_ds *buf)
 {
+#if IPC_TIME64
+       struct shmid_ds out, *orig;
+       if (cmd&IPC_TIME64) {
+               out = (struct shmid_ds){0};
+               orig = buf;
+               buf = &out;
+       }
+#endif
 #ifdef SYSCALL_IPC_BROKEN_MODE
        struct shmid_ds tmp;
        if (cmd == IPC_SET) {
@@ -32,6 +40,8 @@ int shmctl(int id, int cmd, struct shmid_ds *buf)
 #endif
 #if IPC_TIME64
        if (r >= 0 && (cmd&IPC_TIME64)) {
+               buf = orig;
+               *buf = out;
                IPC_HILO(buf, shm_atime);
                IPC_HILO(buf, shm_dtime);
                IPC_HILO(buf, shm_ctime);