Skip to content

Commit b9ffd80

Browse files
Brad Volkindanvet
authored andcommitted
drm/i915: Use batch length instead of object size in command parser
Previously we couldn't trust the user-supplied batch length because it came directly from userspace (i.e. untrusted code). It would have affected what commands software parsed without regard to what hardware would actually execute, leaving a potential hole. With the parser now copying the user supplied batch buffer and writing MI_NOP commands to any space after the copied region, we can safely use the batch length input. This should be a performance win as the actual batch length is frequently much smaller than the allocated object size. v2: Fix handling of non-zero batch_start_offset Issue: VIZ-4719 Signed-off-by: Brad Volkin <bradley.d.volkin@intel.com> Reviewed-By: Jon Bloomfield <jon.bloomfield@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
1 parent 78a4237 commit b9ffd80

File tree

3 files changed

+34
-16
lines changed

3 files changed

+34
-16
lines changed

drivers/gpu/drm/i915/i915_cmd_parser.c

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -850,52 +850,65 @@ static u32 *vmap_batch(struct drm_i915_gem_object *obj)
850850

851851
/* Returns a vmap'd pointer to dest_obj, which the caller must unmap */
852852
static u32 *copy_batch(struct drm_i915_gem_object *dest_obj,
853-
struct drm_i915_gem_object *src_obj)
853+
struct drm_i915_gem_object *src_obj,
854+
u32 batch_start_offset,
855+
u32 batch_len)
854856
{
855857
int ret = 0;
856858
int needs_clflush = 0;
857-
u32 *src_addr, *dest_addr = NULL;
859+
u32 *src_base, *dest_base = NULL;
860+
u32 *src_addr, *dest_addr;
861+
u32 offset = batch_start_offset / sizeof(*dest_addr);
862+
u32 end = batch_start_offset + batch_len;
863+
864+
if (end > dest_obj->base.size || end > src_obj->base.size)
865+
return ERR_PTR(-E2BIG);
858866

859867
ret = i915_gem_obj_prepare_shmem_read(src_obj, &needs_clflush);
860868
if (ret) {
861869
DRM_DEBUG_DRIVER("CMD: failed to prep read\n");
862870
return ERR_PTR(ret);
863871
}
864872

865-
src_addr = vmap_batch(src_obj);
866-
if (!src_addr) {
873+
src_base = vmap_batch(src_obj);
874+
if (!src_base) {
867875
DRM_DEBUG_DRIVER("CMD: Failed to vmap batch\n");
868876
ret = -ENOMEM;
869877
goto unpin_src;
870878
}
871879

880+
src_addr = src_base + offset;
881+
872882
if (needs_clflush)
873-
drm_clflush_virt_range((char *)src_addr, src_obj->base.size);
883+
drm_clflush_virt_range((char *)src_addr, batch_len);
874884

875885
ret = i915_gem_object_set_to_cpu_domain(dest_obj, true);
876886
if (ret) {
877887
DRM_DEBUG_DRIVER("CMD: Failed to set batch CPU domain\n");
878888
goto unmap_src;
879889
}
880890

881-
dest_addr = vmap_batch(dest_obj);
882-
if (!dest_addr) {
891+
dest_base = vmap_batch(dest_obj);
892+
if (!dest_base) {
883893
DRM_DEBUG_DRIVER("CMD: Failed to vmap shadow batch\n");
884894
ret = -ENOMEM;
885895
goto unmap_src;
886896
}
887897

888-
memcpy(dest_addr, src_addr, src_obj->base.size);
889-
if (dest_obj->base.size > src_obj->base.size)
890-
memset((u8 *)dest_addr + src_obj->base.size, 0,
891-
dest_obj->base.size - src_obj->base.size);
898+
dest_addr = dest_base + offset;
899+
900+
if (batch_start_offset != 0)
901+
memset((u8 *)dest_base, 0, batch_start_offset);
902+
903+
memcpy(dest_addr, src_addr, batch_len);
904+
memset((u8 *)dest_addr + batch_len, 0, dest_obj->base.size - end);
892905

893906
unmap_src:
894-
vunmap(src_addr);
907+
vunmap(src_base);
895908
unpin_src:
896909
i915_gem_object_unpin_pages(src_obj);
897910

898-
return ret ? ERR_PTR(ret) : dest_addr;
911+
return ret ? ERR_PTR(ret) : dest_base;
899912
}
900913

901914
/**
@@ -1016,6 +1029,7 @@ static bool check_cmd(const struct intel_engine_cs *ring,
10161029
* @batch_obj: the batch buffer in question
10171030
* @shadow_batch_obj: copy of the batch buffer in question
10181031
* @batch_start_offset: byte offset in the batch at which execution starts
1032+
* @batch_len: length of the commands in batch_obj
10191033
* @is_master: is the submitting process the drm master?
10201034
*
10211035
* Parses the specified batch buffer looking for privilege violations as
@@ -1028,14 +1042,16 @@ int i915_parse_cmds(struct intel_engine_cs *ring,
10281042
struct drm_i915_gem_object *batch_obj,
10291043
struct drm_i915_gem_object *shadow_batch_obj,
10301044
u32 batch_start_offset,
1045+
u32 batch_len,
10311046
bool is_master)
10321047
{
10331048
int ret = 0;
10341049
u32 *cmd, *batch_base, *batch_end;
10351050
struct drm_i915_cmd_descriptor default_desc = { 0 };
10361051
bool oacontrol_set = false; /* OACONTROL tracking. See check_cmd() */
10371052

1038-
batch_base = copy_batch(shadow_batch_obj, batch_obj);
1053+
batch_base = copy_batch(shadow_batch_obj, batch_obj,
1054+
batch_start_offset, batch_len);
10391055
if (IS_ERR(batch_base)) {
10401056
DRM_DEBUG_DRIVER("CMD: Failed to copy batch\n");
10411057
return PTR_ERR(batch_base);
@@ -1044,11 +1060,11 @@ int i915_parse_cmds(struct intel_engine_cs *ring,
10441060
cmd = batch_base + (batch_start_offset / sizeof(*cmd));
10451061

10461062
/*
1047-
* We use the source object's size because the shadow object is as
1063+
* We use the batch length as size because the shadow object is as
10481064
* large or larger and copy_batch() will write MI_NOPs to the extra
10491065
* space. Parsing should be faster in some cases this way.
10501066
*/
1051-
batch_end = cmd + (batch_obj->base.size / sizeof(*batch_end));
1067+
batch_end = cmd + (batch_len / sizeof(*batch_end));
10521068

10531069
while (cmd < batch_end) {
10541070
const struct drm_i915_cmd_descriptor *desc;

drivers/gpu/drm/i915/i915_drv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2965,6 +2965,7 @@ int i915_parse_cmds(struct intel_engine_cs *ring,
29652965
struct drm_i915_gem_object *batch_obj,
29662966
struct drm_i915_gem_object *shadow_batch_obj,
29672967
u32 batch_start_offset,
2968+
u32 batch_len,
29682969
bool is_master);
29692970

29702971
/* i915_suspend.c */

drivers/gpu/drm/i915/i915_gem_execbuffer.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,6 +1421,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
14211421
batch_obj,
14221422
shadow_batch_obj,
14231423
args->batch_start_offset,
1424+
args->batch_len,
14241425
file->is_master);
14251426
i915_gem_object_ggtt_unpin(shadow_batch_obj);
14261427

0 commit comments

Comments
 (0)