sysvipc: Return EINVAL for invalid shmctl 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:55:02 -03:00
parent a49d7fd4f7
commit 9ebaabeaac
3 changed files with 69 additions and 13 deletions

View File

@ -88,25 +88,49 @@ __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf)
{
#if __IPC_TIME64
struct kernel_shmid64_ds kshmid, *arg = NULL;
if (buf != NULL)
#else
shmctl_arg_t *arg;
#endif
switch (cmd)
{
/* This is a Linux extension where kernel expects either a
'struct shminfo' (IPC_INFO) or 'struct shm_info' (SHM_INFO). */
if (cmd == IPC_INFO || cmd == SHM_INFO)
arg = (struct kernel_shmid64_ds *) buf;
else
case IPC_RMID:
case SHM_LOCK:
case SHM_UNLOCK:
arg = NULL;
break;
case IPC_SET:
case IPC_STAT:
case SHM_STAT:
case SHM_STAT_ANY:
#if __IPC_TIME64
if (buf != NULL)
{
shmid64_to_kshmid64 (buf, &kshmid);
arg = &kshmid;
}
}
# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
if (cmd == IPC_SET)
arg->shm_perm.mode *= 0x10000U;
# endif
#else
shmctl_arg_t *arg = buf;
arg = buf;
#endif
break;
case IPC_INFO:
case SHM_INFO:
/* This is a Linux extension where kernel expects either a
'struct shminfo' (IPC_INFO) or 'struct shm_info' (SHM_INFO). */
arg = (__typeof__ (arg)) buf;
break;
default:
__set_errno (EINVAL);
return -1;
}
int ret = shmctl_syscall (shmid, cmd, arg);
if (ret < 0)

View File

@ -25,7 +25,7 @@
#include <sys/shm.h>
#include <include/array_length.h>
/* Return the first invalid command SysV IPC command from common shared
/* Return the first invalid SysV IPC command from common shared
between message queue, shared memory, and semaphore. */
static inline int
first_common_invalid_cmd (void)
@ -50,7 +50,7 @@ first_common_invalid_cmd (void)
return invalid;
}
/* Return the first invalid command SysV IPC command for semaphore. */
/* Return the first invalid SysV IPC command for semaphore. */
static inline int
first_sem_invalid_cmd (void)
{
@ -82,7 +82,7 @@ first_sem_invalid_cmd (void)
return invalid;
}
/* Return the first invalid command SysV IPC command for message queue. */
/* Return the first invalid SysV IPC command for message queue. */
static inline int
first_msg_invalid_cmd (void)
{
@ -107,4 +107,31 @@ first_msg_invalid_cmd (void)
return invalid;
}
/* Return the first invalid SysV IPC command for shared memory. */
static inline int
first_shm_invalid_cmd (void)
{
const int shm_cmds[] = {
SHM_STAT,
SHM_INFO,
#ifdef SHM_STAT_ANY
SHM_STAT_ANY,
#endif
SHM_LOCK,
SHM_UNLOCK
};
int invalid = first_common_invalid_cmd ();
for (int i = 0; i < array_length (shm_cmds); i++)
{
if (invalid == shm_cmds[i])
{
invalid++;
i = 0;
}
}
return invalid;
}
#endif /* _TEST_SYSV_H */

View File

@ -25,6 +25,8 @@
#include <sys/ipc.h>
#include <sys/shm.h>
#include <test-sysvipc.h>
#include <support/support.h>
#include <support/check.h>
#include <support/temp_file.h>
@ -81,6 +83,9 @@ do_test (void)
FAIL_EXIT1 ("shmget failed (errno=%d)", errno);
}
TEST_COMPARE (shmctl (shmid, first_shm_invalid_cmd (), NULL), -1);
TEST_COMPARE (errno, EINVAL);
/* Get shared memory kernel information and do some sanity checks. */
struct shmid_ds shminfo;
if (shmctl (shmid, IPC_STAT, &shminfo) == -1)