1 /*
2 * Copyright (c) 2010 Andreas Schwab <schwab@linux-m68k.org>
3 * Copyright (c) 2012-2013 Denys Vlasenko <vda.linux@googlemail.com>
4 * Copyright (c) 2014 Masatake YAMATO <yamato@redhat.com>
5 * Copyright (c) 2010-2016 Dmitry V. Levin <ldv@strace.io>
6 * Copyright (c) 2016-2023 The strace developers.
7 * All rights reserved.
8 *
9 * SPDX-License-Identifier: LGPL-2.1-or-later
10 */
11
12 #include "defs.h"
13 #include "msghdr.h"
14 #include "xstring.h"
15 #include <limits.h>
16
17 static bool
18 fetch_struct_mmsghdr_for_print(struct tcb *const tcp,
19 const kernel_ulong_t addr,
20 const unsigned int len, void *const mh)
21 {
22 return (entering(tcp) || !syserror(tcp)) &&
23 fetch_struct_mmsghdr(tcp, addr, mh);
24 }
25
26 struct print_struct_mmsghdr_config {
27 const int *p_user_msg_namelen;
28 unsigned int msg_len_vlen;
29 unsigned int count;
30 bool use_msg_len;
31 };
32
33 static bool
34 print_struct_mmsghdr(struct tcb *tcp, void *elem_buf,
35 size_t elem_size, void *data)
36 {
37 const struct mmsghdr *const mmsg = elem_buf;
38 struct print_struct_mmsghdr_config *const c = data;
39
40 if (!c->count) {
41 tprint_more_data_follows();
42 return false;
43 }
44 --c->count;
45
46 tprint_struct_begin();
47 PRINT_FIELD_OBJ_TCB_PTR(*mmsg, msg_hdr, tcp, print_struct_msghdr,
48 c->p_user_msg_namelen,
49 c->use_msg_len ? mmsg->msg_len : (kernel_ulong_t) -1);
50 if (c->msg_len_vlen) {
51 tprint_struct_next();
52 PRINT_FIELD_U(*mmsg, msg_len);
53 --c->msg_len_vlen;
54 }
55 tprint_struct_end();
56
57 if (c->p_user_msg_namelen)
58 ++c->p_user_msg_namelen;
59
60 return true;
61 }
62
63 static void
64 free_mmsgvec_data(void *ptr)
65 {
66 char **pstr = ptr;
67 free(*pstr);
68 *pstr = 0;
69
70 free(ptr);
71 }
72
73 struct mmsgvec_data {
74 char *timeout;
75 unsigned int count;
76 int namelen[0];
77 };
78
79 static void
80 save_mmsgvec_namelen(struct tcb *const tcp, kernel_ulong_t addr,
81 unsigned int len, const char *const timeout)
82 {
83 if (len > IOV_MAX)
84 len = IOV_MAX;
85
86 const size_t data_size = offsetof(struct mmsgvec_data, namelen)
87 + sizeof(int) * len;
88 struct mmsgvec_data *const data = xmalloc(data_size);
89 data->timeout = xstrdup(timeout);
90
91 unsigned int i, fetched;
92
93 for (i = 0; i < len; ++i, addr += fetched) {
94 struct mmsghdr mh;
95
96 fetched = fetch_struct_mmsghdr(tcp, addr, &mh);
97 if (!fetched)
98 break;
99 data->namelen[i] = mh.msg_hdr.msg_namelen;
100 }
101 data->count = i;
102
103 set_tcb_priv_data(tcp, data, free_mmsgvec_data);
104 }
105
106 static void
107 decode_mmsgvec(struct tcb *const tcp, const kernel_ulong_t addr,
108 const unsigned int vlen, const unsigned int msg_len_vlen,
109 const bool use_msg_len)
110 {
111 struct mmsghdr mmsg;
112 struct print_struct_mmsghdr_config c = {
113 .msg_len_vlen = msg_len_vlen,
114 .count = IOV_MAX,
115 .use_msg_len = use_msg_len
116 };
117 const struct mmsgvec_data *const data = get_tcb_priv_data(tcp);
118
119 if (data) {
120 if (data->count < c.count)
121 c.count = data->count;
122 c.p_user_msg_namelen = data->namelen;
123 }
124
125 print_array(tcp, addr, vlen, &mmsg, sizeof_struct_mmsghdr(),
126 fetch_struct_mmsghdr_for_print,
127 print_struct_mmsghdr, &c);
128 }
129
130 void
131 dumpiov_in_mmsghdr(struct tcb *const tcp, kernel_ulong_t addr)
132 {
133 unsigned int len = tcp->u_rval;
134 unsigned int fetched;
135
136 for (unsigned int i = 0; i < len; ++i, addr += fetched) {
137 struct mmsghdr mmsg;
138 fetched = fetch_struct_mmsghdr(tcp, addr, &mmsg);
139 if (!fetched)
140 break;
141 tprintf_string(" = %" PRI_klu " buffers in vector %u\n",
142 (kernel_ulong_t) mmsg.msg_hdr.msg_iovlen, i);
143 dumpiov_upto(tcp, mmsg.msg_hdr.msg_iovlen,
144 ptr_to_kulong(mmsg.msg_hdr.msg_iov),
145 mmsg.msg_len);
146 }
147 }
148
149 SYS_FUNC(sendmmsg)
150 {
151 if (entering(tcp)) {
152 /* sockfd */
153 printfd(tcp, tcp->u_arg[0]);
154 tprint_arg_next();
155
156 if (!verbose(tcp)) {
157 /* msgvec */
158 printaddr(tcp->u_arg[1]);
159 tprint_arg_next();
160
161 /* vlen */
162 PRINT_VAL_U((unsigned int) tcp->u_arg[2]);
163 tprint_arg_next();
164
165 /* flags */
166 printflags(msg_flags, tcp->u_arg[3], "MSG_???");
167 return RVAL_DECODED;
168 }
169 } else {
170 const unsigned int msg_len_vlen =
171 syserror(tcp) ? 0 : tcp->u_rval;
172 /* msgvec */
173 temporarily_clear_syserror(tcp);
174 decode_mmsgvec(tcp, tcp->u_arg[1], tcp->u_arg[2],
175 msg_len_vlen, false);
176 restore_cleared_syserror(tcp);
177 tprint_arg_next();
178
179 /* vlen */
180 PRINT_VAL_U((unsigned int) tcp->u_arg[2]);
181 tprint_arg_next();
182
183 /* flags */
184 printflags(msg_flags, tcp->u_arg[3], "MSG_???");
185 }
186 return 0;
187 }
188
189 static int
190 do_recvmmsg(struct tcb *const tcp, const print_obj_by_addr_fn print_ts,
191 const sprint_obj_by_addr_fn sprint_ts)
192 {
193 if (entering(tcp)) {
194 /* sockfd */
195 printfd(tcp, tcp->u_arg[0]);
196 tprint_arg_next();
197
198 if (verbose(tcp)) {
199 save_mmsgvec_namelen(tcp, tcp->u_arg[1], tcp->u_arg[2],
200 sprint_ts(tcp, tcp->u_arg[4]));
201 } else {
202 /* msgvec */
203 printaddr(tcp->u_arg[1]);
204 tprint_arg_next();
205
206 /* vlen */
207 PRINT_VAL_U((unsigned int) tcp->u_arg[2]);
208 tprint_arg_next();
209
210 /* flags */
211 printflags(msg_flags, tcp->u_arg[3], "MSG_???");
212 tprint_arg_next();
213
214 /* timeout */
215 print_ts(tcp, tcp->u_arg[4]);
216 }
217 return 0;
218 } else {
219 if (verbose(tcp)) {
220 /* msgvec */
221 decode_mmsgvec(tcp, tcp->u_arg[1], tcp->u_rval,
222 tcp->u_rval, true);
223 tprint_arg_next();
224
225 /* vlen */
226 PRINT_VAL_U((unsigned int) tcp->u_arg[2]);
227 tprint_arg_next();
228
229 /* flags */
230 printflags(msg_flags, tcp->u_arg[3], "MSG_???");
231 tprint_arg_next();
232
233 /* timeout on entrance */
234 tprints_string(*(const char **) get_tcb_priv_data(tcp));
235 }
236 if (syserror(tcp))
237 return 0;
238 if (tcp->u_rval == 0) {
239 tcp->auxstr = "Timeout";
240 return RVAL_STR;
241 }
242 if (!verbose(tcp) || !tcp->u_arg[4])
243 return 0;
244 /* timeout on exit */
245 static char str[sizeof("left") + TIMESPEC_TEXT_BUFSIZE];
246 xsprintf(str, "left %s", sprint_ts(tcp, tcp->u_arg[4]));
247 tcp->auxstr = str;
248 return RVAL_STR;
249 }
250 }
251
252 #if HAVE_ARCH_TIME32_SYSCALLS
253 SYS_FUNC(recvmmsg_time32)
254 {
255 return do_recvmmsg(tcp, print_timespec32, sprint_timespec32);
256 }
257 #endif
258
259 SYS_FUNC(recvmmsg_time64)
260 {
261 return do_recvmmsg(tcp, print_timespec64, sprint_timespec64);
262 }