1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved. 4 * Author: Feiyu Zhu <zhufy.jy@cn.fujitsu.com> 5 */ 6/*\ 7 * [Description] 8 * 9 * Call msgctl() with MSG_INFO flag and check that: 10 * 11 * * The returned index points to a valid MSG by calling MSG_STAT_ANY 12 * * Also count that valid indexes < returned max index sums up to used_ids 13 * * And the data are consistent with /proc/sysvipc/msg 14 * 15 * There is a possible race between the call to the msgctl() and read from the 16 * proc file so this test cannot be run in parallel with any IPC testcases that 17 * adds or removes MSG queues. 18 * 19 * Note what we create a MSG segment in the test setup and send msg to make sure 20 * that there is at least one during the testrun. 21 * 22 * Also note that for MSG_INFO the members of the msginfo structure have 23 * completely different meaning than their names seems to suggest. 24 */ 25 26#include <stdio.h> 27#include <pwd.h> 28#include "tst_test.h" 29#include "tst_safe_sysv_ipc.h" 30#include "libnewipc.h" 31#include "lapi/msg.h" 32 33static int msg_id = -1; 34static struct passwd *ltpuser; 35static uid_t nobody_uid, root_uid; 36 37static struct tcases { 38 uid_t *uid; 39 char *desc; 40} tests[] = { 41 {&nobody_uid, "with nobody user"}, 42 {&root_uid, "with root user"} 43}; 44 45static void parse_proc_sysvipc(struct msginfo *info) 46{ 47 FILE *f = fopen("/proc/sysvipc/msg", "r"); 48 int queue_cnt = 0; 49 int msg_cnt = 0; 50 int msg_bytes = 0; 51 52 /* Eat header */ 53 for (;;) { 54 int c = fgetc(f); 55 56 if (c == '\n' || c == EOF) 57 break; 58 } 59 60 int cbytes, msgs; 61 62 /* 63 * Sum queue and byte for all elements listed, which should equal 64 * the data returned in the msginfo structure. 65 */ 66 while (fscanf(f, "%*i %*i %*i %i %i %*i %*i %*i %*i %*i %*i %*i %*i %*i", 67 &cbytes, &msgs) > 0){ 68 queue_cnt++; 69 msg_cnt += msgs; 70 msg_bytes += cbytes; 71 } 72 73 if (info->msgpool != queue_cnt) { 74 tst_res(TFAIL, "msgpool = %i, expected %i", 75 info->msgpool, queue_cnt); 76 } else { 77 tst_res(TPASS, "queue_cnt = %i", queue_cnt); 78 } 79 80 if (info->msgmap != msg_cnt) { 81 tst_res(TFAIL, "msgmap = %i, expected %i", 82 info->msgpool, msg_cnt); 83 } else { 84 tst_res(TPASS, "msg_cnt = %i", msg_cnt); 85 } 86 87 if (info->msgtql != msg_bytes) { 88 tst_res(TFAIL, "msgtql = %i, expected %i", 89 info->msgtql, msg_bytes); 90 } else { 91 tst_res(TPASS, "msg_bytes = %i", msg_bytes); 92 } 93 94 fclose(f); 95} 96 97static void verify_msgctl(unsigned int n) 98{ 99 struct tcases *tc = &tests[n]; 100 int i, msgid, cnt = 0; 101 struct msqid_ds buf; 102 struct msginfo info; 103 104 tst_res(TINFO, "Test MSG_STAT_ANY %s", tc->desc); 105 106 SAFE_SETEUID(*tc->uid); 107 108 TEST(msgctl(0, MSG_INFO, (struct msqid_ds *)&info)); 109 110 if (TST_RET == -1) { 111 tst_res(TFAIL | TTERRNO, "msgctl(0, MSG_INFO, ...)"); 112 return; 113 } 114 115 msgid = msgctl(TST_RET, MSG_STAT_ANY, &buf); 116 117 if (msgid == -1) { 118 tst_res(TFAIL | TERRNO, "MSG_INFO haven't returned a valid index"); 119 } else { 120 tst_res(TPASS, "MSG_INFO returned valid index %li to msgid %i", 121 TST_RET, msgid); 122 } 123 124 for (i = 0; i <= TST_RET; i++) { 125 if (msgctl(i, MSG_STAT_ANY, &buf) != -1) 126 cnt++; 127 } 128 129 if (cnt == info.msgpool) { 130 tst_res(TPASS, "Counted used = %i", cnt); 131 } else { 132 tst_res(TFAIL, "Counted used = %i, msgpool = %i", 133 cnt, info.msgpool); 134 } 135 136 parse_proc_sysvipc(&info); 137} 138 139static void setup(void) 140{ 141 struct msqid_ds temp_buf; 142 ltpuser = SAFE_GETPWNAM("nobody"); 143 nobody_uid = ltpuser->pw_uid; 144 root_uid = 0; 145 146 msg_id = SAFE_MSGGET(IPC_PRIVATE, IPC_CREAT | MSG_RW); 147 SAFE_MSGSND(msg_id, "abcd", 4, 0); 148 149 TEST(msgctl(msg_id, MSG_STAT_ANY, &temp_buf)); 150 if (TST_RET == -1) { 151 if (TST_ERR == EINVAL) 152 tst_brk(TCONF, "kernel doesn't support MSG_STAT_ANY"); 153 else 154 tst_brk(TBROK | TTERRNO, 155 "Current environment doesn't permit MSG_STAT_ANY"); 156 } 157} 158 159static void cleanup(void) 160{ 161 if (msg_id >= 0) 162 SAFE_MSGCTL(msg_id, IPC_RMID, NULL); 163} 164 165static struct tst_test test = { 166 .setup = setup, 167 .cleanup = cleanup, 168 .test = verify_msgctl, 169 .tcnt = ARRAY_SIZE(tests), 170 .needs_root = 1, 171}; 172