From d0308e5ecc1ce70b489354b0ddce8045800b3215 Mon Sep 17 00:00:00 2001 From: Andrey Zhadchenko Date: Mon, 11 Jan 2021 18:17:40 +0300 Subject: [PATCH] sk-unix: make criu respect existing files while restoring ghost unix socket fd If there are any file in place of ghost unix socket, criu will delete it at restore while trying to recreate ghost one. Reviewed-by: Alexander Mikhalitsyn Reviewed-by: Pavel Tikhomirov Signed-off-by: Andrey Zhadchenko --- criu/sk-unix.c | 84 ++++++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/criu/sk-unix.c b/criu/sk-unix.c index a5b931b2a..09ae1f542 100644 --- a/criu/sk-unix.c +++ b/criu/sk-unix.c @@ -1470,56 +1470,49 @@ static int bind_on_deleted(int sk, struct unix_sk_info *ui) addr.sun_family = AF_UNIX; memcpy(&addr.sun_path, ui->name, ui->ue->name.len); + ret = access(ui->name, F_OK); + if (!ret) { + snprintf(path_parked, sizeof(path_parked), UNIX_GHOST_FMT, ui->name); + /* + * In case if there exist any file with same name + * just move it aside for a while, we will move it back + * once ghost socket is processed. + */ + if (unlinkat(AT_FDCWD, path_parked, 0) == 0) + pr_debug("ghost: Unlinked stale socket id %#x ino %d name %s\n", + ui->ue->id, ui->ue->ino, path_parked); + if (rename(ui->name, path_parked)) { + ret = -errno; + pr_perror("ghost: Can't rename id %#x ino %u addr %s -> %s", + ui->ue->id, ui->ue->ino, ui->name, path_parked); + return ret; + } + pr_debug("ghost: id %#x ino %d renamed %s -> %s\n", + ui->ue->id, ui->ue->ino, ui->name, path_parked); + renamed = true; + } + ret = bind(sk, (struct sockaddr *)&addr, sizeof(addr.sun_family) + ui->ue->name.len); if (ret < 0) { - /* - * In case if there some real living socket - * with same name just move it aside for a - * while, we will move it back once ghost - * socket is processed. - */ - if (errno == EADDRINUSE) { - snprintf(path_parked, sizeof(path_parked), UNIX_GHOST_FMT, ui->name); - /* - * Say previous restore get killed in a middle due to - * any reason, be ready the file might already exist, - * clean it up. - */ - if (unlinkat(AT_FDCWD, path_parked, 0) == 0) - pr_debug("ghost: Unlinked stale socket id %#x ino %u name %s\n", - ui->ue->id, ui->ue->ino, path_parked); - if (rename(ui->name, path_parked)) { - ret = -errno; - pr_perror("ghost: Can't rename id %#x ino %u addr %s -> %s", - ui->ue->id, ui->ue->ino, ui->name, path_parked); - return ret; - } - pr_debug("ghost: id %#x ino %u renamed %s -> %s\n", - ui->ue->id, ui->ue->ino, ui->name, path_parked); - renamed = true; - ret = bind(sk, (struct sockaddr *)&addr, - sizeof(addr.sun_family) + ui->ue->name.len); - } - if (ret < 0) { - ret = -errno; - pr_perror("ghost: Can't bind on socket id %#x ino %u addr %s", - ui->ue->id, ui->ue->ino, ui->name); - return ret; - } + ret = -errno; + pr_perror("ghost: Can't bind on socket id %#x ino %d addr %s", + ui->ue->id, ui->ue->ino, ui->name); + goto out_rename; } ret = restore_file_perms(ui); if (ret < 0) - return ret; + goto out; ret = keep_deleted(ui); if (ret < 0) { pr_err("ghost: Can't save socket %#x ino %u addr %s into fdstore\n", ui->ue->id, ui->ue->ino, ui->name); - return -EIO; + ret = -EIO; } +out: /* * Once everything is ready, just remove the socket from the * filesystem and rename back the original one if it were here. @@ -1529,19 +1522,18 @@ static int bind_on_deleted(int sk, struct unix_sk_info *ui) ret = -errno; pr_perror("ghost: Can't unlink socket %#x ino %u addr %s", ui->ue->id, ui->ue->ino, ui->name); - return ret; } +out_rename: if (renamed) { if (rename(path_parked, ui->name)) { ret = -errno; pr_perror("ghost: Can't rename id %#x ino %u addr %s -> %s", ui->ue->id, ui->ue->ino, path_parked, ui->name); - return ret; + } else { + pr_debug("ghost: id %#x ino %d renamed %s -> %s\n", + ui->ue->id, ui->ue->ino, path_parked, ui->name); } - - pr_debug("ghost: id %#x ino %u renamed %s -> %s\n", - ui->ue->id, ui->ue->ino, path_parked, ui->name); } /* @@ -1988,6 +1980,7 @@ static struct file_desc_ops unix_desc_ops = { static int unlink_sk(struct unix_sk_info *ui) { int ret = 0, cwd_fd = -1, root_fd = -1, ns_fd = -1; + struct stat statbuf; if (!ui->name || ui->name[0] == '\0' || (ui->ue->uflags & USK_EXTERN)) return 0; @@ -1995,6 +1988,15 @@ static int unlink_sk(struct unix_sk_info *ui) if (prep_unix_sk_cwd(ui, &cwd_fd, &root_fd, NULL)) return -1; + ret = stat(ui->name, &statbuf); + if (!ret) { + /* Do not cleanup non-socket files */ + if (!S_ISSOCK(statbuf.st_mode)) { + ret = 0; + goto out; + } + } + ret = unlinkat(AT_FDCWD, ui->name, 0) ? -1 : 0; if (ret < 0 && errno != ENOENT) { pr_warn("Can't unlink socket %u peer %u (name %s dir %s)\n",