qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

Merge remote-tracking branch 'remotes/berrange/tags/socket-next-pull-request' into staging

Add support for UNIX sockets in the abstract namespace

# gpg: Signature made Wed 20 May 2020 13:58:43 BST
# gpg: using RSA key DAF3A6FDB26B62912D0E8E3FBE86EBB415104FDF
# gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" [full]
# gpg: aka "Daniel P. Berrange <berrange@redhat.com>" [full]
# Primary key fingerprint: DAF3 A6FD B26B 6291 2D0E 8E3F BE86 EBB4 1510 4FDF

* remotes/berrange/tags/socket-next-pull-request:
qemu-options: updates for abstract unix sockets
tests/util-sockets: add abstract unix socket cases
qemu-sockets: add abstract UNIX domain socket support

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

+148 -10
+4
chardev/char-socket.c
··· 1380 1380 const char *host = qemu_opt_get(opts, "host"); 1381 1381 const char *port = qemu_opt_get(opts, "port"); 1382 1382 const char *fd = qemu_opt_get(opts, "fd"); 1383 + bool tight = qemu_opt_get_bool(opts, "tight", true); 1384 + bool abstract = qemu_opt_get_bool(opts, "abstract", false); 1383 1385 SocketAddressLegacy *addr; 1384 1386 ChardevSocket *sock; 1385 1387 ··· 1431 1433 addr->type = SOCKET_ADDRESS_LEGACY_KIND_UNIX; 1432 1434 q_unix = addr->u.q_unix.data = g_new0(UnixSocketAddress, 1); 1433 1435 q_unix->path = g_strdup(path); 1436 + q_unix->tight = tight; 1437 + q_unix->abstract = abstract; 1434 1438 } else if (host) { 1435 1439 addr->type = SOCKET_ADDRESS_LEGACY_KIND_INET; 1436 1440 addr->u.inet.data = g_new(InetSocketAddress, 1);
+7
chardev/char.c
··· 939 939 },{ 940 940 .name = "logappend", 941 941 .type = QEMU_OPT_BOOL, 942 + },{ 943 + .name = "tight", 944 + .type = QEMU_OPT_BOOL, 945 + .def_value_str = "on", 946 + },{ 947 + .name = "abstract", 948 + .type = QEMU_OPT_BOOL, 942 949 }, 943 950 { /* end of list */ } 944 951 },
+7 -1
qapi/sockets.json
··· 73 73 # Captures a socket address in the local ("Unix socket") namespace. 74 74 # 75 75 # @path: filesystem path to use 76 + # @tight: pass a socket address length confined to the minimum length of the 77 + # abstract string, rather than the full sockaddr_un record length 78 + # (only matters for abstract sockets, default true). (Since 5.1) 79 + # @abstract: whether this is an abstract address, default false. (Since 5.1) 76 80 # 77 81 # Since: 1.3 78 82 ## 79 83 { 'struct': 'UnixSocketAddress', 80 84 'data': { 81 - 'path': 'str' } } 85 + 'path': 'str', 86 + '*tight': 'bool', 87 + '*abstract': 'bool' } } 82 88 83 89 ## 84 90 # @VsockSocketAddress:
+6 -2
qemu-options.hx
··· 2938 2938 " [,server][,nowait][,telnet][,websocket][,reconnect=seconds][,mux=on|off]\n" 2939 2939 " [,logfile=PATH][,logappend=on|off][,tls-creds=ID][,tls-authz=ID] (tcp)\n" 2940 2940 "-chardev socket,id=id,path=path[,server][,nowait][,telnet][,websocket][,reconnect=seconds]\n" 2941 - " [,mux=on|off][,logfile=PATH][,logappend=on|off] (unix)\n" 2941 + " [,mux=on|off][,logfile=PATH][,logappend=on|off][,abstract=on|off][,tight=on|off] (unix)\n" 2942 2942 "-chardev udp,id=id[,host=host],port=port[,localaddr=localaddr]\n" 2943 2943 " [,localport=localport][,ipv4][,ipv6][,mux=on|off]\n" 2944 2944 " [,logfile=PATH][,logappend=on|off]\n" ··· 3105 3105 3106 3106 ``nodelay`` disables the Nagle algorithm. 3107 3107 3108 - ``unix options: path=path`` 3108 + ``unix options: path=path[,abstract=on|off][,tight=on|off]`` 3109 3109 ``path`` specifies the local path of the unix socket. ``path`` 3110 3110 is required. 3111 + ``abstract`` specifies the use of the abstract socket namespace, 3112 + rather than the filesystem. Optional, defaults to false. 3113 + ``tight`` sets the socket length of abstract sockets to their minimum, 3114 + rather than the full sun_path length. Optional, defaults to true. 3111 3115 3112 3116 ``-chardev udp,id=id[,host=host],port=port[,localaddr=localaddr][,localport=localport][,ipv4][,ipv6]`` 3113 3117 Sends all traffic from the guest to a remote host over UDP.
+92
tests/test-util-sockets.c
··· 227 227 g_free(addr.u.fd.str); 228 228 } 229 229 230 + #ifdef __linux__ 231 + static gchar *abstract_sock_name; 232 + 233 + static gpointer unix_server_thread_func(gpointer user_data) 234 + { 235 + SocketAddress addr; 236 + Error *err = NULL; 237 + int fd = -1; 238 + int connfd = -1; 239 + struct sockaddr_un un; 240 + socklen_t len = sizeof(un); 241 + 242 + addr.type = SOCKET_ADDRESS_TYPE_UNIX; 243 + addr.u.q_unix.path = abstract_sock_name; 244 + addr.u.q_unix.tight = user_data != NULL; 245 + addr.u.q_unix.abstract = true; 246 + 247 + fd = socket_listen(&addr, 1, &err); 248 + g_assert_cmpint(fd, >=, 0); 249 + g_assert(fd_is_socket(fd)); 250 + 251 + connfd = accept(fd, (struct sockaddr *)&un, &len); 252 + g_assert_cmpint(connfd, !=, -1); 253 + 254 + close(fd); 255 + 256 + return NULL; 257 + } 258 + 259 + static gpointer unix_client_thread_func(gpointer user_data) 260 + { 261 + SocketAddress addr; 262 + Error *err = NULL; 263 + int fd = -1; 264 + 265 + addr.type = SOCKET_ADDRESS_TYPE_UNIX; 266 + addr.u.q_unix.path = abstract_sock_name; 267 + addr.u.q_unix.tight = user_data != NULL; 268 + addr.u.q_unix.abstract = true; 269 + 270 + fd = socket_connect(&addr, &err); 271 + 272 + g_assert_cmpint(fd, >=, 0); 273 + 274 + close(fd); 275 + 276 + return NULL; 277 + } 278 + 279 + static void test_socket_unix_abstract_good(void) 280 + { 281 + GRand *r = g_rand_new(); 282 + 283 + abstract_sock_name = g_strdup_printf("unix-%d-%d", getpid(), 284 + g_rand_int_range(r, 100, 1000)); 285 + 286 + /* non tight socklen serv and cli */ 287 + GThread *serv = g_thread_new("abstract_unix_server", 288 + unix_server_thread_func, 289 + NULL); 290 + 291 + sleep(1); 292 + 293 + GThread *cli = g_thread_new("abstract_unix_client", 294 + unix_client_thread_func, 295 + NULL); 296 + 297 + g_thread_join(cli); 298 + g_thread_join(serv); 299 + 300 + /* tight socklen serv and cli */ 301 + serv = g_thread_new("abstract_unix_server", 302 + unix_server_thread_func, 303 + (gpointer)1); 304 + 305 + sleep(1); 306 + 307 + cli = g_thread_new("abstract_unix_client", 308 + unix_client_thread_func, 309 + (gpointer)1); 310 + 311 + g_thread_join(cli); 312 + g_thread_join(serv); 313 + 314 + g_free(abstract_sock_name); 315 + } 316 + #endif 230 317 231 318 int main(int argc, char **argv) 232 319 { ··· 264 351 g_test_add_func("/socket/fd-pass/num/nocli", 265 352 test_socket_fd_pass_num_nocli); 266 353 } 354 + 355 + #ifdef __linux__ 356 + g_test_add_func("/util/socket/unix-abstract/good", 357 + test_socket_unix_abstract_good); 358 + #endif 267 359 268 360 end: 269 361 return g_test_run();
+32 -7
util/qemu-sockets.c
··· 863 863 char *pathbuf = NULL; 864 864 const char *path; 865 865 size_t pathlen; 866 + size_t addrlen; 866 867 867 868 sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); 868 869 if (sock < 0) { ··· 879 880 } 880 881 881 882 pathlen = strlen(path); 882 - if (pathlen > sizeof(un.sun_path)) { 883 + if (pathlen > sizeof(un.sun_path) || 884 + (saddr->abstract && pathlen > (sizeof(un.sun_path) - 1))) { 883 885 error_setg(errp, "UNIX socket path '%s' is too long", path); 884 886 error_append_hint(errp, "Path must be less than %zu bytes\n", 887 + saddr->abstract ? sizeof(un.sun_path) - 1 : 885 888 sizeof(un.sun_path)); 886 889 goto err; 887 890 } ··· 903 906 close(fd); 904 907 } 905 908 906 - if (unlink(path) < 0 && errno != ENOENT) { 909 + if (!saddr->abstract && unlink(path) < 0 && errno != ENOENT) { 907 910 error_setg_errno(errp, errno, 908 911 "Failed to unlink socket %s", path); 909 912 goto err; ··· 911 914 912 915 memset(&un, 0, sizeof(un)); 913 916 un.sun_family = AF_UNIX; 914 - memcpy(un.sun_path, path, pathlen); 917 + addrlen = sizeof(un); 915 918 916 - if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { 919 + if (saddr->abstract) { 920 + un.sun_path[0] = '\0'; 921 + memcpy(&un.sun_path[1], path, pathlen); 922 + if (saddr->tight) { 923 + addrlen = offsetof(struct sockaddr_un, sun_path) + 1 + pathlen; 924 + } 925 + } else { 926 + memcpy(un.sun_path, path, pathlen); 927 + } 928 + 929 + if (bind(sock, (struct sockaddr *) &un, addrlen) < 0) { 917 930 error_setg_errno(errp, errno, "Failed to bind socket to %s", path); 918 931 goto err; 919 932 } ··· 936 949 struct sockaddr_un un; 937 950 int sock, rc; 938 951 size_t pathlen; 952 + size_t addrlen; 939 953 940 954 if (saddr->path == NULL) { 941 955 error_setg(errp, "unix connect: no path specified"); ··· 949 963 } 950 964 951 965 pathlen = strlen(saddr->path); 952 - if (pathlen > sizeof(un.sun_path)) { 966 + if (pathlen > sizeof(un.sun_path) || 967 + (saddr->abstract && pathlen > (sizeof(un.sun_path) - 1))) { 953 968 error_setg(errp, "UNIX socket path '%s' is too long", saddr->path); 954 969 error_append_hint(errp, "Path must be less than %zu bytes\n", 970 + saddr->abstract ? sizeof(un.sun_path) - 1 : 955 971 sizeof(un.sun_path)); 956 972 goto err; 957 973 } 958 974 959 975 memset(&un, 0, sizeof(un)); 960 976 un.sun_family = AF_UNIX; 961 - memcpy(un.sun_path, saddr->path, pathlen); 977 + addrlen = sizeof(un); 962 978 979 + if (saddr->abstract) { 980 + un.sun_path[0] = '\0'; 981 + memcpy(&un.sun_path[1], saddr->path, pathlen); 982 + if (saddr->tight) { 983 + addrlen = offsetof(struct sockaddr_un, sun_path) + 1 + pathlen; 984 + } 985 + } else { 986 + memcpy(un.sun_path, saddr->path, pathlen); 987 + } 963 988 /* connect to peer */ 964 989 do { 965 990 rc = 0; 966 - if (connect(sock, (struct sockaddr *) &un, sizeof(un)) < 0) { 991 + if (connect(sock, (struct sockaddr *) &un, addrlen) < 0) { 967 992 rc = -errno; 968 993 } 969 994 } while (rc == -EINTR);