1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-29 11:41:21 +03:00

sysvipc: Return EINVAL for invalid msgctl commands

It avoids regressions on possible future commands that might require
additional libc support.  The downside is new commands added by newer
kernels will need further glibc support.

Checked on x86_64-linux-gnu and i686-linux-gnu (Linux v4.15 and v5.4).
This commit is contained in:
Adhemerval Zanella
2020-09-29 14:45:09 -03:00
parent 20a00dbefc
commit be9b0b9a01
3 changed files with 61 additions and 10 deletions

View File

@ -88,25 +88,46 @@ __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf)
{ {
#if __IPC_TIME64 #if __IPC_TIME64
struct kernel_msqid64_ds ksemid, *arg = NULL; struct kernel_msqid64_ds ksemid, *arg = NULL;
if (buf != NULL) #else
msgctl_arg_t *arg;
#endif
switch (cmd)
{ {
/* This is a Linux extension where kernel returns a 'struct msginfo' case IPC_RMID:
instead. */ arg = NULL;
if (cmd == IPC_INFO || cmd == MSG_INFO) break;
arg = (struct kernel_msqid64_ds *) buf;
else case IPC_SET:
case IPC_STAT:
case MSG_STAT:
case MSG_STAT_ANY:
#if __IPC_TIME64
if (buf != NULL)
{ {
msqid64_to_kmsqid64 (buf, &ksemid); msqid64_to_kmsqid64 (buf, &ksemid);
arg = &ksemid; arg = &ksemid;
} }
}
# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T # ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
if (cmd == IPC_SET) if (cmd == IPC_SET)
arg->msg_perm.mode *= 0x10000U; arg->msg_perm.mode *= 0x10000U;
# endif # endif
#else #else
msgctl_arg_t *arg = buf; arg = buf;
#endif #endif
break;
case IPC_INFO:
case MSG_INFO:
/* This is a Linux extension where kernel returns a 'struct msginfo'
instead. */
arg = (__typeof__ (arg)) buf;
break;
default:
__set_errno (EINVAL);
return -1;
}
int ret = msgctl_syscall (msqid, cmd, arg); int ret = msgctl_syscall (msqid, cmd, arg);
if (ret < 0) if (ret < 0)

View File

@ -82,4 +82,29 @@ first_sem_invalid_cmd (void)
return invalid; return invalid;
} }
/* Return the first invalid command SysV IPC command for message queue. */
static inline int
first_msg_invalid_cmd (void)
{
const int msg_cmds[] = {
MSG_STAT,
MSG_INFO,
#ifdef MSG_STAT_ANY
MSG_STAT_ANY,
#endif
};
int invalid = first_common_invalid_cmd ();
for (int i = 0; i < array_length (msg_cmds); i++)
{
if (invalid == msg_cmds[i])
{
invalid++;
i = 0;
}
}
return invalid;
}
#endif /* _TEST_SYSV_H */ #endif /* _TEST_SYSV_H */

View File

@ -24,6 +24,8 @@
#include <sys/ipc.h> #include <sys/ipc.h>
#include <sys/msg.h> #include <sys/msg.h>
#include <test-sysvipc.h>
#include <support/support.h> #include <support/support.h>
#include <support/check.h> #include <support/check.h>
#include <support/temp_file.h> #include <support/temp_file.h>
@ -86,6 +88,9 @@ do_test (void)
FAIL_EXIT1 ("msgget failed (errno=%d)", errno); FAIL_EXIT1 ("msgget failed (errno=%d)", errno);
} }
TEST_COMPARE (msgctl (msqid, first_msg_invalid_cmd (), NULL), -1);
TEST_COMPARE (errno, EINVAL);
/* Get message queue kernel information and do some sanity checks. */ /* Get message queue kernel information and do some sanity checks. */
struct msqid_ds msginfo; struct msqid_ds msginfo;
if (msgctl (msqid, IPC_STAT, &msginfo) == -1) if (msgctl (msqid, IPC_STAT, &msginfo) == -1)