• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) International Business Machines  Corp., 2001
4  *
5  * Basic error test for msgrcv(2).
6  *
7  * 1)msgrcv(2) fails and sets errno to E2BIG if the message text length is
8  *    greater than msgsz and MSG_NOERROR isn't specified in msgflg.
9  *
10  * 2)The calling process does not have read permission on the message
11  *    queue, so msgrcv(2) fails and sets errno to EACCES.
12  *
13  * 3)msgrcv(2) fails and sets errno to EFAULT if the message buffer address
14  *    isn't accessible.
15  *
16  * 4)msgrcv(2) fails and sets errno to EINVAL if msqid was invalid(<0).
17  *
18  * 5)msgrcv(2) fails and sets errno to EINVAL if msgsize is less than 0.
19  *
20  * 6)msgrcv(2) fails and sets errno to ENOMSG if IPC_NOWAIT was specified in
21  *   msgflg and no message of the requested type existed on the message queue.
22  */
23 
24 #define _GNU_SOURCE
25 
26 #include <string.h>
27 #include <sys/wait.h>
28 #include <sys/msg.h>
29 #include <stdlib.h>
30 #include <pwd.h>
31 #include "tst_test.h"
32 #include "tst_safe_sysv_ipc.h"
33 #include "libnewipc.h"
34 
35 static key_t msgkey;
36 static int queue_id = -1;
37 static int bad_id = -1;
38 struct passwd *pw;
39 
40 static struct buf {
41 	long type;
42 	char mtext[MSGSIZE];
43 } rcv_buf, snd_buf = {2, "hello"};
44 
45 static struct tcase {
46 	int *id;
47 	struct buf *buffer;
48 	int msgsz;
49 	long msgtyp;
50 	int msgflag;
51 	int exp_user;
52 	int exp_err;
53 } tcases[] = {
54 	{&queue_id, &rcv_buf, MSGSIZE - 1, 2, 0, 0, E2BIG},
55 	{&queue_id, &rcv_buf, MSGSIZE,     2, 0, 1, EACCES},
56 	{&queue_id, NULL,     MSGSIZE,     2, 0, 0, EFAULT},
57 	{&bad_id,   &rcv_buf, MSGSIZE,     2, 0, 0, EINVAL},
58 	{&queue_id, &rcv_buf, -1,          2, 0, 0, EINVAL},
59 	{&queue_id, &rcv_buf, MSGSIZE,  3, IPC_NOWAIT,              0, ENOMSG},
60 	{&queue_id, &rcv_buf, MSGSIZE, -1, IPC_NOWAIT,              0, ENOMSG},
61 	{&queue_id, &rcv_buf, MSGSIZE, -1, IPC_NOWAIT | MSG_EXCEPT, 0, ENOMSG},
62 };
63 
verify_msgrcv(struct tcase * tc)64 static void verify_msgrcv(struct tcase *tc)
65 {
66 	TST_EXP_FAIL2(msgrcv(*tc->id, tc->buffer, tc->msgsz, tc->msgtyp, tc->msgflag), tc->exp_err,
67 		"msgrcv(%i, %p, %i, %ld, %i)", *tc->id, tc->buffer, tc->msgsz, tc->msgtyp, tc->msgflag);
68 }
69 
do_test(unsigned int n)70 static void do_test(unsigned int n)
71 {
72 	struct tcase *tc = &tcases[n];
73 	pid_t pid;
74 
75 	queue_id = SAFE_MSGGET(msgkey, IPC_CREAT | IPC_EXCL | MSG_RW);
76 
77 	SAFE_MSGSND(queue_id, &snd_buf, MSGSIZE, 0);
78 	pid = SAFE_FORK();
79 	if (pid == 0) {
80 		if (tc->exp_user)
81 			SAFE_SETUID(pw->pw_uid);
82 		verify_msgrcv(tc);
83 		exit(0);
84 	}
85 	tst_reap_children();
86 	SAFE_MSGCTL(queue_id, IPC_RMID, NULL);
87 }
88 
setup(void)89 static void setup(void)
90 {
91 	msgkey = GETIPCKEY();
92 	pw = SAFE_GETPWNAM("nobody");
93 }
94 
cleanup(void)95 static void cleanup(void)
96 {
97 	if (queue_id != -1)
98 		SAFE_MSGCTL(queue_id, IPC_RMID, NULL);
99 }
100 
101 static struct tst_test test = {
102 	.needs_tmpdir = 1,
103 	.needs_root = 1,
104 	.forks_child = 1,
105 	.tcnt = ARRAY_SIZE(tcases),
106 	.setup = setup,
107 	.cleanup = cleanup,
108 	.test = do_test
109 };
110