1 /*
2 * Copyright (c) 1993 Ulrich Pegelow <pegelow@moorea.uni-muenster.de>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
5 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * Copyright (c) 2003-2006 Roland McGrath <roland@redhat.com>
7 * Copyright (c) 2006-2015 Dmitry V. Levin <ldv@strace.io>
8 * Copyright (c) 2015-2021 The strace developers.
9 * All rights reserved.
10 *
11 * SPDX-License-Identifier: LGPL-2.1-or-later
12 */
13
14 #include "defs.h"
15
16 #include DEF_MPERS_TYPE(semid_ds_t)
17 #include DEF_MPERS_TYPE(semun_ptr_t)
18
19 #include "ipc_defs.h"
20
21 #include SEM_H_PROVIDER
22
23 typedef struct NAME_OF_STRUCT_SEMID_DS semid_ds_t;
24 typedef kernel_ulong_t semun_ptr_t;
25
26 #include MPERS_DEFS
27
28 #include "xlat/semctl_flags.h"
29
30 #define key NAME_OF_STRUCT_IPC_PERM_KEY
31
32 static void
33 print_ipc_perm(const typeof_field(semid_ds_t, sem_perm) *const p,
34 const unsigned int cmd)
35 {
36 tprint_struct_begin();
37 PRINT_FIELD_ID(*p, uid);
38 tprint_struct_next();
39 PRINT_FIELD_ID(*p, gid);
40 tprint_struct_next();
41 PRINT_FIELD_OBJ_U(*p, mode, print_numeric_ll_umode_t);
42 if (cmd != IPC_SET) {
43 tprint_struct_next();
44 PRINT_FIELD_U(*p, key);
45 tprint_struct_next();
46 PRINT_FIELD_ID(*p, cuid);
47 tprint_struct_next();
48 PRINT_FIELD_ID(*p, cgid);
49 }
50 tprint_struct_end();
51 }
52
53 static void
54 print_semid_ds(struct tcb *const tcp, const kernel_ulong_t addr,
55 const unsigned int cmd, const bool indirect_addr)
56 {
57 semid_ds_t ds;
58
59 if (!tfetch_mem(tcp, addr, sizeof(ds), &ds)) {
60 if (indirect_addr)
61 tprint_indirect_begin();
62 printaddr(addr);
63 if (indirect_addr)
64 tprint_indirect_end();
65 return;
66 }
67
68 tprint_struct_begin();
69 PRINT_FIELD_OBJ_PTR(ds, sem_perm, print_ipc_perm, cmd);
70 if (cmd != IPC_SET) {
71 tprint_struct_next();
72 PRINT_FIELD_U(ds, sem_otime);
73 tprint_struct_next();
74 PRINT_FIELD_U(ds, sem_ctime);
75 tprint_struct_next();
76 PRINT_FIELD_U(ds, sem_nsems);
77 }
78 tprint_struct_end();
79 }
80
81 static void
82 print_seminfo(struct tcb *const tcp, const kernel_ulong_t addr,
83 const unsigned int cmd, const bool indirect_addr)
84 {
85 struct seminfo info;
86
87 if (umove_or_printaddr(tcp, addr, &info))
88 return;
89 if (!tfetch_mem(tcp, addr, sizeof(info), &info)) {
90 if (indirect_addr)
91 tprint_indirect_begin();
92 printaddr(addr);
93 if (indirect_addr)
94 tprint_indirect_end();
95 return;
96 }
97
98 tprint_struct_begin();
99 PRINT_FIELD_D(info, semmap);
100 tprint_struct_next();
101 PRINT_FIELD_D(info, semmni);
102 tprint_struct_next();
103 PRINT_FIELD_D(info, semmns);
104 tprint_struct_next();
105 PRINT_FIELD_D(info, semmnu);
106 tprint_struct_next();
107 PRINT_FIELD_D(info, semmsl);
108 tprint_struct_next();
109 PRINT_FIELD_D(info, semopm);
110 tprint_struct_next();
111 PRINT_FIELD_D(info, semume);
112 tprint_struct_next();
113 PRINT_FIELD_D(info, semusz);
114 tprint_struct_next();
115 PRINT_FIELD_D(info, semvmx);
116 tprint_struct_next();
117 PRINT_FIELD_D(info, semaem);
118 tprint_struct_end();
119 }
120
121 SYS_FUNC(semctl)
122 {
123 kernel_ulong_t addr;
124 unsigned int cmd = tcp->u_arg[2];
125 const bool indirect_addr = indirect_ipccall(tcp)
126 #ifdef SPARC64
127 && current_personality != 0
128 #endif
129 ;
130
131 /* TODO: We don't properly decode old compat ipc calls. */
132 if (cmd & IPC_64)
133 cmd &= ~IPC_64;
134
135 if (entering(tcp)) {
136 /* semid */
137 PRINT_VAL_D((int) tcp->u_arg[0]);
138 tprint_arg_next();
139
140 /* semnum */
141 PRINT_VAL_D((int) tcp->u_arg[1]);
142 tprint_arg_next();
143
144 /* cmd */
145 PRINTCTL(semctl_flags, tcp->u_arg[2], "SEM_???");
146 tprint_arg_next();
147
148 if (indirect_addr) {
149 semun_ptr_t ptr;
150 if (umove_or_printaddr(tcp, tcp->u_arg[3], &ptr))
151 return RVAL_DECODED;
152 addr = ptr;
153 } else {
154 addr = tcp->u_arg[3];
155 }
156 switch (cmd) {
157 case IPC_SET:
158 print_semid_ds(tcp, addr, cmd, indirect_addr);
159 return RVAL_DECODED;
160
161 case IPC_STAT:
162 case SEM_STAT:
163 case SEM_STAT_ANY:
164 case IPC_INFO:
165 case SEM_INFO:
166 /* decode on exiting */
167 set_tcb_priv_ulong(tcp, addr);
168 break;
169
170 default:
171 if (indirect_addr)
172 tprint_indirect_begin();
173 printaddr(addr);
174 if (indirect_addr)
175 tprint_indirect_end();
176 return RVAL_DECODED;
177 }
178 } else {
179 addr = get_tcb_priv_ulong(tcp);
180 switch (cmd) {
181 case IPC_STAT:
182 case SEM_STAT:
183 case SEM_STAT_ANY:
184 print_semid_ds(tcp, addr, cmd, indirect_addr);
185 break;
186
187 case IPC_INFO:
188 case SEM_INFO:
189 print_seminfo(tcp, addr, cmd, indirect_addr);
190 break;
191 }
192 }
193 return 0;
194 }