1 /* 2 * QEMU monitor file descriptor passing 3 * 4 * Copyright (c) 2003-2004 Fabrice Bellard 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25 #include "qemu/osdep.h" 26 #include "monitor-internal.h" 27 #include "qapi/error.h" 28 #include "qapi/qapi-commands-misc.h" 29 #include "qapi/qmp/qerror.h" 30 #include "qemu/ctype.h" 31 #include "qemu/cutils.h" 32 #include "sysemu/runstate.h" 33 34 /* file descriptors passed via SCM_RIGHTS */ 35 typedef struct mon_fd_t mon_fd_t; 36 struct mon_fd_t { 37 char *name; 38 int fd; 39 QLIST_ENTRY(mon_fd_t) next; 40 }; 41 42 /* file descriptor associated with a file descriptor set */ 43 typedef struct MonFdsetFd MonFdsetFd; 44 struct MonFdsetFd { 45 int fd; 46 char *opaque; 47 QLIST_ENTRY(MonFdsetFd) next; 48 }; 49 50 /* file descriptor set containing fds passed via SCM_RIGHTS */ 51 typedef struct MonFdset MonFdset; 52 struct MonFdset { 53 int64_t id; 54 QLIST_HEAD(, MonFdsetFd) fds; 55 QLIST_HEAD(, MonFdsetFd) dup_fds; 56 QLIST_ENTRY(MonFdset) next; 57 }; 58 59 /* Protects mon_fdsets */ 60 static QemuMutex mon_fdsets_lock; 61 static QLIST_HEAD(, MonFdset) mon_fdsets; 62 63 static bool monitor_add_fd(Monitor *mon, int fd, const char *fdname, Error **errp) 64 { 65 mon_fd_t *monfd; 66 67 if (qemu_isdigit(fdname[0])) { 68 close(fd); 69 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdname", 70 "a name not starting with a digit"); 71 return false; 72 } 73 74 /* See close() call below. */ 75 qemu_mutex_lock(&mon->mon_lock); 76 QLIST_FOREACH(monfd, &mon->fds, next) { 77 int tmp_fd; 78 79 if (strcmp(monfd->name, fdname) != 0) { 80 continue; 81 } 82 83 tmp_fd = monfd->fd; 84 monfd->fd = fd; 85 qemu_mutex_unlock(&mon->mon_lock); 86 /* Make sure close() is outside critical section */ 87 close(tmp_fd); 88 return true; 89 } 90 91 monfd = g_new0(mon_fd_t, 1); 92 monfd->name = g_strdup(fdname); 93 monfd->fd = fd; 94 95 QLIST_INSERT_HEAD(&mon->fds, monfd, next); 96 qemu_mutex_unlock(&mon->mon_lock); 97 return true; 98 } 99 100 #ifdef CONFIG_POSIX 101 void qmp_getfd(const char *fdname, Error **errp) 102 { 103 Monitor *cur_mon = monitor_cur(); 104 int fd; 105 106 fd = qemu_chr_fe_get_msgfd(&cur_mon->chr); 107 if (fd == -1) { 108 error_setg(errp, "No file descriptor supplied via SCM_RIGHTS"); 109 return; 110 } 111 112 monitor_add_fd(cur_mon, fd, fdname, errp); 113 } 114 #endif 115 116 void qmp_closefd(const char *fdname, Error **errp) 117 { 118 Monitor *cur_mon = monitor_cur(); 119 mon_fd_t *monfd; 120 int tmp_fd; 121 122 qemu_mutex_lock(&cur_mon->mon_lock); 123 QLIST_FOREACH(monfd, &cur_mon->fds, next) { 124 if (strcmp(monfd->name, fdname) != 0) { 125 continue; 126 } 127 128 QLIST_REMOVE(monfd, next); 129 tmp_fd = monfd->fd; 130 g_free(monfd->name); 131 g_free(monfd); 132 qemu_mutex_unlock(&cur_mon->mon_lock); 133 /* Make sure close() is outside critical section */ 134 close(tmp_fd); 135 return; 136 } 137 138 qemu_mutex_unlock(&cur_mon->mon_lock); 139 error_setg(errp, "File descriptor named '%s' not found", fdname); 140 } 141 142 int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp) 143 { 144 mon_fd_t *monfd; 145 146 QEMU_LOCK_GUARD(&mon->mon_lock); 147 QLIST_FOREACH(monfd, &mon->fds, next) { 148 int fd; 149 150 if (strcmp(monfd->name, fdname) != 0) { 151 continue; 152 } 153 154 fd = monfd->fd; 155 assert(fd >= 0); 156 157 /* caller takes ownership of fd */ 158 QLIST_REMOVE(monfd, next); 159 g_free(monfd->name); 160 g_free(monfd); 161 162 return fd; 163 } 164 165 error_setg(errp, "File descriptor named '%s' has not been found", fdname); 166 return -1; 167 } 168 169 static void monitor_fdset_free(MonFdset *mon_fdset) 170 { 171 QLIST_REMOVE(mon_fdset, next); 172 g_free(mon_fdset); 173 } 174 175 static void monitor_fdset_free_if_empty(MonFdset *mon_fdset) 176 { 177 /* 178 * Only remove an empty fdset. The fds are owned by the user and 179 * should have been removed with qmp_remove_fd(). The dup_fds are 180 * owned by QEMU and should have been removed with qemu_close(). 181 */ 182 if (QLIST_EMPTY(&mon_fdset->fds) && QLIST_EMPTY(&mon_fdset->dup_fds)) { 183 monitor_fdset_free(mon_fdset); 184 } 185 } 186 187 static void monitor_fdset_fd_free(MonFdsetFd *mon_fdset_fd) 188 { 189 close(mon_fdset_fd->fd); 190 g_free(mon_fdset_fd->opaque); 191 QLIST_REMOVE(mon_fdset_fd, next); 192 g_free(mon_fdset_fd); 193 } 194 195 void monitor_fdsets_cleanup(void) 196 { 197 MonFdset *mon_fdset; 198 MonFdset *mon_fdset_next; 199 200 QEMU_LOCK_GUARD(&mon_fdsets_lock); 201 QLIST_FOREACH_SAFE(mon_fdset, &mon_fdsets, next, mon_fdset_next) { 202 monitor_fdset_free_if_empty(mon_fdset); 203 } 204 } 205 206 AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id, 207 const char *opaque, Error **errp) 208 { 209 int fd; 210 Monitor *mon = monitor_cur(); 211 AddfdInfo *fdinfo; 212 213 fd = qemu_chr_fe_get_msgfd(&mon->chr); 214 if (fd == -1) { 215 error_setg(errp, "No file descriptor supplied via SCM_RIGHTS"); 216 goto error; 217 } 218 219 fdinfo = monitor_fdset_add_fd(fd, has_fdset_id, fdset_id, opaque, errp); 220 if (fdinfo) { 221 return fdinfo; 222 } 223 224 error: 225 if (fd != -1) { 226 close(fd); 227 } 228 return NULL; 229 } 230 231 #ifdef WIN32 232 void qmp_get_win32_socket(const char *infos, const char *fdname, Error **errp) 233 { 234 g_autofree WSAPROTOCOL_INFOW *info = NULL; 235 gsize len; 236 SOCKET sk; 237 int fd; 238 239 info = (void *)g_base64_decode(infos, &len); 240 if (len != sizeof(*info)) { 241 error_setg(errp, "Invalid WSAPROTOCOL_INFOW value"); 242 return; 243 } 244 245 sk = WSASocketW(FROM_PROTOCOL_INFO, 246 FROM_PROTOCOL_INFO, 247 FROM_PROTOCOL_INFO, 248 info, 0, 0); 249 if (sk == INVALID_SOCKET) { 250 error_setg_win32(errp, WSAGetLastError(), "Couldn't import socket"); 251 return; 252 } 253 254 fd = _open_osfhandle(sk, _O_BINARY); 255 if (fd < 0) { 256 error_setg_errno(errp, errno, "Failed to associate a FD with the SOCKET"); 257 closesocket(sk); 258 return; 259 } 260 261 monitor_add_fd(monitor_cur(), fd, fdname, errp); 262 } 263 #endif 264 265 266 void qmp_remove_fd(int64_t fdset_id, bool has_fd, int64_t fd, Error **errp) 267 { 268 MonFdset *mon_fdset; 269 MonFdsetFd *mon_fdset_fd, *mon_fdset_fd_next; 270 char fd_str[60]; 271 272 QEMU_LOCK_GUARD(&mon_fdsets_lock); 273 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { 274 if (mon_fdset->id != fdset_id) { 275 continue; 276 } 277 QLIST_FOREACH_SAFE(mon_fdset_fd, &mon_fdset->fds, next, 278 mon_fdset_fd_next) { 279 if (has_fd) { 280 if (mon_fdset_fd->fd != fd) { 281 continue; 282 } 283 monitor_fdset_fd_free(mon_fdset_fd); 284 break; 285 } else { 286 monitor_fdset_fd_free(mon_fdset_fd); 287 } 288 } 289 if (has_fd && !mon_fdset_fd) { 290 goto error; 291 } 292 monitor_fdset_free_if_empty(mon_fdset); 293 return; 294 } 295 296 error: 297 if (has_fd) { 298 snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64 ", fd:%" PRId64, 299 fdset_id, fd); 300 } else { 301 snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64, fdset_id); 302 } 303 error_setg(errp, "File descriptor named '%s' not found", fd_str); 304 } 305 306 FdsetInfoList *qmp_query_fdsets(Error **errp) 307 { 308 MonFdset *mon_fdset; 309 MonFdsetFd *mon_fdset_fd; 310 FdsetInfoList *fdset_list = NULL; 311 312 QEMU_LOCK_GUARD(&mon_fdsets_lock); 313 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { 314 FdsetInfo *fdset_info = g_malloc0(sizeof(*fdset_info)); 315 316 fdset_info->fdset_id = mon_fdset->id; 317 318 QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { 319 FdsetFdInfo *fdsetfd_info; 320 321 fdsetfd_info = g_malloc0(sizeof(*fdsetfd_info)); 322 fdsetfd_info->fd = mon_fdset_fd->fd; 323 fdsetfd_info->opaque = g_strdup(mon_fdset_fd->opaque); 324 325 QAPI_LIST_PREPEND(fdset_info->fds, fdsetfd_info); 326 } 327 328 QAPI_LIST_PREPEND(fdset_list, fdset_info); 329 } 330 331 return fdset_list; 332 } 333 334 AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id, 335 const char *opaque, Error **errp) 336 { 337 MonFdset *mon_fdset = NULL; 338 MonFdsetFd *mon_fdset_fd; 339 AddfdInfo *fdinfo; 340 341 QEMU_LOCK_GUARD(&mon_fdsets_lock); 342 if (has_fdset_id) { 343 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { 344 /* Break if match found or match impossible due to ordering by ID */ 345 if (fdset_id <= mon_fdset->id) { 346 if (fdset_id < mon_fdset->id) { 347 mon_fdset = NULL; 348 } 349 break; 350 } 351 } 352 } 353 354 if (mon_fdset == NULL) { 355 int64_t fdset_id_prev = -1; 356 MonFdset *mon_fdset_cur = QLIST_FIRST(&mon_fdsets); 357 358 if (has_fdset_id) { 359 if (fdset_id < 0) { 360 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdset-id", 361 "a non-negative value"); 362 return NULL; 363 } 364 /* Use specified fdset ID */ 365 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { 366 mon_fdset_cur = mon_fdset; 367 if (fdset_id < mon_fdset_cur->id) { 368 break; 369 } 370 } 371 } else { 372 /* Use first available fdset ID */ 373 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { 374 mon_fdset_cur = mon_fdset; 375 if (fdset_id_prev == mon_fdset_cur->id - 1) { 376 fdset_id_prev = mon_fdset_cur->id; 377 continue; 378 } 379 break; 380 } 381 } 382 383 mon_fdset = g_malloc0(sizeof(*mon_fdset)); 384 if (has_fdset_id) { 385 mon_fdset->id = fdset_id; 386 } else { 387 mon_fdset->id = fdset_id_prev + 1; 388 } 389 390 /* The fdset list is ordered by fdset ID */ 391 if (!mon_fdset_cur) { 392 QLIST_INSERT_HEAD(&mon_fdsets, mon_fdset, next); 393 } else if (mon_fdset->id < mon_fdset_cur->id) { 394 QLIST_INSERT_BEFORE(mon_fdset_cur, mon_fdset, next); 395 } else { 396 QLIST_INSERT_AFTER(mon_fdset_cur, mon_fdset, next); 397 } 398 } 399 400 mon_fdset_fd = g_malloc0(sizeof(*mon_fdset_fd)); 401 mon_fdset_fd->fd = fd; 402 mon_fdset_fd->opaque = g_strdup(opaque); 403 QLIST_INSERT_HEAD(&mon_fdset->fds, mon_fdset_fd, next); 404 405 fdinfo = g_malloc0(sizeof(*fdinfo)); 406 fdinfo->fdset_id = mon_fdset->id; 407 fdinfo->fd = mon_fdset_fd->fd; 408 409 return fdinfo; 410 } 411 412 int monitor_fdset_dup_fd_add(int64_t fdset_id, int flags, Error **errp) 413 { 414 #ifdef _WIN32 415 error_setg(errp, "Platform does not support fd passing (fdset)"); 416 return -ENOENT; 417 #else 418 MonFdset *mon_fdset; 419 420 QEMU_LOCK_GUARD(&mon_fdsets_lock); 421 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { 422 MonFdsetFd *mon_fdset_fd; 423 MonFdsetFd *mon_fdset_fd_dup; 424 int fd = -1; 425 int dup_fd; 426 int mon_fd_flags; 427 428 if (mon_fdset->id != fdset_id) { 429 continue; 430 } 431 432 QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { 433 mon_fd_flags = fcntl(mon_fdset_fd->fd, F_GETFL); 434 if (mon_fd_flags == -1) { 435 error_setg(errp, "Failed to read file status flags for fd=%d", 436 mon_fdset_fd->fd); 437 return -1; 438 } 439 440 if ((flags & O_ACCMODE) == (mon_fd_flags & O_ACCMODE)) { 441 fd = mon_fdset_fd->fd; 442 break; 443 } 444 } 445 446 if (fd == -1) { 447 errno = EACCES; 448 error_setg(errp, 449 "Failed to find file descriptor with matching flags=0x%x", 450 flags); 451 return -1; 452 } 453 454 dup_fd = qemu_dup_flags(fd, flags); 455 if (dup_fd == -1) { 456 error_setg(errp, "Failed to dup() given file descriptor fd=%d", fd); 457 return -1; 458 } 459 460 mon_fdset_fd_dup = g_malloc0(sizeof(*mon_fdset_fd_dup)); 461 mon_fdset_fd_dup->fd = dup_fd; 462 QLIST_INSERT_HEAD(&mon_fdset->dup_fds, mon_fdset_fd_dup, next); 463 return dup_fd; 464 } 465 466 error_setg(errp, "Failed to find fdset /dev/fdset/%" PRId64, fdset_id); 467 errno = ENOENT; 468 return -1; 469 #endif 470 } 471 472 void monitor_fdset_dup_fd_remove(int dup_fd) 473 { 474 MonFdset *mon_fdset; 475 MonFdsetFd *mon_fdset_fd_dup; 476 477 QEMU_LOCK_GUARD(&mon_fdsets_lock); 478 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { 479 QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) { 480 if (mon_fdset_fd_dup->fd == dup_fd) { 481 QLIST_REMOVE(mon_fdset_fd_dup, next); 482 g_free(mon_fdset_fd_dup); 483 monitor_fdset_free_if_empty(mon_fdset); 484 return; 485 } 486 } 487 } 488 } 489 490 int monitor_fd_param(Monitor *mon, const char *fdname, Error **errp) 491 { 492 int fd; 493 494 if (!qemu_isdigit(fdname[0]) && mon) { 495 fd = monitor_get_fd(mon, fdname, errp); 496 } else { 497 fd = qemu_parse_fd(fdname); 498 if (fd < 0) { 499 error_setg(errp, "Invalid file descriptor number '%s'", 500 fdname); 501 } 502 } 503 504 return fd; 505 } 506 507 static void __attribute__((__constructor__)) monitor_fds_init(void) 508 { 509 qemu_mutex_init(&mon_fdsets_lock); 510 } 511