[PATCH 08/16] drm/vmwgfx: implement mmap access managament

David Herrmann dh.herrmann at gmail.com
Fri Aug 16 10:01:49 PDT 2013


Hi

On Fri, Aug 16, 2013 at 5:33 PM, Thomas Hellstrom <thellstrom at vmware.com> wrote:
> On 08/16/2013 03:19 PM, David Herrmann wrote:
>>
>> Hi
>>
>> On Wed, Aug 14, 2013 at 7:35 PM, Thomas Hellstrom <thellstrom at vmware.com>
>> wrote:
>>>
>>> (CC'ing the proper people since I'm still on parental leave).
>>>
>>> On 08/13/2013 11:44 PM, David Herrmann wrote:
>>>
>>> Please see inline comments.
>>>
>>>
>>>> Hi
>>>>
>>>> On Tue, Aug 13, 2013 at 9:38 PM, David Herrmann <dh.herrmann at gmail.com>
>>>> wrote:
>>>>>
>>>>> Correctly allow and revoke buffer access on each open/close via the new
>>>>> VMA offset manager.
>>>
>>>
>>> I haven't yet had time to check the access policies of the new VMA offset
>>> manager, but anything that is identical or stricter than the current
>>> vmwgfx
>>> verify_access() would be fine. If it's stricter however, we need to
>>> double-check backwards user-space compatibility.
>>
>> My patches make vmw_dmabuf_alloc_ioctl() add the caller's open-file
>> (file*) to the list of allowed users of the new bo.
>> vmw_dmabuf_unref_ioctl() removes it again. I haven't seen any way to
>> pass a user-dmabuf to another user so there is currently at most one
>> user for a vmw_dmabuf. vmw_user_dmabuf_reference() looks like it is
>> intended exactly for this case so it would have to add the file* of
>> the caller to the list of allowed users. I will change that in v2.
>> This means every user who gets a handle for the buffer (like gem_open)
>> will be added to the allowed users. For TTM-object currently only a
>> single user is allowed.
>>
>> So I replace vmw_user_bo->base.tfile with a list (actually rbtree) of
>> allowed files. So more than one user can have access. This, however,
>> breaks the "shareable" attribute which I wasn't aware of. As far as I
>> can see, "shareable" is only used by vmwgfx_surface.c and can be set
>> by userspace to allow arbitrary processes to map this buffer (sounds
>> like a security issue similar to gem flink).
>> I actually think we can replace the "shareable" attribute with proper
>> access-management in the vma-manager. But first I'd need to know
>> whether "shareable = true" is actually used by vmwgfx user-space and
>> how buffers are shared? Do you simply pass the mmap offset between
>> processes? Or do you pass some handle?
>
>
> Buffer- and surface sharing is done by passing an opaque (not mmap) handle.
> A process intending to map the shared buffer must obtain the map offset
> through a
> vmw_user_dmabuf_reference() call, and that only works if the buffer is
> "shareable".

Ugh? That's not true. At least in upstream vmwgfx
vmw_user_dmabuf_reference() is unused. Maybe you have access to some
newer codebase? Anyway, I can easily make this function call
drm_vma_node_allow() and then newer vmwgfx additions will work just
fine. This means, every user who calls vmw_user_dmabuf_reference()
will then also be allowed to mmap that buffer. But users who do not
own a handle (that is, they didn't call vmw_user_dmabuf_reference() or
they dropped the reference via vmw_user_dmabuf_unref_ioctl()) will get
-EACCES if they try to mmap the buffer.

This is an extension to how it currently works, so I doubt that it
breaks any user-space. Is that fine for vmwgfx?

> mmap offsets are never passed between processes, but valid only if obtained
> directly
> from the kernel driver.

Good to hear. That means this patch doesn't break any existing userspace.

> This means that currently buffer mapping should have the same access
> restriction as the
> X server imposes on DRI clients; If a process is allowed to open the drm
> device, it also has
> map access to all "shareable" objects, which is a security hole in the sense
> that verify_access() should
> really check that the caller, if not the buffer owner, is also
> authenticated.

I actually don't care for DRI. This series tries to fix exactly that.
I don't want that. Users with DRM access shouldn't be able to map
arbitrary buffers. Instead, users should only be able to map buffers
that they own a handle for. Access management for handles is an
orthogonal problem that this series does not change. dma-buf does a
pretty good job there, anyway.

> The reason verify_access() is there is to make the TTM buffer object
> transparent to how it is exported
> to user space (GEM or TTM objects). Apparently the GEM TTM drivers have
> ignored this hook for some unknown
> reason.

I don't think that we need any extended access-management here. Why
would we ever need different access-modes for mmap than for handles?
This series reduces mmap() access-management to
handle-access-management. That is, the right to mmap() a buffer is now
bound to a buffer handle. If you don't own a handle, you cannot mmap
the buffer. But if you own a handle, you're always allowed to mmap the
buffer. I think this should be the policy to go for, or am I missing
something?

That's also why I think verify_access() is not needed at all. Drivers
shouldn't care for mmap() access, instead they should take care only
privileged users get handles (whatever they do to guarantee that,
gem-flink, dma-buf, ...).

Cheers
David

> Some ideas:
> 1) Rather than having a list of allowable files on each buffer object,
> perhaps we should have a user and a group and
> a set of permissions (for user, group and system) more like how files are
> handled?
>
> 2) Rather than imposing a security policy in the vma manager, could we
> perhaps have a set a utility functions that
> are called through verify_access(). Each driver could then have a wrapper to
> gather the needed information and
> hand it over to the VMA manager?
>
>
>>
>> If you really pass mmap offsets in user-space and rely on this, I
>> guess there is no way I can make vmwgfx use the vma-manager access
>> management. I will have to find a way to work around it or move the
>> "shareable" flag to ttm_bo.
>>
>>>>>    We also need to make vmw_user_dmabuf_reference()
>>>>> correctly increase the vma-allow counter, but it is unused so remove it
>>>>> instead.
>>>
>>> IIRC this function or a derivative thereof is used heavily in an upcoming
>>> version driver, so if possible, please add a corrected version rather
>>> than
>>> remove the (currently) unused code. This will trigger a merge error and
>>> the
>>> upcoming code can be more easily corrected.
>>
>> I will do so.
>>
>>>>> Cc: Thomas Hellstrom <thellstrom at vmware.com>
>>>>> Signed-off-by: David Herrmann <dh.herrmann at gmail.com>
>>>>
>>>> Just as a hint, this patch would allow to remove the
>>>> "->access_verify()" callback in vmwgfx. No other driver uses it,
>>>> afaik. I will try to add this in v2.
>>>>
>>>> Regards
>>>> David
>>>>
>>>>> ---
>>>>>    drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 29
>>>>> +++++++++++++++++------------
>>>>>    1 file changed, 17 insertions(+), 12 deletions(-)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
>>>>> b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
>>>>> index 0e67cf4..4d3f0ae 100644
>>>>> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
>>>>> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
>>>>> @@ -499,6 +499,12 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev,
>>>>> void *data,
>>>>>           if (unlikely(ret != 0))
>>>>>                   goto out_no_dmabuf;
>>>>>
>>>>> +       ret = drm_vma_node_allow(&dma_buf->base.vma_node,
>>>>> file_priv->filp);
>>>>> +       if (ret) {
>>>>> +               vmw_dmabuf_unreference(&dma_buf);
>>>>> +               goto out_no_dmabuf;
>>>>> +       }
>>>>> +
>>>>>           rep->handle = handle;
>>>>>           rep->map_handle =
>>>>> drm_vma_node_offset_addr(&dma_buf->base.vma_node);
>>>>>           rep->cur_gmr_id = handle;
>>>>> @@ -517,7 +523,18 @@ int vmw_dmabuf_unref_ioctl(struct drm_device *dev,
>>>>> void *data,
>>>>>    {
>>>>>           struct drm_vmw_unref_dmabuf_arg *arg =
>>>>>               (struct drm_vmw_unref_dmabuf_arg *)data;
>>>>> +       struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
>>>>> +       struct vmw_dma_buffer *dma_buf;
>>>>> +       int ret;
>>>>> +
>>>>> +       ret = vmw_user_dmabuf_lookup(tfile, arg->handle, &dma_buf);
>>>>> +       if (ret)
>>>>> +               return -EINVAL;
>>>>>
>>>>> +       drm_vma_node_revoke(&dma_buf->base.vma_node, file_priv->filp);
>>>>> +       vmw_dmabuf_unreference(&dma_buf);
>>>>> +
>>>>> +       /* FIXME: is this equivalent to
>>>>> vmw_dmabuf_unreference(dma_buf)?
>>>>> */
>>>
>>>
>>> No. A ttm ref object is rather similar to a generic GEM object, only that
>>> it's generic in the sense that it is not restricted to buffers, and can
>>> make
>>> any desired object visible to user-space. So translated the below code
>>> removes a reference that the arg->handle holds on the "gem" object,
>>> potentially destroying the whole object in which the "gem" object is
>>> embedded.
>>
>> So I actually need both lookups, vmw_user_dmabuf_lookup() and the
>> lookup in ttm_ref_object_base_unref()? Ugh.. but ok, I will leave the
>> function then as it is now but remove the comment.
>
>
> Yes. This seems odd, but IIRC the lookups are from different hash tables.
> The unref() call
> makes a lookup in a hash table private to the file.
>
>
>>
>>>>>           return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
>>>>>                                            arg->handle,
>>>>>                                            TTM_REF_USAGE);
>>>>> @@ -551,18 +568,6 @@ int vmw_user_dmabuf_lookup(struct ttm_object_file
>>>>> *tfile,
>>>>>           return 0;
>>>>>    }
>>>>>
>>>>> -int vmw_user_dmabuf_reference(struct ttm_object_file *tfile,
>>>>> -                             struct vmw_dma_buffer *dma_buf)
>>>>> -{
>>>>> -       struct vmw_user_dma_buffer *user_bo;
>>>>> -
>>>>> -       if (dma_buf->base.destroy != vmw_user_dmabuf_destroy)
>>>>> -               return -EINVAL;
>>>>> -
>>>>> -       user_bo = container_of(dma_buf, struct vmw_user_dma_buffer,
>>>>> dma);
>>>>> -       return ttm_ref_object_add(tfile, &user_bo->base, TTM_REF_USAGE,
>>>>> NULL);
>>>>> -}
>>>>> -
>>>>>    /*
>>>>>     * Stream management
>>>>>     */
>>>>> --
>>>>> 1.8.3.4
>>>>>
>>> Otherwise looks OK to me.
>>
>> Thanks!
>> David


More information about the dri-devel mailing list