Re: [PATCH 1/7] kvmtool: 9p: fix path traversal vulnerabilities

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

thanks for the patches!

Please add a commit message (applies to the other patches as well). Also
we will need your Signed-off-by: for every patch that you want to see
committed.

On 18/10/16 17:02, G. Campana wrote:
> ---
>  virtio/9p.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 55 insertions(+)
> 
> diff --git a/virtio/9p.c b/virtio/9p.c
> index 49e7c5c..c3edc20 100644
> --- a/virtio/9p.c
> +++ b/virtio/9p.c
> @@ -222,6 +222,21 @@ static bool is_dir(struct p9_fid *fid)
>  	return S_ISDIR(st.st_mode);
>  }
>  
> +/* path is always absolute */
> +static bool path_is_illegal(const char *path)
> +{
> +	size_t len;
> +
> +	if (strstr(path, "/../") != NULL)
> +		return true;
> +
> +	len = strlen(path);
> +	if (len >= 3 && strcmp(path + len - 3, "/..") == 0)
> +		return true;
> +
> +	return false;
> +}
> +

I was wondering if this is good enough, as it only looks for this
specific sequence (for instance omitting "../")? I couldn't quickly find
a counterexample (Unicode? Quoting?), but it feels like there are
potentially dangerous cases we miss.
Also the naming maybe a bit misleading (as having a dot-dot-slash
sequence isn't per se illegal).

So I was wondering if we could make use of realpath(3) here? That would
also detect cases where we have symlinks pointing outside of the root
directory (does that matter here?). But I am not sure we want to pay the
overhead of normalizing the path each time, since this one will check
the path components against the filesystem.

Opinions?

Cheers,
Andre.

>  static void virtio_p9_open(struct p9_dev *p9dev,
>  			   struct p9_pdu *pdu, u32 *outlen)
>  {
> @@ -278,6 +293,11 @@ static void virtio_p9_create(struct p9_dev *p9dev,
>  	flags = virtio_p9_openflags(flags);
>  
>  	sprintf(full_path, "%s/%s", dfid->abs_path, name);
> +	if (path_is_illegal(full_path)) {
> +		errno = EACCES;
> +		goto err_out;
> +	}
> +
>  	fd = open(full_path, flags | O_CREAT, mode);
>  	if (fd < 0)
>  		goto err_out;
> @@ -319,6 +339,11 @@ static void virtio_p9_mkdir(struct p9_dev *p9dev,
>  	dfid = get_fid(p9dev, dfid_val);
>  
>  	sprintf(full_path, "%s/%s", dfid->abs_path, name);
> +	if (path_is_illegal(full_path)) {
> +		errno = EACCES;
> +		goto err_out;
> +	}
> +
>  	ret = mkdir(full_path, mode);
>  	if (ret < 0)
>  		goto err_out;
> @@ -776,6 +801,11 @@ static void virtio_p9_rename(struct p9_dev *p9dev,
>  	new_fid = get_fid(p9dev, new_fid_val);
>  
>  	sprintf(full_path, "%s/%s", new_fid->abs_path, new_name);
> +	if (path_is_illegal(full_path)) {
> +		errno = EACCES;
> +		goto err_out;
> +	}
> +
>  	ret = rename(fid->abs_path, full_path);
>  	if (ret < 0)
>  		goto err_out;
> @@ -860,6 +890,11 @@ static void virtio_p9_mknod(struct p9_dev *p9dev,
>  
>  	dfid = get_fid(p9dev, fid_val);
>  	sprintf(full_path, "%s/%s", dfid->abs_path, name);
> +	if (path_is_illegal(full_path)) {
> +		errno = EACCES;
> +		goto err_out;
> +	}
> +
>  	ret = mknod(full_path, mode, makedev(major, minor));
>  	if (ret < 0)
>  		goto err_out;
> @@ -927,6 +962,11 @@ static void virtio_p9_symlink(struct p9_dev *p9dev,
>  
>  	dfid = get_fid(p9dev, fid_val);
>  	sprintf(new_name, "%s/%s", dfid->abs_path, name);
> +	if (path_is_illegal(new_name)) {
> +		errno = EACCES;
> +		goto err_out;
> +	}
> +
>  	ret = symlink(old_path, new_name);
>  	if (ret < 0)
>  		goto err_out;
> @@ -962,6 +1002,11 @@ static void virtio_p9_link(struct p9_dev *p9dev,
>  	dfid = get_fid(p9dev, dfid_val);
>  	fid =  get_fid(p9dev, fid_val);
>  	sprintf(full_path, "%s/%s", dfid->abs_path, name);
> +	if (path_is_illegal(full_path)) {
> +		errno = EACCES;
> +		goto err_out;
> +	}
> +
>  	ret = link(fid->abs_path, full_path);
>  	if (ret < 0)
>  		goto err_out;
> @@ -1079,6 +1124,11 @@ static void virtio_p9_renameat(struct p9_dev *p9dev,
>  
>  	sprintf(old_full_path, "%s/%s", old_dfid->abs_path, old_name);
>  	sprintf(new_full_path, "%s/%s", new_dfid->abs_path, new_name);
> +	if (path_is_illegal(old_full_path) || path_is_illegal(new_full_path)) {
> +		errno = EACCES;
> +		goto err_out;
> +	}
> +
>  	ret = rename(old_full_path, new_full_path);
>  	if (ret < 0)
>  		goto err_out;
> @@ -1112,6 +1162,11 @@ static void virtio_p9_unlinkat(struct p9_dev *p9dev,
>  	fid = get_fid(p9dev, fid_val);
>  
>  	sprintf(full_path, "%s/%s", fid->abs_path, name);
> +	if (path_is_illegal(full_path)) {
> +		errno = EACCES;
> +		goto err_out;
> +	}
> +
>  	ret = remove(full_path);
>  	if (ret < 0)
>  		goto err_out;
> 
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux