[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