Skip to content

Commit 41a97c4

Browse files
committed
drm/xe/pxp/uapi: Add API to mark a BO as using PXP
The driver needs to know if a BO is encrypted with PXP to enable the display decryption at flip time. Furthermore, we want to keep track of the status of the encryption and reject any operation that involves a BO that is encrypted using an old key. There are two points in time where such checks can kick in: 1 - at VM bind time, all operations except for unmapping will be rejected if the key used to encrypt the BO is no longer valid. This check is opt-in via a new VM_BIND flag, to avoid a scenario where a malicious app purposely shares an invalid BO with a non-PXP aware app (such as a compositor). If the VM_BIND was failed, the compositor would be unable to display anything at all. Allowing the bind to go through means that output still works, it just displays garbage data within the bounds of the illegal BO. 2 - at job submission time, if the queue is marked as using PXP, all objects bound to the VM will be checked and the submission will be rejected if any of them was encrypted with a key that is no longer valid. Note that there is no risk of leaking the encrypted data if a user does not opt-in to those checks; the only consequence is that the user will not realize that the encryption key is changed and that the data is no longer valid. v2: Better commnnts and descriptions (John), rebase v3: Properly return the result of key_assign up the stack, do not use xe_bo in display headers (Jani) v4: improve key_instance variable documentation (John) Signed-off-by: Daniele Ceraolo Spurio <[email protected]> Cc: Matthew Brost <[email protected]> Cc: Thomas Hellström <[email protected]> Cc: John Harrison <[email protected]> Cc: Jani Nikula <[email protected]> Reviewed-by: John Harrison <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent bd98ac2 commit 41a97c4

File tree

12 files changed

+296
-7
lines changed

12 files changed

+296
-7
lines changed

drivers/gpu/drm/xe/compat-i915-headers/pxp/intel_pxp.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,24 @@
99
#include <linux/errno.h>
1010
#include <linux/types.h>
1111

12+
#include "xe_pxp.h"
13+
1214
struct drm_gem_object;
1315
struct xe_pxp;
1416

1517
static inline int intel_pxp_key_check(struct xe_pxp *pxp,
1618
struct drm_gem_object *obj,
1719
bool assign)
1820
{
19-
return -ENODEV;
21+
/*
22+
* The assign variable is used in i915 to assign the key to the BO at
23+
* first submission time. In Xe the key is instead assigned at BO
24+
* creation time, so the assign variable must always be false.
25+
*/
26+
if (assign)
27+
return -EINVAL;
28+
29+
return xe_pxp_obj_key_check(pxp, obj);
2030
}
2131

2232
#endif

drivers/gpu/drm/xe/display/intel_bo.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ bool intel_bo_is_shmem(struct drm_gem_object *obj)
2525

2626
bool intel_bo_is_protected(struct drm_gem_object *obj)
2727
{
28-
return false;
28+
return xe_bo_is_protected(gem_to_xe_bo(obj));
2929
}
3030

3131
void intel_bo_flush_if_display(struct drm_gem_object *obj)

drivers/gpu/drm/xe/xe_bo.c

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "xe_bo.h"
77

88
#include <linux/dma-buf.h>
9+
#include <linux/nospec.h>
910

1011
#include <drm/drm_drv.h>
1112
#include <drm/drm_gem_ttm_helper.h>
@@ -26,6 +27,7 @@
2627
#include "xe_migrate.h"
2728
#include "xe_pm.h"
2829
#include "xe_preempt_fence.h"
30+
#include "xe_pxp.h"
2931
#include "xe_res_cursor.h"
3032
#include "xe_trace_bo.h"
3133
#include "xe_ttm_stolen_mgr.h"
@@ -2155,6 +2157,93 @@ void xe_bo_vunmap(struct xe_bo *bo)
21552157
__xe_bo_vunmap(bo);
21562158
}
21572159

2160+
static int gem_create_set_pxp_type(struct xe_device *xe, struct xe_bo *bo, u64 value)
2161+
{
2162+
if (value == DRM_XE_PXP_TYPE_NONE)
2163+
return 0;
2164+
2165+
/* we only support DRM_XE_PXP_TYPE_HWDRM for now */
2166+
if (XE_IOCTL_DBG(xe, value != DRM_XE_PXP_TYPE_HWDRM))
2167+
return -EINVAL;
2168+
2169+
return xe_pxp_key_assign(xe->pxp, bo);
2170+
}
2171+
2172+
typedef int (*xe_gem_create_set_property_fn)(struct xe_device *xe,
2173+
struct xe_bo *bo,
2174+
u64 value);
2175+
2176+
static const xe_gem_create_set_property_fn gem_create_set_property_funcs[] = {
2177+
[DRM_XE_GEM_CREATE_EXTENSION_SET_PROPERTY] = gem_create_set_pxp_type,
2178+
};
2179+
2180+
static int gem_create_user_ext_set_property(struct xe_device *xe,
2181+
struct xe_bo *bo,
2182+
u64 extension)
2183+
{
2184+
u64 __user *address = u64_to_user_ptr(extension);
2185+
struct drm_xe_ext_set_property ext;
2186+
int err;
2187+
u32 idx;
2188+
2189+
err = __copy_from_user(&ext, address, sizeof(ext));
2190+
if (XE_IOCTL_DBG(xe, err))
2191+
return -EFAULT;
2192+
2193+
if (XE_IOCTL_DBG(xe, ext.property >=
2194+
ARRAY_SIZE(gem_create_set_property_funcs)) ||
2195+
XE_IOCTL_DBG(xe, ext.pad) ||
2196+
XE_IOCTL_DBG(xe, ext.property != DRM_XE_GEM_CREATE_EXTENSION_SET_PROPERTY))
2197+
return -EINVAL;
2198+
2199+
idx = array_index_nospec(ext.property, ARRAY_SIZE(gem_create_set_property_funcs));
2200+
if (!gem_create_set_property_funcs[idx])
2201+
return -EINVAL;
2202+
2203+
return gem_create_set_property_funcs[idx](xe, bo, ext.value);
2204+
}
2205+
2206+
typedef int (*xe_gem_create_user_extension_fn)(struct xe_device *xe,
2207+
struct xe_bo *bo,
2208+
u64 extension);
2209+
2210+
static const xe_gem_create_user_extension_fn gem_create_user_extension_funcs[] = {
2211+
[DRM_XE_GEM_CREATE_EXTENSION_SET_PROPERTY] = gem_create_user_ext_set_property,
2212+
};
2213+
2214+
#define MAX_USER_EXTENSIONS 16
2215+
static int gem_create_user_extensions(struct xe_device *xe, struct xe_bo *bo,
2216+
u64 extensions, int ext_number)
2217+
{
2218+
u64 __user *address = u64_to_user_ptr(extensions);
2219+
struct drm_xe_user_extension ext;
2220+
int err;
2221+
u32 idx;
2222+
2223+
if (XE_IOCTL_DBG(xe, ext_number >= MAX_USER_EXTENSIONS))
2224+
return -E2BIG;
2225+
2226+
err = __copy_from_user(&ext, address, sizeof(ext));
2227+
if (XE_IOCTL_DBG(xe, err))
2228+
return -EFAULT;
2229+
2230+
if (XE_IOCTL_DBG(xe, ext.pad) ||
2231+
XE_IOCTL_DBG(xe, ext.name >= ARRAY_SIZE(gem_create_user_extension_funcs)))
2232+
return -EINVAL;
2233+
2234+
idx = array_index_nospec(ext.name,
2235+
ARRAY_SIZE(gem_create_user_extension_funcs));
2236+
err = gem_create_user_extension_funcs[idx](xe, bo, extensions);
2237+
if (XE_IOCTL_DBG(xe, err))
2238+
return err;
2239+
2240+
if (ext.next_extension)
2241+
return gem_create_user_extensions(xe, bo, ext.next_extension,
2242+
++ext_number);
2243+
2244+
return 0;
2245+
}
2246+
21582247
int xe_gem_create_ioctl(struct drm_device *dev, void *data,
21592248
struct drm_file *file)
21602249
{
@@ -2167,8 +2256,7 @@ int xe_gem_create_ioctl(struct drm_device *dev, void *data,
21672256
u32 handle;
21682257
int err;
21692258

2170-
if (XE_IOCTL_DBG(xe, args->extensions) ||
2171-
XE_IOCTL_DBG(xe, args->pad[0] || args->pad[1] || args->pad[2]) ||
2259+
if (XE_IOCTL_DBG(xe, args->pad[0] || args->pad[1] || args->pad[2]) ||
21722260
XE_IOCTL_DBG(xe, args->reserved[0] || args->reserved[1]))
21732261
return -EINVAL;
21742262

@@ -2250,6 +2338,12 @@ int xe_gem_create_ioctl(struct drm_device *dev, void *data,
22502338
goto out_vm;
22512339
}
22522340

2341+
if (args->extensions) {
2342+
err = gem_create_user_extensions(xe, bo, args->extensions, 0);
2343+
if (err)
2344+
goto out_bulk;
2345+
}
2346+
22532347
err = drm_gem_handle_create(file, &bo->ttm.base, &handle);
22542348
if (err)
22552349
goto out_bulk;

drivers/gpu/drm/xe/xe_bo.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,11 @@ static inline bool xe_bo_is_pinned(struct xe_bo *bo)
186186
return bo->ttm.pin_count;
187187
}
188188

189+
static inline bool xe_bo_is_protected(const struct xe_bo *bo)
190+
{
191+
return bo->pxp_key_instance;
192+
}
193+
189194
static inline void xe_bo_unpin_map_no_vm(struct xe_bo *bo)
190195
{
191196
if (likely(bo)) {

drivers/gpu/drm/xe/xe_bo_types.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ struct xe_bo {
5757
*/
5858
struct list_head client_link;
5959
#endif
60+
/**
61+
* @pxp_key_instance: PXP key instance this BO was created against. A
62+
* 0 in this variable indicates that the BO does not use PXP encryption.
63+
*/
64+
u32 pxp_key_instance;
65+
6066
/** @freed: List node for delayed put. */
6167
struct llist_node freed;
6268
/** @update_index: Update index if PT BO */

drivers/gpu/drm/xe/xe_exec.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,12 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
262262
goto err_exec;
263263
}
264264

265+
if (xe_exec_queue_uses_pxp(q)) {
266+
err = xe_vm_validate_protected(q->vm);
267+
if (err)
268+
goto err_exec;
269+
}
270+
265271
job = xe_sched_job_create(q, xe_exec_queue_is_parallel(q) ?
266272
addresses : &args->address);
267273
if (IS_ERR(job)) {

drivers/gpu/drm/xe/xe_pxp.c

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include <drm/drm_managed.h>
99
#include <uapi/drm/xe_drm.h>
1010

11+
#include "xe_bo.h"
12+
#include "xe_bo_types.h"
1113
#include "xe_device_types.h"
1214
#include "xe_exec_queue.h"
1315
#include "xe_force_wake.h"
@@ -185,6 +187,9 @@ static void pxp_terminate(struct xe_pxp *pxp)
185187

186188
pxp_invalidate_queues(pxp);
187189

190+
if (pxp->status == XE_PXP_ACTIVE)
191+
pxp->key_instance++;
192+
188193
/*
189194
* If we have a termination already in progress, we need to wait for
190195
* it to complete before queueing another one. Once the first
@@ -385,6 +390,8 @@ int xe_pxp_init(struct xe_device *xe)
385390
pxp->xe = xe;
386391
pxp->gt = gt;
387392

393+
pxp->key_instance = 1;
394+
388395
/*
389396
* we'll use the completions to check if there is an action pending,
390397
* so we start them as completed and we reinit it when an action is
@@ -689,3 +696,86 @@ static void pxp_invalidate_queues(struct xe_pxp *pxp)
689696

690697
spin_unlock_irq(&pxp->queues.lock);
691698
}
699+
700+
/**
701+
* xe_pxp_key_assign - mark a BO as using the current PXP key iteration
702+
* @pxp: the xe->pxp pointer (it will be NULL if PXP is disabled)
703+
* @bo: the BO to mark
704+
*
705+
* Returns: -ENODEV if PXP is disabled, 0 otherwise.
706+
*/
707+
int xe_pxp_key_assign(struct xe_pxp *pxp, struct xe_bo *bo)
708+
{
709+
if (!xe_pxp_is_enabled(pxp))
710+
return -ENODEV;
711+
712+
xe_assert(pxp->xe, !bo->pxp_key_instance);
713+
714+
/*
715+
* Note that the PXP key handling is inherently racey, because the key
716+
* can theoretically change at any time (although it's unlikely to do
717+
* so without triggers), even right after we copy it. Taking a lock
718+
* wouldn't help because the value might still change as soon as we
719+
* release the lock.
720+
* Userspace needs to handle the fact that their BOs can go invalid at
721+
* any point.
722+
*/
723+
bo->pxp_key_instance = pxp->key_instance;
724+
725+
return 0;
726+
}
727+
728+
/**
729+
* xe_pxp_bo_key_check - check if the key used by a xe_bo is valid
730+
* @pxp: the xe->pxp pointer (it will be NULL if PXP is disabled)
731+
* @bo: the BO we want to check
732+
*
733+
* Checks whether a BO was encrypted with the current key or an obsolete one.
734+
*
735+
* Returns: 0 if the key is valid, -ENODEV if PXP is disabled, -EINVAL if the
736+
* BO is not using PXP, -ENOEXEC if the key is not valid.
737+
*/
738+
int xe_pxp_bo_key_check(struct xe_pxp *pxp, struct xe_bo *bo)
739+
{
740+
if (!xe_pxp_is_enabled(pxp))
741+
return -ENODEV;
742+
743+
if (!xe_bo_is_protected(bo))
744+
return -EINVAL;
745+
746+
xe_assert(pxp->xe, bo->pxp_key_instance);
747+
748+
/*
749+
* Note that the PXP key handling is inherently racey, because the key
750+
* can theoretically change at any time (although it's unlikely to do
751+
* so without triggers), even right after we check it. Taking a lock
752+
* wouldn't help because the value might still change as soon as we
753+
* release the lock.
754+
* We mitigate the risk by checking the key at multiple points (on each
755+
* submission involving the BO and right before flipping it on the
756+
* display), but there is still a very small chance that we could
757+
* operate on an invalid BO for a single submission or a single frame
758+
* flip. This is a compromise made to protect the encrypted data (which
759+
* is what the key termination is for).
760+
*/
761+
if (bo->pxp_key_instance != pxp->key_instance)
762+
return -ENOEXEC;
763+
764+
return 0;
765+
}
766+
767+
/**
768+
* xe_pxp_obj_key_check - check if the key used by a drm_gem_obj is valid
769+
* @pxp: the xe->pxp pointer (it will be NULL if PXP is disabled)
770+
* @obj: the drm_gem_obj we want to check
771+
*
772+
* Checks whether a drm_gem_obj was encrypted with the current key or an
773+
* obsolete one.
774+
*
775+
* Returns: 0 if the key is valid, -ENODEV if PXP is disabled, -EINVAL if the
776+
* obj is not using PXP, -ENOEXEC if the key is not valid.
777+
*/
778+
int xe_pxp_obj_key_check(struct xe_pxp *pxp, struct drm_gem_object *obj)
779+
{
780+
return xe_pxp_bo_key_check(pxp, gem_to_xe_bo(obj));
781+
}

drivers/gpu/drm/xe/xe_pxp.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#include <linux/types.h>
1010

11+
struct drm_gem_object;
12+
struct xe_bo;
1113
struct xe_device;
1214
struct xe_exec_queue;
1315
struct xe_pxp;
@@ -23,4 +25,8 @@ int xe_pxp_exec_queue_set_type(struct xe_pxp *pxp, struct xe_exec_queue *q, u8 t
2325
int xe_pxp_exec_queue_add(struct xe_pxp *pxp, struct xe_exec_queue *q);
2426
void xe_pxp_exec_queue_remove(struct xe_pxp *pxp, struct xe_exec_queue *q);
2527

28+
int xe_pxp_key_assign(struct xe_pxp *pxp, struct xe_bo *bo);
29+
int xe_pxp_bo_key_check(struct xe_pxp *pxp, struct xe_bo *bo);
30+
int xe_pxp_obj_key_check(struct xe_pxp *pxp, struct drm_gem_object *obj);
31+
2632
#endif /* __XE_PXP_H__ */

drivers/gpu/drm/xe/xe_pxp_types.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,17 @@ struct xe_pxp {
112112
/** @queues.list: list of exec_queues that use PXP */
113113
struct list_head list;
114114
} queues;
115+
116+
/**
117+
* @key_instance: keep track of the current iteration of the PXP key.
118+
* Note that, due to the time needed for PXP termination and re-start
119+
* to complete, the minimum time between 2 subsequent increases of this
120+
* variable is 50ms, and even that only if there is a continuous attack;
121+
* normal behavior is for this to increase much much slower than that.
122+
* This means that we don't expect this to ever wrap and don't implement
123+
* that case in the code.
124+
*/
125+
u32 key_instance;
115126
};
116127

117128
#endif /* __XE_PXP_TYPES_H__ */

0 commit comments

Comments
 (0)