VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/VBoxClient/wayland-helper-ipc.cpp@ 102468

Last change on this file since 102468 was 102064, checked in by vboxsync, 13 months ago

Additions: X11/Wayland: vboxwl/VBoxClient IPC: Prevent partial reads from IPC socket, bugref:10194.

Do not specify pcbRead parameter to RTLocalIpcSessionRead, so it will attempt to read
entire buffer from IPC socket. This commit also fixes issue when vboxwl was not able to
receive large buffer from VBoxClient.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.0 KB
Line 
1/* $Id: wayland-helper-ipc.cpp 102064 2023-11-10 14:15:11Z vboxsync $ */
2/** @file
3 * Guest Additions - IPC between VBoxClient and vboxwl tool.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#include <sys/types.h>
29#include <pwd.h>
30#include <unistd.h>
31
32#include <iprt/cdefs.h>
33#include <iprt/err.h>
34#include <iprt/linux/sysfs.h>
35#include <iprt/localipc.h>
36#include <iprt/mem.h>
37#include <iprt/crc.h>
38#include <iprt/env.h>
39#include <iprt/process.h>
40#include <iprt/asm.h>
41
42#include <VBox/GuestHost/clipboard-helper.h>
43
44#include "VBoxClient.h"
45#include "wayland-helper-ipc.h"
46
47RTDECL(int) vbcl_wayland_hlp_gtk_ipc_srv_name(char *szBuf, size_t cbBuf)
48{
49 int rc;
50
51 char pszActiveTTY[128];
52 size_t cchRead;
53 struct passwd *pwd;
54
55 AssertReturn(RT_VALID_PTR(szBuf), VERR_INVALID_PARAMETER);
56 AssertReturn(cbBuf > 0, VERR_INVALID_PARAMETER);
57
58 RT_BZERO(szBuf, cbBuf);
59 RT_ZERO(pszActiveTTY);
60
61 rc = RTStrCat(szBuf, cbBuf, "GtkHlpIpcServer-");
62 if (RT_SUCCESS(rc))
63 rc = RTLinuxSysFsReadStrFile(pszActiveTTY, sizeof(pszActiveTTY) - 1 /* reserve last byte for string termination */,
64 &cchRead, "class/tty/tty0/active");
65 if (RT_SUCCESS(rc))
66 rc = RTStrCat(szBuf, cbBuf, pszActiveTTY);
67
68 if (RT_SUCCESS(rc))
69 rc = RTStrCat(szBuf, cbBuf, "-");
70
71 pwd = getpwuid(geteuid());
72 if (RT_VALID_PTR(pwd))
73 {
74 if (RT_VALID_PTR(pwd->pw_name))
75 rc = RTStrCat(szBuf, cbBuf, pwd->pw_name);
76 else
77 rc = VERR_NOT_FOUND;
78 }
79 else
80 rc = VERR_NOT_FOUND;
81
82 return rc;
83}
84
85void vbcl::ipc::packet_dump(vbcl::ipc::packet_t *pPacket)
86{
87 VBClLogVerbose(3, "IPC packet dump:\n");
88 VBClLogVerbose(3, "u64Crc : 0x%x\n", pPacket->u64Crc);
89 VBClLogVerbose(3, "uSessionId: %u\n", pPacket->uSessionId);
90 VBClLogVerbose(3, "idCmd : %u\n", pPacket->idCmd);
91 VBClLogVerbose(3, "cbData: : %u\n", pPacket->cbData);
92}
93
94bool vbcl::ipc::packet_verify(vbcl::ipc::packet_t *pPacket, size_t cbPacket)
95{
96 bool fResult = false;
97
98 AssertPtrReturn(pPacket, VERR_INVALID_PARAMETER);
99 AssertReturn(cbPacket > sizeof(vbcl::ipc::packet_t), VERR_INVALID_PARAMETER);
100
101 AssertReturn( pPacket->idCmd > vbcl::ipc::CMD_UNKNOWN
102 && pPacket->idCmd < vbcl::ipc::CMD_MAX, VERR_INVALID_PARAMETER);
103
104 /* Exact size match. */
105 if (pPacket->cbData == cbPacket)
106 {
107 /* CRC check. */
108 uint64_t u64Crc = pPacket->u64Crc;
109 pPacket->u64Crc = 0;
110 if (u64Crc != 0 && RTCrc64(pPacket, pPacket->cbData) == u64Crc)
111 {
112 /* Verify payload size. */
113 size_t cbPayload = 0;
114
115 switch (pPacket->idCmd)
116 {
117 case vbcl::ipc::CLIP_FORMATS:
118 case vbcl::ipc::CLIP_FORMAT:
119 cbPayload = sizeof(vbcl::ipc::clipboard::formats_packet_t);
120 break;
121
122 case vbcl::ipc::CLIP_DATA:
123 {
124 vbcl::ipc::clipboard::data_packet_t *pDataEx = (vbcl::ipc::clipboard::data_packet_t *)pPacket;
125 cbPayload = sizeof(vbcl::ipc::clipboard::data_packet_t) + pDataEx->cbData;
126 break;
127 }
128
129 default:
130 break;
131 }
132
133 if (pPacket->cbData == cbPayload)
134 fResult = true;
135 else
136 VBClLogVerbose(3, "bad cmd size (%u vs %u)\n", pPacket->cbData, cbPayload);
137 }
138 else
139 VBClLogVerbose(3, "bad crc\n");
140
141 /* Restore CRC. */
142 pPacket->u64Crc = u64Crc;
143 }
144 else
145 VBClLogVerbose(3, "bad size\n");
146
147 return fResult;
148}
149
150int vbcl::ipc::packet_read(uint32_t uSessionId, RTLOCALIPCSESSION hSession, void **ppvData)
151{
152 int rc;
153
154 vbcl::ipc::packet_t Packet;
155
156 AssertPtrReturn(ppvData, VERR_INVALID_PARAMETER);
157
158 rc = RTLocalIpcSessionWaitForData(hSession, VBOX_GTKIPC_RX_TIMEOUT_MS);
159 if (RT_SUCCESS(rc))
160 {
161 /* Read IPC message header. */
162 rc = RTLocalIpcSessionRead(hSession, &Packet, sizeof(Packet), NULL);
163 if (RT_SUCCESS(rc))
164 {
165 bool fCheck = true;
166
167#define _CHECK(_cond, _msg, _ptr) \
168 if (fCheck) \
169 { \
170 fCheck &= _cond; \
171 if (!fCheck) \
172 VBClLogVerbose(3, _msg "\n", _ptr); \
173 }
174
175 _CHECK(Packet.u64Crc > 0, "bad crc: 0x%x", Packet.u64Crc);
176 _CHECK(Packet.uSessionId == uSessionId, "bad session id: %u vs %u", (Packet.uSessionId, uSessionId));
177 _CHECK(Packet.cbData > sizeof(Packet), "bad cbData: %u", Packet.cbData);
178
179 /* Receive the rest of a message. */
180 if (fCheck)
181 {
182 uint8_t *puData;
183
184 puData = (uint8_t *)RTMemAllocZ(Packet.cbData);
185 if (RT_VALID_PTR(puData))
186 {
187 /* Add generic header to the beginning of the output buffer
188 * and receive the rest of the data into it. */
189 memcpy(puData, &Packet, sizeof(Packet));
190
191 rc = RTLocalIpcSessionRead(hSession, puData + sizeof(Packet),
192 Packet.cbData - sizeof(Packet), NULL);
193 if (RT_SUCCESS(rc))
194 {
195 if (vbcl::ipc::packet_verify((vbcl::ipc::packet_t *)puData, Packet.cbData))
196 {
197 /* Now return received data to the caller. */
198 *ppvData = puData;
199 }
200 else
201 rc = VERR_NOT_EQUAL;
202 }
203
204 if (RT_FAILURE(rc))
205 RTMemFree(puData);
206 }
207 else
208 rc = VERR_NO_MEMORY;
209 }
210 else
211 rc = VERR_INVALID_PARAMETER;
212
213 if (RT_FAILURE(rc))
214 vbcl::ipc::packet_dump(&Packet);
215 }
216 }
217
218 return rc;
219}
220
221int vbcl::ipc::packet_write(RTLOCALIPCSESSION hSession, vbcl::ipc::packet_t *pPacket)
222{
223 int rc;
224
225 AssertPtrReturn(pPacket, VERR_INVALID_PARAMETER);
226
227 pPacket->u64Crc = 0;
228 pPacket->u64Crc = RTCrc64(pPacket, pPacket->cbData);
229
230 Assert(pPacket->u64Crc);
231
232 if (vbcl::ipc::packet_verify(pPacket, pPacket->cbData))
233 {
234 rc = RTLocalIpcSessionWrite(hSession, (void *)pPacket, pPacket->cbData);
235 if (RT_SUCCESS(rc))
236 rc = RTLocalIpcSessionFlush(hSession);
237 }
238 else
239 {
240 vbcl::ipc::packet_dump(pPacket);
241 rc = VERR_NOT_EQUAL;
242 }
243
244 return rc;
245}
246
247int vbcl::ipc::clipboard::ClipboardIpc::send_formats(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession)
248{
249 vbcl::ipc::clipboard::formats_packet_t Packet;
250 SHCLFORMATS fFormats;
251 int rc = VINF_SUCCESS;
252
253 RT_ZERO(Packet);
254
255 Packet.Hdr.u64Crc = 0;
256 Packet.Hdr.uSessionId = uSessionId;
257 Packet.Hdr.idCmd = CLIP_FORMATS;
258 Packet.Hdr.cbData = sizeof(Packet);
259
260 fFormats = m_fFmts.wait();
261 if (fFormats != m_fFmts.defaults())
262 {
263 Packet.fFormats = fFormats;
264 rc = vbcl::ipc::packet_write(hIpcSession, &Packet.Hdr);
265 }
266 else
267 rc = VERR_TIMEOUT;
268
269 VBClLogVerbose(3, "%s: send_formats [sid=%u, fmts=0x%x], rc=%Rrc\n",
270 m_fServer ? "server" : "client", uSessionId, fFormats, rc);
271
272 return rc;
273}
274
275int vbcl::ipc::clipboard::ClipboardIpc::recv_formats(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession)
276{
277 int rc;
278 vbcl::ipc::clipboard::formats_packet_t *pPacket;
279 vbcl::ipc::command_t idCmd = CMD_UNKNOWN;
280 SHCLFORMATS fFormats = VBOX_SHCL_FMT_NONE;
281
282 rc = vbcl::ipc::packet_read(uSessionId, hIpcSession, (void **)&pPacket);
283 if (RT_SUCCESS(rc))
284 {
285 if ( pPacket->Hdr.idCmd == CLIP_FORMATS
286 && vbcl::ipc::packet_verify(&pPacket->Hdr, pPacket->Hdr.cbData))
287 {
288 fFormats = pPacket->fFormats;
289 idCmd = pPacket->Hdr.idCmd;
290 m_fFmts.set(fFormats);
291 }
292 else
293 rc = VERR_WRONG_ORDER;
294
295 RTMemFree(pPacket);
296 }
297
298 VBClLogVerbose(3, "%s: recv_formats [sid=%u, cmd=0x%x, fmts=0x%x], rc=%Rrc\n",
299 m_fServer ? "server" : "client", uSessionId, idCmd, fFormats, rc);
300
301 return rc;
302}
303
304int vbcl::ipc::clipboard::ClipboardIpc::send_format(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession)
305{
306 vbcl::ipc::clipboard::formats_packet_t Packet;
307 SHCLFORMAT uFormat;
308 int rc = VINF_SUCCESS;
309
310 RT_ZERO(Packet);
311
312 Packet.Hdr.u64Crc = 0;
313 Packet.Hdr.uSessionId = uSessionId;
314 Packet.Hdr.idCmd = CLIP_FORMAT;
315 Packet.Hdr.cbData = sizeof(Packet);
316
317 uFormat = m_uFmt.wait();
318 if (uFormat != m_uFmt.defaults())
319 {
320 Packet.fFormats = uFormat;
321 rc = vbcl::ipc::packet_write(hIpcSession, &Packet.Hdr);
322 }
323 else
324 rc = VERR_TIMEOUT;
325
326 VBClLogVerbose(3, "%s: send_format [sid=%u, fmt=0x%x], rc=%Rrc\n",
327 m_fServer ? "server" : "client", uSessionId, uFormat, rc);
328
329 return rc;
330}
331
332int vbcl::ipc::clipboard::ClipboardIpc::recv_format(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession)
333{
334 int rc;
335 vbcl::ipc::clipboard::formats_packet_t *pPacket;
336 vbcl::ipc::command_t idCmd = CMD_UNKNOWN;
337 SHCLFORMATS uFormat = VBOX_SHCL_FMT_NONE;
338
339 rc = vbcl::ipc::packet_read(uSessionId, hIpcSession, (void **)&pPacket);
340 if (RT_SUCCESS(rc))
341 {
342 if ( pPacket->Hdr.idCmd == CLIP_FORMAT
343 && vbcl::ipc::packet_verify(&pPacket->Hdr, pPacket->Hdr.cbData))
344 {
345 uFormat = pPacket->fFormats;
346 idCmd = pPacket->Hdr.idCmd;
347 m_uFmt.set(uFormat);
348 }
349 else
350 rc = VERR_WRONG_ORDER;
351
352 RTMemFree(pPacket);
353 }
354
355 VBClLogVerbose(3, "%s: recv_format [sid=%u, cmd=0x%x, fmts=0x%x], rc=%Rrc\n",
356 m_fServer ? "server" : "client", uSessionId, idCmd, uFormat, rc);
357
358 return rc;
359}
360
361int vbcl::ipc::clipboard::ClipboardIpc::send_data(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession)
362{
363 vbcl::ipc::clipboard::data_packet_t *pPacket;
364 int rc = VINF_SUCCESS;
365
366 void *pvData;
367 uint32_t cbData;
368
369 cbData = m_cbClipboardBuf.wait();
370 pvData = (void *)m_pvClipboardBuf.wait();
371 if ( cbData != m_cbClipboardBuf.defaults()
372 && pvData != (void *)m_pvClipboardBuf.defaults())
373 {
374 pPacket = (vbcl::ipc::clipboard::data_packet_t *)RTMemAllocZ(sizeof(vbcl::ipc::clipboard::data_packet_t) + cbData);
375 if (RT_VALID_PTR(pPacket))
376 {
377 pPacket->Hdr.u64Crc = 0;
378 pPacket->Hdr.uSessionId = uSessionId;
379 pPacket->Hdr.idCmd = CLIP_DATA;
380 pPacket->Hdr.cbData = sizeof(vbcl::ipc::clipboard::data_packet_t) + cbData;
381 pPacket->cbData = cbData;
382
383 memcpy((uint8_t *)pPacket + sizeof(vbcl::ipc::clipboard::data_packet_t), pvData, cbData);
384 rc = vbcl::ipc::packet_write(hIpcSession, &pPacket->Hdr);
385 RTMemFree(pPacket);
386 }
387 else
388 rc = VERR_NO_MEMORY;
389 }
390 else
391 rc = VERR_TIMEOUT;
392
393 VBClLogVerbose(3, "%s: send_data [sid=%u, cbData=%u], rc=%Rrc\n",
394 m_fServer ? "server" : "client", uSessionId, cbData, rc);
395
396 return rc;
397}
398
399int vbcl::ipc::clipboard::ClipboardIpc::recv_data(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession)
400{
401 int rc;
402 vbcl::ipc::clipboard::data_packet_t *pPacket;
403 vbcl::ipc::command_t idCmd = CMD_UNKNOWN;
404 uint32_t cbData = 0;
405
406 rc = vbcl::ipc::packet_read(uSessionId, hIpcSession, (void **)&pPacket);
407 if (RT_SUCCESS(rc))
408 {
409 if ( pPacket->Hdr.idCmd == CLIP_DATA
410 && vbcl::ipc::packet_verify(&pPacket->Hdr, pPacket->Hdr.cbData))
411 {
412 void *pvData = RTMemAllocZ(pPacket->cbData);
413 idCmd = pPacket->Hdr.idCmd;
414 if (RT_VALID_PTR(pvData))
415 {
416 memcpy(pvData, (uint8_t *)pPacket + sizeof(vbcl::ipc::clipboard::data_packet_t), pPacket->cbData);
417 m_pvClipboardBuf.set((uint64_t)pvData);
418 cbData = pPacket->cbData;
419 m_cbClipboardBuf.set(cbData);
420 }
421 else
422 rc = VERR_NO_MEMORY;
423 }
424 else
425 rc = VERR_WRONG_ORDER;
426
427 RTMemFree(pPacket);
428 }
429
430 VBClLogVerbose(3, "%s: recv_data [sid=%u, cmd=0x%x, cbData=%u], rc=%Rrc\n",
431 m_fServer ? "server" : "client", uSessionId, idCmd, cbData, rc);
432
433 return rc;
434}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette