From e202333dbb3ee8d78627eae61dede90d06e01696 Mon Sep 17 00:00:00 2001 From: Joseph Gooch Date: Fri, 11 Sep 2020 15:01:50 +0000 Subject: [PATCH] Refactor UNIX socket binding into helper function for Attach and Notify Signed-off-by: Joseph Gooch --- src/conn_sock.c | 143 +++++++++++++++++++----------------------------- 1 file changed, 55 insertions(+), 88 deletions(-) diff --git a/src/conn_sock.c b/src/conn_sock.c index 68b7b36d..717f235e 100644 --- a/src/conn_sock.c +++ b/src/conn_sock.c @@ -22,7 +22,8 @@ static void remote_sock_shutdown(struct remote_sock_s *sock, int how); static void schedule_local_sock_write(struct local_sock_s *local_sock); static void sock_try_write_to_local_sock(struct remote_sock_s *sock); static gboolean local_sock_write_cb(G_GNUC_UNUSED int fd, G_GNUC_UNUSED GIOCondition condition, G_GNUC_UNUSED gpointer user_data); - +static char *bind_unix_socket(char *socket_relative_name, int sock_type, mode_t perms, struct remote_sock_s *remote_sock, + gboolean do_chdir); /* Since our socket handling is abstract now, handling is based on sock_type, so we can pass around a structure that contains everything we need to handle I/O. Callbacks used to handle IO, for example, and whether this @@ -109,71 +110,18 @@ char *setup_console_socket(void) char *setup_attach_socket(void) { - struct sockaddr_un attach_addr = {0}; - attach_addr.sun_family = AF_UNIX; - - /* - * Create a symlink so we don't exceed unix domain socket - * path length limit. - */ - char *attach_symlink_dir_path = g_build_filename(opt_socket_path, opt_cuuid, NULL); - if (unlink(attach_symlink_dir_path) == -1 && errno != ENOENT) - pexit("Failed to remove existing symlink for attach socket directory"); - - /* - * This is to address a corner case where the symlink path length can end up being - * the same as the socket. When it happens, the symlink prevents the socket from being - * be created. This could still be a problem with other containers, but it is safe - * to assume the CUUIDs don't change length in the same directory. As a workaround, - * in such case, make the symlink one char shorter. - */ - if (strlen(attach_symlink_dir_path) == (sizeof(attach_addr.sun_path) - 1)) - attach_symlink_dir_path[sizeof(attach_addr.sun_path) - 2] = '\0'; - - if (symlink(opt_bundle_path, attach_symlink_dir_path) == -1) - pexit("Failed to create symlink for attach socket"); - - _cleanup_free_ char *attach_sock_path = g_build_filename(opt_socket_path, opt_cuuid, "attach", NULL); - ninfof("attach sock path: %s", attach_sock_path); - - strncpy(attach_addr.sun_path, attach_sock_path, sizeof(attach_addr.sun_path) - 1); - ninfof("addr{sun_family=AF_UNIX, sun_path=%s}", attach_addr.sun_path); - - /* - * We make the socket non-blocking to avoid a race where client aborts connection - * before the server gets a chance to call accept. In that scenario, the server - * accept blocks till a new client connection comes in. - */ - attach_socket_fd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); - if (attach_socket_fd == -1) - pexit("Failed to create attach socket"); - - remote_attach_sock.fd = attach_socket_fd; - - if (fchmod(attach_socket_fd, 0700)) - pexit("Failed to change attach socket permissions"); + char *symlink_dir_path = bind_unix_socket("attach", SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0700, &remote_attach_sock, 0); - if (unlink(attach_addr.sun_path) == -1 && errno != ENOENT) - pexitf("Failed to remove existing attach socket: %s", attach_addr.sun_path); + if (listen(remote_attach_sock.fd, 10) == -1) + pexitf("Failed to listen on attach socket: %s/%s", symlink_dir_path, "attach"); - if (bind(attach_socket_fd, (struct sockaddr *)&attach_addr, sizeof(struct sockaddr_un)) == -1) - pexitf("Failed to bind attach socket: %s", attach_sock_path); + g_unix_fd_add(remote_attach_sock.fd, G_IO_IN, attach_cb, &remote_attach_sock); - if (listen(attach_socket_fd, 10) == -1) - pexitf("Failed to listen on attach socket: %s", attach_sock_path); - - g_unix_fd_add(attach_socket_fd, G_IO_IN, attach_cb, &remote_attach_sock); - - return attach_symlink_dir_path; + return symlink_dir_path; } void setup_notify_socket(char *socket_path) { - int notify_socket_fd = -1; - struct sockaddr_un notify_addr = {0}; - notify_addr.sun_family = AF_UNIX; - _cleanup_free_ char *cwd = NULL; - /* Connect to Host socket */ if (local_notify_host_fd < 0) { local_notify_host_fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); @@ -184,13 +132,23 @@ void setup_notify_socket(char *socket_path) strncpy(local_notify_host_addr.sun_path, socket_path, sizeof(local_notify_host_addr.sun_path) - 1); } + _cleanup_free_ char *symlink_dir_path = + bind_unix_socket("notify/notify.sock", SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0777, &remote_notify_sock, 1); + g_unix_fd_add(remote_notify_sock.fd, G_IO_IN | G_IO_HUP | G_IO_ERR, remote_sock_cb, &remote_notify_sock); +} + +static char *bind_unix_socket(char *socket_relative_name, int sock_type, mode_t perms, struct remote_sock_s *remote_sock, gboolean do_chdir) +{ + int socket_fd = -1; + struct sockaddr_un socket_addr = {0}; + socket_addr.sun_family = AF_UNIX; + _cleanup_free_ char *cwd = NULL; + /* * Create a symlink so we don't exceed unix domain socket * path length limit. */ - _cleanup_free_ char *notify_symlink_dir_path = g_build_filename(opt_socket_path, opt_cuuid, NULL); - if (unlink(notify_symlink_dir_path) == -1 && errno != ENOENT) - pexit("Failed to remove existing symlink for notify socket directory"); + char *base_path = g_build_filename(opt_socket_path, opt_cuuid, NULL); /* * This is to address a corner case where the symlink path length can end up being @@ -198,53 +156,62 @@ void setup_notify_socket(char *socket_path) * be created. This could still be a problem with other containers, but it is safe * to assume the CUUIDs don't change length in the same directory. As a workaround, * in such case, make the symlink one char shorter. + * + * If we're using do_chdir, this is unnecessary. + */ + if (!do_chdir && strlen(base_path) == (sizeof(socket_addr.sun_path) - 1)) + base_path[sizeof(socket_addr.sun_path) - 2] = '\0'; + + /* + * Create a symlink so we don't exceed unix domain socket + * path length limit. We use the base path passed in from our parent. */ - if (strlen(notify_symlink_dir_path) == (sizeof(notify_addr.sun_path) - 1)) - notify_symlink_dir_path[sizeof(notify_addr.sun_path) - 2] = '\0'; + if (unlink(base_path) == -1 && errno != ENOENT) + pexitf("Failed to remove existing symlink for socket directory %s", base_path); - if (symlink(opt_bundle_path, notify_symlink_dir_path) == -1) + if (symlink(opt_bundle_path, base_path) == -1) pexit("Failed to create symlink for notify socket"); - _cleanup_free_ char *notify_sock_fullpath = g_build_filename(opt_socket_path, opt_cuuid, "notify/notify.sock", NULL); - _cleanup_free_ char *notify_sock_path = g_build_filename(opt_cuuid, "notify/notify.sock", NULL); - ninfof("notify sock path: %s", notify_sock_fullpath); + _cleanup_free_ char *sock_fullpath = g_build_filename(base_path, socket_relative_name, NULL); + _cleanup_free_ char *sock_relpath = g_build_filename(opt_cuuid, socket_relative_name, NULL); + ninfof("socket path: %s", sock_fullpath); - strncpy(notify_addr.sun_path, notify_sock_path, sizeof(notify_addr.sun_path) - 1); - ninfof("addr{sun_family=AF_UNIX, sun_path=%s}", notify_addr.sun_path); + strncpy(socket_addr.sun_path, do_chdir ? sock_relpath : sock_fullpath, sizeof(socket_addr.sun_path) - 1); + ninfof("addr{sun_family=AF_UNIX, sun_path=%s}", socket_addr.sun_path); /* * We make the socket non-blocking to avoid a race where client aborts connection * before the server gets a chance to call accept. In that scenario, the server * accept blocks till a new client connection comes in. */ - if ((cwd = getcwd(NULL, 0)) == NULL) - pexit("Failed to get CWD for notify socket"); + if (do_chdir && (cwd = getcwd(NULL, 0)) == NULL) + pexitf("Failed to get CWD for socket %s", sock_fullpath); - notify_socket_fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); - if (notify_socket_fd == -1) - pexit("Failed to create notify socket"); + socket_fd = socket(AF_UNIX, sock_type, 0); + if (socket_fd == -1) + pexitf("Failed to create socket %s", sock_fullpath); - remote_notify_sock.fd = notify_socket_fd; + if (fchmod(socket_fd, perms)) + pexitf("Failed to change socket permissions %s", sock_fullpath); - if (fchmod(notify_socket_fd, 0777)) - pexit("Failed to change notify socket permissions"); - - if (chdir(opt_socket_path) == -1) + if (do_chdir && chdir(opt_socket_path) == -1) pexitf("Could not chdir to %s", opt_socket_path); - if (unlink(notify_sock_fullpath) == -1 && errno != ENOENT) - pexitf("Failed to remove existing notify socket: %s", notify_sock_fullpath); + if (unlink(sock_fullpath) == -1 && errno != ENOENT) + pexitf("Failed to remove existing socket: %s", sock_fullpath); - if (bind(notify_socket_fd, (struct sockaddr *)¬ify_addr, sizeof(struct sockaddr_un)) == -1) - pexitf("Failed to bind notify socket: %s", notify_sock_fullpath); + if (bind(socket_fd, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_un)) == -1) + pexitf("Failed to bind socket: %s", sock_fullpath); - if (chmod(notify_sock_fullpath, 0777)) - pexit("Failed to change notify socket permissions"); + if (chmod(sock_fullpath, perms)) + pexitf("Failed to change socket permissions %s", sock_fullpath); - if (chdir(cwd) == -1) + if (do_chdir && chdir(cwd) == -1) pexitf("Could not chdir to %s", cwd); - g_unix_fd_add(notify_socket_fd, G_IO_IN | G_IO_HUP | G_IO_ERR, remote_sock_cb, &remote_notify_sock); + remote_sock->fd = socket_fd; + + return base_path; }