Skip to content

Commit c3bfba9

Browse files
icklerodrigovivi
authored andcommitted
drm/i915: Check for integer truncation on scatterlist creation
There is an impedance mismatch between the scatterlist API using unsigned int and our memory/page accounting in unsigned long. That is we may try to create a scatterlist for a large object that overflows returning a small table into which we try to fit very many pages. As the object size is under the control of userspace, we have to be prudent and catch the conversion errors. To catch the implicit truncation we check before calling scattterlist creation Apis. we use overflows_type check and report E2BIG if the overflows may raise. When caller does not return errno, use WARN_ON to report a problem. This is already used in our create ioctls to indicate if the uABI request is simply too large for the backing store. Failing that type check, we have a second check at sg_alloc_table time to make sure the values we are passing into the scatterlist API are not truncated. v2: Move added i915_utils's macro into drm_util header (Jani N) v5: Fix macros to be enclosed in parentheses for complex values Fix too long line warning v8: Replace safe_conversion() with check_assign() (Kees) v14: Remove shadowing macros of scatterlist creation api and fix to explicitly overflow check where the scatterlist creation APIs are called. (Jani) v15: Add missing returning of error code when the WARN_ON() has been detected. (Jani) Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Cc: Brian Welty <brian.welty@intel.com> Cc: Matthew Auld <matthew.auld@intel.com> Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Co-developed-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com> Signed-off-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com> Reviewed-by: Nirmoy Das <nirmoy.das@intel.com> Reviewed-by: Mauro Carvalho Chehab <mchehab@kernel.org> Reviewed-by: Andrzej Hajda <andrzej.hajda@intel.com> Acked-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20221228192252.917299-3-gwan-gyeong.mun@intel.com
1 parent f47e630 commit c3bfba9

File tree

12 files changed

+60
-14
lines changed

12 files changed

+60
-14
lines changed

drivers/gpu/drm/i915/gem/i915_gem_internal.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,15 @@ static int i915_gem_object_get_pages_internal(struct drm_i915_gem_object *obj)
3535
struct drm_i915_private *i915 = to_i915(obj->base.dev);
3636
struct sg_table *st;
3737
struct scatterlist *sg;
38-
unsigned int npages;
38+
unsigned int npages; /* restricted by sg_alloc_table */
3939
int max_order = MAX_ORDER;
4040
unsigned int max_segment;
4141
gfp_t gfp;
4242

43+
if (overflows_type(obj->base.size >> PAGE_SHIFT, npages))
44+
return -E2BIG;
45+
46+
npages = obj->base.size >> PAGE_SHIFT;
4347
max_segment = i915_sg_segment_size(i915->drm.dev) >> PAGE_SHIFT;
4448
max_order = min(max_order, get_order(max_segment));
4549

@@ -55,7 +59,6 @@ static int i915_gem_object_get_pages_internal(struct drm_i915_gem_object *obj)
5559
if (!st)
5660
return -ENOMEM;
5761

58-
npages = obj->base.size / PAGE_SIZE;
5962
if (sg_alloc_table(st, npages, GFP_KERNEL)) {
6063
kfree(st);
6164
return -ENOMEM;

drivers/gpu/drm/i915/gem/i915_gem_object.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@ enum intel_region_id;
2626
* this and catch if we ever need to fix it. In the meantime, if you do
2727
* spot such a local variable, please consider fixing!
2828
*
29-
* Aside from our own locals (for which we have no excuse!):
30-
* - sg_table embeds unsigned int for nents
31-
*
3229
* We can check for invalidly typed locals with typecheck(), see for example
3330
* i915_gem_object_get_sg().
3431
*/

drivers/gpu/drm/i915/gem/i915_gem_phys.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj)
2828
void *dst;
2929
int i;
3030

31+
/* Contiguous chunk, with a single scatterlist element */
32+
if (overflows_type(obj->base.size, sg->length))
33+
return -E2BIG;
34+
3135
if (GEM_WARN_ON(i915_gem_object_needs_bit17_swizzle(obj)))
3236
return -EINVAL;
3337

drivers/gpu/drm/i915/gem/i915_gem_shmem.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,18 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
6060
struct address_space *mapping,
6161
unsigned int max_segment)
6262
{
63-
const unsigned long page_count = size / PAGE_SIZE;
63+
unsigned int page_count; /* restricted by sg_alloc_table */
6464
unsigned long i;
6565
struct scatterlist *sg;
6666
struct page *page;
6767
unsigned long last_pfn = 0; /* suppress gcc warning */
6868
gfp_t noreclaim;
6969
int ret;
7070

71+
if (overflows_type(size / PAGE_SIZE, page_count))
72+
return -E2BIG;
73+
74+
page_count = size / PAGE_SIZE;
7175
/*
7276
* If there's no chance of allocating enough pages for the whole
7377
* object, bail early.
@@ -193,7 +197,6 @@ static int shmem_get_pages(struct drm_i915_gem_object *obj)
193197
struct drm_i915_private *i915 = to_i915(obj->base.dev);
194198
struct intel_memory_region *mem = obj->mm.region;
195199
struct address_space *mapping = obj->base.filp->f_mapping;
196-
const unsigned long page_count = obj->base.size / PAGE_SIZE;
197200
unsigned int max_segment = i915_sg_segment_size(i915->drm.dev);
198201
struct sg_table *st;
199202
struct sgt_iter sgt_iter;
@@ -236,7 +239,7 @@ static int shmem_get_pages(struct drm_i915_gem_object *obj)
236239
} else {
237240
dev_warn(i915->drm.dev,
238241
"Failed to DMA remap %lu pages\n",
239-
page_count);
242+
obj->base.size >> PAGE_SHIFT);
240243
goto err_pages;
241244
}
242245
}

drivers/gpu/drm/i915/gem/i915_gem_ttm.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,10 @@ static int i915_ttm_get_pages(struct drm_i915_gem_object *obj)
832832
struct ttm_place requested, busy[I915_TTM_MAX_PLACEMENTS];
833833
struct ttm_placement placement;
834834

835+
/* restricted by sg_alloc_table */
836+
if (overflows_type(obj->base.size >> PAGE_SHIFT, unsigned int))
837+
return -E2BIG;
838+
835839
GEM_BUG_ON(obj->mm.n_placements > I915_TTM_MAX_PLACEMENTS);
836840

837841
/* Move to the requested placement. */

drivers/gpu/drm/i915/gem/i915_gem_userptr.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,12 +128,16 @@ static void i915_gem_object_userptr_drop_ref(struct drm_i915_gem_object *obj)
128128

129129
static int i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
130130
{
131-
const unsigned long num_pages = obj->base.size >> PAGE_SHIFT;
132131
unsigned int max_segment = i915_sg_segment_size(obj->base.dev->dev);
133132
struct sg_table *st;
134133
struct page **pvec;
134+
unsigned int num_pages; /* limited by sg_alloc_table_from_pages_segment */
135135
int ret;
136136

137+
if (overflows_type(obj->base.size >> PAGE_SHIFT, num_pages))
138+
return -E2BIG;
139+
140+
num_pages = obj->base.size >> PAGE_SHIFT;
137141
st = kmalloc(sizeof(*st), GFP_KERNEL);
138142
if (!st)
139143
return -ENOMEM;

drivers/gpu/drm/i915/gem/selftests/huge_gem_object.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,15 @@ static int huge_get_pages(struct drm_i915_gem_object *obj)
2929
{
3030
#define GFP (GFP_KERNEL | __GFP_NOWARN | __GFP_RETRY_MAYFAIL)
3131
const unsigned long nreal = obj->scratch / PAGE_SIZE;
32-
const unsigned long npages = obj->base.size / PAGE_SIZE;
32+
unsigned int npages; /* restricted by sg_alloc_table */
3333
struct scatterlist *sg, *src, *end;
3434
struct sg_table *pages;
3535
unsigned long n;
3636

37+
if (overflows_type(obj->base.size / PAGE_SIZE, npages))
38+
return -E2BIG;
39+
40+
npages = obj->base.size / PAGE_SIZE;
3741
pages = kmalloc(sizeof(*pages), GFP);
3842
if (!pages)
3943
return -ENOMEM;

drivers/gpu/drm/i915/gem/selftests/huge_pages.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ static int get_huge_pages(struct drm_i915_gem_object *obj)
8484
unsigned int sg_page_sizes;
8585
u64 rem;
8686

87+
/* restricted by sg_alloc_table */
88+
if (overflows_type(obj->base.size >> PAGE_SHIFT, unsigned int))
89+
return -E2BIG;
90+
8791
st = kmalloc(sizeof(*st), GFP);
8892
if (!st)
8993
return -ENOMEM;
@@ -212,6 +216,10 @@ static int fake_get_huge_pages(struct drm_i915_gem_object *obj)
212216
struct scatterlist *sg;
213217
u64 rem;
214218

219+
/* restricted by sg_alloc_table */
220+
if (overflows_type(obj->base.size >> PAGE_SHIFT, unsigned int))
221+
return -E2BIG;
222+
215223
st = kmalloc(sizeof(*st), GFP);
216224
if (!st)
217225
return -ENOMEM;

drivers/gpu/drm/i915/gvt/dmabuf.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@
4242

4343
#define GEN8_DECODE_PTE(pte) (pte & GENMASK_ULL(63, 12))
4444

45-
static int vgpu_gem_get_pages(
46-
struct drm_i915_gem_object *obj)
45+
static int vgpu_gem_get_pages(struct drm_i915_gem_object *obj)
4746
{
4847
struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
4948
struct intel_vgpu *vgpu;
@@ -52,8 +51,12 @@ static int vgpu_gem_get_pages(
5251
int i, j, ret;
5352
gen8_pte_t __iomem *gtt_entries;
5453
struct intel_vgpu_fb_info *fb_info;
55-
u32 page_num;
54+
unsigned int page_num; /* limited by sg_alloc_table */
5655

56+
if (overflows_type(obj->base.size >> PAGE_SHIFT, page_num))
57+
return -E2BIG;
58+
59+
page_num = obj->base.size >> PAGE_SHIFT;
5760
fb_info = (struct intel_vgpu_fb_info *)obj->gvt_info;
5861
if (drm_WARN_ON(&dev_priv->drm, !fb_info))
5962
return -ENODEV;
@@ -66,7 +69,6 @@ static int vgpu_gem_get_pages(
6669
if (unlikely(!st))
6770
return -ENOMEM;
6871

69-
page_num = obj->base.size >> PAGE_SHIFT;
7072
ret = sg_alloc_table(st, page_num, GFP_KERNEL);
7173
if (ret) {
7274
kfree(st);

drivers/gpu/drm/i915/i915_scatterlist.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
9696

9797
i915_refct_sgt_init(rsgt, node->size << PAGE_SHIFT);
9898
st = &rsgt->table;
99+
/* restricted by sg_alloc_table */
100+
if (WARN_ON(overflows_type(DIV_ROUND_UP_ULL(node->size, segment_pages),
101+
unsigned int)))
102+
return ERR_PTR(-E2BIG);
103+
99104
if (sg_alloc_table(st, DIV_ROUND_UP_ULL(node->size, segment_pages),
100105
GFP_KERNEL)) {
101106
i915_refct_sgt_put(rsgt);
@@ -177,6 +182,10 @@ struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
177182

178183
i915_refct_sgt_init(rsgt, size);
179184
st = &rsgt->table;
185+
/* restricted by sg_alloc_table */
186+
if (WARN_ON(overflows_type(PFN_UP(res->size), unsigned int)))
187+
return ERR_PTR(-E2BIG);
188+
180189
if (sg_alloc_table(st, PFN_UP(res->size), GFP_KERNEL)) {
181190
i915_refct_sgt_put(rsgt);
182191
return ERR_PTR(-ENOMEM);

0 commit comments

Comments
 (0)