1 /*
2  * Copyright (c) International Business Machines  Corp., 2001
3  *
4  * This program is free software;  you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
12  * the GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.
16  */
17 
18 /*
19  * DESCRIPTION
20  * 1) The calling process does not have write permission on the message
21  *    queue, so msgsnd(2) fails and sets errno to EACCES.
22  * 2) msgsnd(2) fails and sets errno to EFAULT if the message buffer address
23  *    is invalid.
24  * 3) msgsnd(2) fails and sets errno to EINVAL if the queue ID is invalid.
25  * 4) msgsnd(2) fails and sets errno to EINVAL if the message type is not
26  *    positive (0).
27  * 5) msgsnd(2) fails and sets errno to EINVAL if the message type is not
28  *    positive (>0).
29  * 6) msgsnd(2) fails and sets errno to EINVAL if the message size is less
30  *    than zero.
31  */
32 
33 #include <errno.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <sys/types.h>
37 #include <sys/ipc.h>
38 #include <sys/msg.h>
39 #include <pwd.h>
40 
41 #include "tst_test.h"
42 #include "tst_safe_sysv_ipc.h"
43 #include "libnewipc.h"
44 
45 static key_t msgkey;
46 static int queue_id = -1;
47 static int bad_id = -1;
48 static struct passwd *pw;
49 static struct buf {
50 	long type;
51 	char text[MSGSIZE];
52 } snd_buf[] = {
53 	{1, "hello"},
54 	{0, "hello"},
55 	{-1, "hello"}
56 };
57 
58 static struct tcase {
59 	int *id;
60 	struct buf *buffer;
61 	int msgsz;
62 	int exp_err;
63 	/*1: nobody expected  0: root expected */
64 	int exp_user;
65 } tcases[] = {
66 	{&queue_id, &snd_buf[0], MSGSIZE, EACCES, 1},
67 	{&queue_id, NULL, MSGSIZE, EFAULT, 0},
68 	{&bad_id, &snd_buf[0], MSGSIZE, EINVAL, 0},
69 	{&queue_id, &snd_buf[1], MSGSIZE, EINVAL, 0},
70 	{&queue_id, &snd_buf[2], MSGSIZE, EINVAL, 0},
71 	{&queue_id, &snd_buf[0], -1, EINVAL, 0}
72 };
73 
74 static void verify_msgsnd(struct tcase *tc)
75 {
76 	TEST(msgsnd(*tc->id, tc->buffer, tc->msgsz, 0));
77 	if (TEST_RETURN != -1) {
78 		tst_res(TFAIL, "smgsnd() succeeded unexpectedly");
79 		return;
80 	}
81 
82 	if (TEST_ERRNO == tc->exp_err) {
83 		tst_res(TPASS | TTERRNO, "msgsnd() failed as expected");
84 	} else {
85 		tst_res(TFAIL | TTERRNO, "msgsnd() failed unexpectedly,"
86 			" expected %s", tst_strerrno(tc->exp_err));
87 	}
88 }
89 
90 static void do_test(unsigned int n)
91 {
92 	pid_t pid;
93 	struct tcase *tc = &tcases[n];
94 
95 	if (tc->exp_user == 0) {
96 		verify_msgsnd(tc);
97 		return;
98 	}
99 
100 	pid = SAFE_FORK();
101 	if (pid) {
102 		tst_reap_children();
103 	} else {
104 		SAFE_SETUID(pw->pw_uid);
105 		verify_msgsnd(tc);
106 	}
107 }
108 
109 static void setup(void)
110 {
111 	msgkey = GETIPCKEY();
112 
113 	queue_id = SAFE_MSGGET(msgkey, IPC_CREAT | IPC_EXCL | MSG_RW);
114 
115 	pw = SAFE_GETPWNAM("nobody");
116 }
117 
118 static void cleanup(void)
119 {
120 	if (queue_id != -1)
121 		SAFE_MSGCTL(queue_id, IPC_RMID, NULL);
122 }
123 
124 static struct tst_test test = {
125 	.needs_tmpdir = 1,
126 	.needs_root = 1,
127 	.forks_child = 1,
128 	.tcnt = ARRAY_SIZE(tcases),
129 	.setup = setup,
130 	.cleanup = cleanup,
131 	.test = do_test
132 };
133