[CRIU] [PATCH 4/5] sk-unix: Add trivial name resolver for sockets with relative names
Pavel Emelyanov
xemul at parallels.com
Tue Jul 28 05:11:48 PDT 2015
> @@ -148,6 +156,62 @@ static int write_unix_entry(struct unix_sk_desc *sk)
> return ret;
> }
>
> +static int resolve_rel_name(struct unix_sk_desc *sk, const struct fd_parms *p)
> +{
> + rel_name_desc_t *rel_name = sk->rel_name;
> + const char *dirs[] = { "cwd", "root" };
> + int mntns_root, i;
> + struct ns_id *ns;
> +
> + ns = lookup_ns_by_id(root_item->ids->mnt_ns_id, &mnt_ns_desc);
This should be task's mntns, not some arbitrary one :)
> + if (!ns)
> + return -ENOENT;
> +
> + mntns_root = mntns_get_root_fd(ns);
> + if (mntns_root < 0)
> + return -ENOENT;
> +
> + pr_debug("Resolving relative name %s for socket %x\n",
> + sk->name, sk->sd.ino);
> +
> + for (i = 0; i < ARRAY_SIZE(dirs); i++) {
> + char dir[PATH_MAX], path[PATH_MAX];
> + struct stat st;
> + int ret;
> +
> + snprintf(path, sizeof(path), "/proc/%d/%s", p->pid, dirs[i]);
> + ret = readlink(path, dir, sizeof(dir));
> + if (ret < 0 || (size_t)ret == sizeof(dir)) {
> + pr_err("Can't readlink for %s\n", dirs[i]);
> + return -1;
> + }
> + dir[ret] = 0;
> +
> + snprintf(path, sizeof(path), ".%s/%s", dir, sk->name);
> + if (fstatat(mntns_root, path, &st, 0)) {
> + if (errno == ENOENT)
> + continue;
> + goto err;
> + }
> +
> + if ((st.st_ino == rel_name->udiag_vfs_ino) &&
> + phys_stat_dev_match(st.st_dev, rel_name->udiag_vfs_dev, ns, path)) {
> + rel_name->dir = xstrdup(path);
> + if (!rel_name->dir)
> + return -ENOMEM;
> +
> + sk->mode = st.st_mode;
> + sk->uid = st.st_uid;
> + sk->gid = st.st_gid;
> + return 0;
> + }
> + }
> +
> +err:
> + pr_err("Can't resolve name for socket %#x\n", rel_name->udiag_vfs_ino);
> + return -ENOENT;
> +}
> +
> static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p)
> {
> struct unix_sk_desc *sk, *peer;
> @@ -714,6 +808,9 @@ static int post_open_unix_sk(struct file_desc *d, int fd)
> addr.sun_family = AF_UNIX;
> memcpy(&addr.sun_path, peer->name, peer->ue->name.len);
>
> + if (prep_unix_sk_cwd(ui))
You do this to make subsequent connect() resolve the name properly,
so the prep_ should be called on peer, not on ui, shouldn't it?
> + return -1;
> +
> if (connect(fd, (struct sockaddr *)&addr,
> sizeof(addr.sun_family) +
> peer->ue->name.len) < 0) {
> @@ -754,6 +851,9 @@ static int bind_unix_sk(int sk, struct unix_sk_info *ui)
> addr.sun_family = AF_UNIX;
> memcpy(&addr.sun_path, ui->name, ui->ue->name.len);
>
> + if (prep_unix_sk_cwd(ui))
> + return -1;
> +
> if (bind(sk, (struct sockaddr *)&addr,
> sizeof(addr.sun_family) + ui->ue->name.len)) {
> pr_perror("Can't bind socket");
> @@ -769,8 +869,11 @@ static int bind_unix_sk(int sk, struct unix_sk_info *ui)
> return -1;
> }
>
> - memcpy(fname, ui->name, ui->ue->name.len);
> - fname[ui->ue->name.len] = '\0';
> + if (!ui->name_dir) {
> + memcpy(fname, ui->name, ui->ue->name.len);
> + fname[ui->ue->name.len] = '\0';
> + } else
> + snprintf(fname, PATH_MAX, "%s/%s", ui->name_dir, ui->name);
>
> if (chown(fname, perms->uid, perms->gid) == -1) {
Won't chownat() be better?
> pr_perror("Unable to change file owner and group");
-- Pavel
More information about the CRIU
mailing list