VirtualBox

source: vbox/trunk/include/VBox/HostServices/GuestPropertySvc.h@ 94290

最後變更 在這個檔案從94290是 93891,由 vboxsync 提交於 3 年 前

Main: Guest Properties: improved property name and value validation, bugref:10185.

This commit also prevents guest properties loss if they were set while VM was running.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id Revision
檔案大小: 19.3 KB
 
1/** @file
2 * Guest property service - Common header for host service and guest clients.
3 */
4
5/*
6 * Copyright (C) 2006-2022 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.alldomusa.eu.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * The contents of this file may alternatively be used under the terms
17 * of the Common Development and Distribution License Version 1.0
18 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
19 * VirtualBox OSE distribution, in which case the provisions of the
20 * CDDL are applicable instead of those of the GPL.
21 *
22 * You may elect to license modified versions of this file under the
23 * terms and conditions of either the GPL or the CDDL or both.
24 */
25
26#ifndef VBOX_INCLUDED_HostServices_GuestPropertySvc_h
27#define VBOX_INCLUDED_HostServices_GuestPropertySvc_h
28#ifndef RT_WITHOUT_PRAGMA_ONCE
29# pragma once
30#endif
31
32#include <VBox/VMMDevCoreTypes.h>
33#include <VBox/VBoxGuestCoreTypes.h>
34#include <VBox/log.h>
35#include <iprt/err.h>
36#include <iprt/assertcompile.h>
37#include <iprt/string.h>
38
39
40/** Maximum length for property names. */
41#define GUEST_PROP_MAX_NAME_LEN 64
42/** Maximum length for property values. */
43#define GUEST_PROP_MAX_VALUE_LEN 128
44/** Maximum number of properties per guest. */
45#define GUEST_PROP_MAX_PROPS 256
46/** Maximum size for enumeration patterns. */
47#define GUEST_PROP_MAX_PATTERN_LEN 1024
48/** Maximum number of changes we remember for guest notifications. */
49#define GUEST_PROP_MAX_GUEST_NOTIFICATIONS 256
50/** Maximum number of current pending waits per client. */
51#define GUEST_PROP_MAX_GUEST_CONCURRENT_WAITS 16
52
53
54/** @name GUEST_PROP_F_XXX - The guest property flag values which are currently accepted.
55 * @{
56 */
57#define GUEST_PROP_F_NILFLAG UINT32_C(0)
58/** Transient until VM gets shut down. */
59#define GUEST_PROP_F_TRANSIENT RT_BIT_32(1)
60#define GUEST_PROP_F_RDONLYGUEST RT_BIT_32(2)
61#define GUEST_PROP_F_RDONLYHOST RT_BIT_32(3)
62/** Transient until VM gets a reset / restarts.
63 * Implies TRANSIENT. */
64#define GUEST_PROP_F_TRANSRESET RT_BIT_32(4)
65#define GUEST_PROP_F_READONLY (GUEST_PROP_F_RDONLYGUEST | GUEST_PROP_F_RDONLYHOST)
66#define GUEST_PROP_F_ALLFLAGS (GUEST_PROP_F_TRANSIENT | GUEST_PROP_F_READONLY | GUEST_PROP_F_TRANSRESET)
67/** @} */
68
69/**
70 * Check that a string fits our criteria for a property name.
71 *
72 * @returns IPRT status code
73 * @param pszName the string to check, must be valid Utf8
74 * @param cbName the number of bytes @a pszName points to, including the terminating character.
75 */
76DECLINLINE(int) GuestPropValidateName(const char *pszName, uint32_t cbName)
77{
78 /* Property name is expected to be at least 1 charecter long plus terminating character. */
79 AssertReturn(cbName >= 2, VERR_INVALID_PARAMETER);
80 AssertReturn(cbName < GUEST_PROP_MAX_NAME_LEN, VERR_INVALID_PARAMETER);
81
82 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
83
84 AssertReturn(memchr(pszName, '*', cbName) == NULL, VERR_INVALID_PARAMETER);
85 AssertReturn(memchr(pszName, '?', cbName) == NULL, VERR_INVALID_PARAMETER);
86 AssertReturn(memchr(pszName, '|', cbName) == NULL, VERR_INVALID_PARAMETER);
87
88 return VINF_SUCCESS;
89}
90
91/**
92 * Check a string fits our criteria for the value of a guest property.
93 *
94 * @returns IPRT status code
95 * @param pszValue the string to check, must be valid Utf8
96 * @param cbValue the length in bytes of @a pszValue, including the
97 * terminator
98 * @thread HGCM
99 */
100DECLINLINE(int) GuestPropValidateValue(const char *pszValue, uint32_t cbValue)
101{
102 AssertPtrReturn(pszValue, VERR_INVALID_POINTER);
103
104 /* Zero-length values are possible, however buffer should contain terminating character at least. */
105 AssertReturn(cbValue > 0, VERR_INVALID_PARAMETER);
106 AssertReturn(cbValue < GUEST_PROP_MAX_VALUE_LEN, VERR_INVALID_PARAMETER);
107
108 return VINF_SUCCESS;
109}
110
111/**
112 * Get the name of a flag as a string.
113 * @returns the name, or NULL if fFlag is invalid.
114 * @param fFlag The flag, GUEST_PROP_F_XXX.
115 * @param pcchName Where to return the name length.
116 */
117DECLINLINE(const char *) GuestPropFlagNameAndLen(uint32_t fFlag, size_t *pcchName)
118{
119 switch (fFlag)
120 {
121 case GUEST_PROP_F_TRANSIENT:
122 *pcchName = sizeof("TRANSIENT") - 1;
123 return "TRANSIENT";
124 case GUEST_PROP_F_RDONLYGUEST:
125 *pcchName = sizeof("RDONLYGUEST") - 1;
126 return "RDONLYGUEST";
127 case GUEST_PROP_F_RDONLYHOST:
128 *pcchName = sizeof("RDONLYHOST") - 1;
129 return "RDONLYHOST";
130 case GUEST_PROP_F_READONLY:
131 *pcchName = sizeof("READONLY") - 1;
132 return "READONLY";
133 case GUEST_PROP_F_TRANSRESET:
134 *pcchName = sizeof("TRANSRESET") - 1;
135 return "TRANSRESET";
136 default:
137 *pcchName = 0;
138 return NULL;
139 }
140}
141
142/**
143 * Maximum length for the property flags field. We only ever return one of
144 * RDONLYGUEST, RDONLYHOST and RDONLY
145 */
146#define GUEST_PROP_MAX_FLAGS_LEN sizeof("TRANSIENT, RDONLYGUEST, TRANSRESET")
147
148/**
149 * Parse a guest properties flags string for flag names and make sure that
150 * there is no junk text in the string.
151 *
152 * @returns IPRT status code
153 * @retval VERR_INVALID_PARAMETER if the flag string is not valid
154 * @param pcszFlags the flag string to parse
155 * @param pfFlags where to store the parse result. May not be NULL.
156 * @note This function is also inline because it must be accessible from
157 * several modules and it does not seem reasonable to put it into
158 * its own library.
159 */
160DECLINLINE(int) GuestPropValidateFlags(const char *pcszFlags, uint32_t *pfFlags)
161{
162 static const uint32_t s_aFlagList[] =
163 {
164 GUEST_PROP_F_TRANSIENT, GUEST_PROP_F_READONLY, GUEST_PROP_F_RDONLYGUEST, GUEST_PROP_F_RDONLYHOST, GUEST_PROP_F_TRANSRESET
165 };
166 const char *pcszNext = pcszFlags;
167 int rc = VINF_SUCCESS;
168 uint32_t fFlags = 0;
169 AssertLogRelReturn(RT_VALID_PTR(pfFlags), VERR_INVALID_POINTER);
170
171 if (pcszFlags)
172 {
173 while (*pcszNext == ' ')
174 ++pcszNext;
175 while ((*pcszNext != '\0') && RT_SUCCESS(rc))
176 {
177 unsigned i;
178 rc = VERR_PARSE_ERROR;
179 for (i = 0; i < RT_ELEMENTS(s_aFlagList); ++i)
180 {
181 size_t cchFlagName;
182 const char *pszFlagName = GuestPropFlagNameAndLen(s_aFlagList[i], &cchFlagName);
183 if (RTStrNICmpAscii(pcszNext, pszFlagName, cchFlagName) == 0)
184 {
185 char ch;
186 fFlags |= s_aFlagList[i];
187 pcszNext += cchFlagName;
188 while ((ch = *pcszNext) == ' ')
189 ++pcszNext;
190 rc = VINF_SUCCESS;
191 if (ch == ',')
192 {
193 ++pcszNext;
194 while (*pcszNext == ' ')
195 ++pcszNext;
196 }
197 else if (ch != '\0')
198 rc = VERR_PARSE_ERROR;
199 break;
200 }
201 }
202 }
203 }
204 if (RT_SUCCESS(rc))
205 *pfFlags = fFlags;
206 return rc;
207}
208
209
210/**
211 * Write out flags to a string.
212 * @returns IPRT status code
213 * @param fFlags the flags to write out
214 * @param pszFlags where to write the flags string. This must point to
215 * a buffer of size (at least) GUEST_PROP_MAX_FLAGS_LEN.
216 */
217DECLINLINE(int) GuestPropWriteFlags(uint32_t fFlags, char *pszFlags)
218{
219 /* Putting READONLY before the other RDONLY flags keeps the result short. */
220 static const uint32_t s_aFlagList[] =
221 {
222 GUEST_PROP_F_TRANSIENT, GUEST_PROP_F_READONLY, GUEST_PROP_F_RDONLYGUEST, GUEST_PROP_F_RDONLYHOST, GUEST_PROP_F_TRANSRESET
223 };
224 int rc = VINF_SUCCESS;
225
226 AssertLogRelReturn(RT_VALID_PTR(pszFlags), VERR_INVALID_POINTER);
227 if ((fFlags & ~GUEST_PROP_F_ALLFLAGS) == GUEST_PROP_F_NILFLAG)
228 {
229 char *pszNext;
230 unsigned i;
231
232 /* TRANSRESET implies TRANSIENT. For compatability with old clients we
233 always set TRANSIENT when TRANSRESET appears. */
234 if (fFlags & GUEST_PROP_F_TRANSRESET)
235 fFlags |= GUEST_PROP_F_TRANSIENT;
236
237 pszNext = pszFlags;
238 for (i = 0; i < RT_ELEMENTS(s_aFlagList); ++i)
239 {
240 if (s_aFlagList[i] == (fFlags & s_aFlagList[i]))
241 {
242 size_t cchFlagName;
243 const char *pszFlagName = GuestPropFlagNameAndLen(s_aFlagList[i], &cchFlagName);
244 memcpy(pszNext, pszFlagName, cchFlagName);
245 pszNext += cchFlagName;
246 fFlags &= ~s_aFlagList[i];
247 if (fFlags != GUEST_PROP_F_NILFLAG)
248 {
249 *pszNext++ = ',';
250 *pszNext++ = ' ';
251 }
252 }
253 }
254 *pszNext = '\0';
255
256 Assert((uintptr_t)(pszNext - pszFlags) < GUEST_PROP_MAX_FLAGS_LEN);
257 Assert(fFlags == GUEST_PROP_F_NILFLAG); /* bad s_aFlagList */
258 }
259 else
260 rc = VERR_INVALID_PARAMETER;
261 return rc;
262}
263
264
265/** @name The service functions which are callable by host.
266 * @{
267 */
268/** Set properties in a block.
269 * The parameters are pointers to NULL-terminated arrays containing the
270 * parameters. These are, in order, name, value, timestamp, flags. Strings are
271 * stored as pointers to mutable utf8 data. All parameters must be supplied. */
272#define GUEST_PROP_FN_HOST_SET_PROPS 1
273/** Get the value attached to a guest property.
274 * The parameter format matches that of GET_PROP. */
275#define GUEST_PROP_FN_HOST_GET_PROP 2
276/** Set the value attached to a guest property.
277 * The parameter format matches that of SET_PROP. */
278#define GUEST_PROP_FN_HOST_SET_PROP 3
279/** Set the value attached to a guest property.
280 * The parameter format matches that of SET_PROP_VALUE. */
281#define GUEST_PROP_FN_HOST_SET_PROP_VALUE 4
282/** Remove a guest property.
283 * The parameter format matches that of DEL_PROP. */
284#define GUEST_PROP_FN_HOST_DEL_PROP 5
285/** Enumerate guest properties.
286 * The parameter format matches that of ENUM_PROPS. */
287#define GUEST_PROP_FN_HOST_ENUM_PROPS 6
288/** Set global flags for the service.
289 * Currently RDONLYGUEST is supported. Takes one 32-bit unsigned integer
290 * parameter for the flags. */
291#define GUEST_PROP_FN_HOST_SET_GLOBAL_FLAGS 7
292/** @} */
293
294
295/** @name The service functions which are called by guest.
296 *
297 * @note The numbers may not change!
298 * @{
299 */
300/** Get a guest property */
301#define GUEST_PROP_FN_GET_PROP 1
302/** Set a guest property */
303#define GUEST_PROP_FN_SET_PROP 2
304/** Set just the value of a guest property */
305#define GUEST_PROP_FN_SET_PROP_VALUE 3
306/** Delete a guest property */
307#define GUEST_PROP_FN_DEL_PROP 4
308/** Enumerate guest properties */
309#define GUEST_PROP_FN_ENUM_PROPS 5
310/** Poll for guest notifications */
311#define GUEST_PROP_FN_GET_NOTIFICATION 6
312/** @} */
313
314
315/**
316 * Data structure to pass to the service extension callback.
317 * We use this to notify the host of changes to properties.
318 */
319typedef struct GUESTPROPHOSTCALLBACKDATA
320{
321 /** Magic number to identify the structure (GUESTPROPHOSTCALLBACKDATA_MAGIC). */
322 uint32_t u32Magic;
323 /** The name of the property that was changed */
324 const char *pcszName;
325 /** The new property value, or NULL if the property was deleted */
326 const char *pcszValue;
327 /** The timestamp of the modification */
328 uint64_t u64Timestamp;
329 /** The flags field of the modified property */
330 const char *pcszFlags;
331} GUESTPROPHOSTCALLBACKDATA;
332/** Poitner to a data structure to pass to the service extension callback. */
333typedef GUESTPROPHOSTCALLBACKDATA *PGUESTPROPHOSTCALLBACKDATA;
334
335/** Magic number for sanity checking the HOSTCALLBACKDATA structure */
336#define GUESTPROPHOSTCALLBACKDATA_MAGIC UINT32_C(0x69c87a78)
337
338/**
339 * HGCM parameter structures. Packing is explicitly defined as this is a wire format.
340 */
341/** The guest is requesting the value of a property */
342typedef struct GuestPropMsgGetProperty
343{
344 VBGLIOCHGCMCALL hdr;
345
346 /**
347 * The property name (IN pointer)
348 * This must fit to a number of criteria, namely
349 * - Only Utf8 strings are allowed
350 * - Less than or equal to MAX_NAME_LEN bytes in length
351 * - Zero terminated
352 */
353 HGCMFunctionParameter name;
354
355 /**
356 * The returned string data will be placed here. (OUT pointer)
357 * This call returns two null-terminated strings which will be placed one
358 * after another: value and flags.
359 */
360 HGCMFunctionParameter buffer;
361
362 /**
363 * The property timestamp. (OUT uint64_t)
364 */
365 HGCMFunctionParameter timestamp;
366
367 /**
368 * If the buffer provided was large enough this will contain the size of
369 * the returned data. Otherwise it will contain the size of the buffer
370 * needed to hold the data and VERR_BUFFER_OVERFLOW will be returned.
371 * (OUT uint32_t)
372 */
373 HGCMFunctionParameter size;
374} GuestPropMsgGetProperty;
375AssertCompileSize(GuestPropMsgGetProperty, 40 + 4 * (ARCH_BITS == 64 ? 16 : 12));
376
377/** The guest is requesting to change a property */
378typedef struct GuestPropMsgSetProperty
379{
380 VBGLIOCHGCMCALL hdr;
381
382 /**
383 * The property name. (IN pointer)
384 * This must fit to a number of criteria, namely
385 * - Only Utf8 strings are allowed
386 * - Less than or equal to MAX_NAME_LEN bytes in length
387 * - Zero terminated
388 */
389 HGCMFunctionParameter name;
390
391 /**
392 * The value of the property (IN pointer)
393 * Criteria as for the name parameter, but with length less than or equal to
394 * MAX_VALUE_LEN.
395 */
396 HGCMFunctionParameter value;
397
398 /**
399 * The property flags (IN pointer)
400 * This is a comma-separated list of the format flag=value
401 * The length must be less than or equal to GUEST_PROP_MAX_FLAGS_LEN and only
402 * known flag names and values will be accepted.
403 */
404 HGCMFunctionParameter flags;
405} GuestPropMsgSetProperty;
406AssertCompileSize(GuestPropMsgSetProperty, 40 + 3 * (ARCH_BITS == 64 ? 16 : 12));
407
408/** The guest is requesting to change the value of a property */
409typedef struct GuestPropMsgSetPropertyValue
410{
411 VBGLIOCHGCMCALL hdr;
412
413 /**
414 * The property name. (IN pointer)
415 * This must fit to a number of criteria, namely
416 * - Only Utf8 strings are allowed
417 * - Less than or equal to MAX_NAME_LEN bytes in length
418 * - Zero terminated
419 */
420 HGCMFunctionParameter name;
421
422 /**
423 * The value of the property (IN pointer)
424 * Criteria as for the name parameter, but with length less than or equal to
425 * MAX_VALUE_LEN.
426 */
427 HGCMFunctionParameter value;
428} GuestPropMsgSetPropertyValue;
429AssertCompileSize(GuestPropMsgSetPropertyValue, 40 + 2 * (ARCH_BITS == 64 ? 16 : 12));
430
431/** The guest is requesting to remove a property */
432typedef struct GuestPropMsgDelProperty
433{
434 VBGLIOCHGCMCALL hdr;
435
436 /**
437 * The property name. This must fit to a number of criteria, namely
438 * - Only Utf8 strings are allowed
439 * - Less than or equal to MAX_NAME_LEN bytes in length
440 * - Zero terminated
441 */
442 HGCMFunctionParameter name;
443} GuestPropMsgDelProperty;
444AssertCompileSize(GuestPropMsgDelProperty, 40 + 1 * (ARCH_BITS == 64 ? 16 : 12));
445
446/** The guest is requesting to enumerate properties */
447typedef struct GuestPropMsgEnumProperties
448{
449 VBGLIOCHGCMCALL hdr;
450
451 /**
452 * Array of patterns to match the properties against, separated by '|'
453 * characters. For backwards compatibility, '\\0' is also accepted
454 * as a separater.
455 * (IN pointer)
456 * If only a single, empty pattern is given then match all.
457 */
458 HGCMFunctionParameter patterns;
459 /**
460 * On success, null-separated array of strings in which the properties are
461 * returned. (OUT pointer)
462 * The number of strings in the array is always a multiple of four,
463 * and in sequences of name, value, timestamp (hexadecimal string) and the
464 * flags as a comma-separated list in the format "name=value". The list
465 * is terminated by an empty string after a "flags" entry (or at the
466 * start).
467 */
468 HGCMFunctionParameter strings;
469 /**
470 * On success, the size of the returned data. If the buffer provided is
471 * too small, the size of buffer needed. (OUT uint32_t)
472 */
473 HGCMFunctionParameter size;
474} GuestPropMsgEnumProperties;
475AssertCompileSize(GuestPropMsgEnumProperties, 40 + 3 * (ARCH_BITS == 64 ? 16 : 12));
476
477/**
478 * The guest is polling for notifications on changes to properties, specifying
479 * a set of patterns to match the names of changed properties against and
480 * optionally the timestamp of the last notification seen.
481 * On success, VINF_SUCCESS will be returned and the buffer will contain
482 * details of a property notification. If no new notification is available
483 * which matches one of the specified patterns, the call will block until one
484 * is.
485 * If the last notification could not be found by timestamp, VWRN_NOT_FOUND
486 * will be returned and the oldest available notification will be returned.
487 * If a zero timestamp is specified, the call will always wait for a new
488 * notification to arrive.
489 * If the buffer supplied was not large enough to hold the notification,
490 * VERR_BUFFER_OVERFLOW will be returned and the size parameter will contain
491 * the size of the buffer needed.
492 *
493 * The protocol for a guest to obtain notifications is to call
494 * GET_NOTIFICATION in a loop. On the first call, the ingoing timestamp
495 * parameter should be set to zero. On subsequent calls, it should be set to
496 * the outgoing timestamp from the previous call.
497 */
498typedef struct GuestPropMsgGetNotification
499{
500 VBGLIOCHGCMCALL hdr;
501
502 /**
503 * A list of patterns to match the guest event name against, separated by
504 * vertical bars (|) (IN pointer)
505 * An empty string means match all.
506 */
507 HGCMFunctionParameter patterns;
508 /**
509 * The timestamp of the last change seen (IN uint64_t)
510 * This may be zero, in which case the oldest available change will be
511 * sent. If the service does not remember an event matching the
512 * timestamp, then VWRN_NOT_FOUND will be returned, and the guest should
513 * assume that it has missed a certain number of notifications.
514 *
515 * The timestamp of the change being notified of (OUT uint64_t)
516 * Undefined on failure.
517 */
518 HGCMFunctionParameter timestamp;
519
520 /**
521 * The returned data, if any, will be placed here. (OUT pointer)
522 * This call returns three null-terminated strings which will be placed
523 * one after another: name, value and flags. For a delete notification,
524 * value and flags will be empty strings. Undefined on failure.
525 */
526 HGCMFunctionParameter buffer;
527
528 /**
529 * On success, the size of the returned data. (OUT uint32_t)
530 * On buffer overflow, the size of the buffer needed to hold the data.
531 * Undefined on failure.
532 */
533 HGCMFunctionParameter size;
534} GuestPropMsgGetNotification;
535AssertCompileSize(GuestPropMsgGetNotification, 40 + 4 * (ARCH_BITS == 64 ? 16 : 12));
536
537
538#endif /* !VBOX_INCLUDED_HostServices_GuestPropertySvc_h */
539
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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