|
8 | 8 | #include <linux/compat.h>
|
9 | 9 | #include <linux/cpu.h>
|
10 | 10 | #include <linux/mman.h>
|
| 11 | +#include <linux/nospec.h> |
11 | 12 | #include <linux/pkeys.h>
|
12 | 13 | #include <linux/seq_file.h>
|
13 | 14 | #include <linux/proc_fs.h>
|
|
18 | 19 | #include <asm/fpu/xcr.h>
|
19 | 20 |
|
20 | 21 | #include <asm/tlbflush.h>
|
| 22 | +#include <asm/prctl.h> |
| 23 | +#include <asm/elf.h> |
21 | 24 |
|
22 | 25 | #include "internal.h"
|
23 | 26 | #include "legacy.h"
|
@@ -1298,6 +1301,159 @@ void fpstate_clear_xstate_component(struct fpstate *fps, unsigned int xfeature)
|
1298 | 1301 | EXPORT_SYMBOL_GPL(fpstate_clear_xstate_component);
|
1299 | 1302 | #endif
|
1300 | 1303 |
|
| 1304 | +#ifdef CONFIG_X86_64 |
| 1305 | +static int validate_sigaltstack(unsigned int usize) |
| 1306 | +{ |
| 1307 | + struct task_struct *thread, *leader = current->group_leader; |
| 1308 | + unsigned long framesize = get_sigframe_size(); |
| 1309 | + |
| 1310 | + lockdep_assert_held(¤t->sighand->siglock); |
| 1311 | + |
| 1312 | + /* get_sigframe_size() is based on fpu_user_cfg.max_size */ |
| 1313 | + framesize -= fpu_user_cfg.max_size; |
| 1314 | + framesize += usize; |
| 1315 | + for_each_thread(leader, thread) { |
| 1316 | + if (thread->sas_ss_size && thread->sas_ss_size < framesize) |
| 1317 | + return -ENOSPC; |
| 1318 | + } |
| 1319 | + return 0; |
| 1320 | +} |
| 1321 | + |
| 1322 | +static int __xstate_request_perm(u64 permitted, u64 requested) |
| 1323 | +{ |
| 1324 | + /* |
| 1325 | + * This deliberately does not exclude !XSAVES as we still might |
| 1326 | + * decide to optionally context switch XCR0 or talk the silicon |
| 1327 | + * vendors into extending XFD for the pre AMX states. |
| 1328 | + */ |
| 1329 | + bool compacted = cpu_feature_enabled(X86_FEATURE_XSAVES); |
| 1330 | + struct fpu *fpu = ¤t->group_leader->thread.fpu; |
| 1331 | + unsigned int ksize, usize; |
| 1332 | + u64 mask; |
| 1333 | + int ret; |
| 1334 | + |
| 1335 | + /* Check whether fully enabled */ |
| 1336 | + if ((permitted & requested) == requested) |
| 1337 | + return 0; |
| 1338 | + |
| 1339 | + /* Calculate the resulting kernel state size */ |
| 1340 | + mask = permitted | requested; |
| 1341 | + ksize = xstate_calculate_size(mask, compacted); |
| 1342 | + |
| 1343 | + /* Calculate the resulting user state size */ |
| 1344 | + mask &= XFEATURE_MASK_USER_SUPPORTED; |
| 1345 | + usize = xstate_calculate_size(mask, false); |
| 1346 | + |
| 1347 | + ret = validate_sigaltstack(usize); |
| 1348 | + if (ret) |
| 1349 | + return ret; |
| 1350 | + |
| 1351 | + /* Pairs with the READ_ONCE() in xstate_get_group_perm() */ |
| 1352 | + WRITE_ONCE(fpu->perm.__state_perm, requested); |
| 1353 | + /* Protected by sighand lock */ |
| 1354 | + fpu->perm.__state_size = ksize; |
| 1355 | + fpu->perm.__user_state_size = usize; |
| 1356 | + return ret; |
| 1357 | +} |
| 1358 | + |
| 1359 | +/* |
| 1360 | + * Permissions array to map facilities with more than one component |
| 1361 | + */ |
| 1362 | +static const u64 xstate_prctl_req[XFEATURE_MAX] = { |
| 1363 | + /* [XFEATURE_XTILE_DATA] = XFEATURE_MASK_XTILE, */ |
| 1364 | +}; |
| 1365 | + |
| 1366 | +static int xstate_request_perm(unsigned long idx) |
| 1367 | +{ |
| 1368 | + u64 permitted, requested; |
| 1369 | + int ret; |
| 1370 | + |
| 1371 | + if (idx >= XFEATURE_MAX) |
| 1372 | + return -EINVAL; |
| 1373 | + |
| 1374 | + /* |
| 1375 | + * Look up the facility mask which can require more than |
| 1376 | + * one xstate component. |
| 1377 | + */ |
| 1378 | + idx = array_index_nospec(idx, ARRAY_SIZE(xstate_prctl_req)); |
| 1379 | + requested = xstate_prctl_req[idx]; |
| 1380 | + if (!requested) |
| 1381 | + return -EOPNOTSUPP; |
| 1382 | + |
| 1383 | + if ((fpu_user_cfg.max_features & requested) != requested) |
| 1384 | + return -EOPNOTSUPP; |
| 1385 | + |
| 1386 | + /* Lockless quick check */ |
| 1387 | + permitted = xstate_get_host_group_perm(); |
| 1388 | + if ((permitted & requested) == requested) |
| 1389 | + return 0; |
| 1390 | + |
| 1391 | + /* Protect against concurrent modifications */ |
| 1392 | + spin_lock_irq(¤t->sighand->siglock); |
| 1393 | + permitted = xstate_get_host_group_perm(); |
| 1394 | + ret = __xstate_request_perm(permitted, requested); |
| 1395 | + spin_unlock_irq(¤t->sighand->siglock); |
| 1396 | + return ret; |
| 1397 | +} |
| 1398 | +#else /* CONFIG_X86_64 */ |
| 1399 | +static inline int xstate_request_perm(unsigned long idx) |
| 1400 | +{ |
| 1401 | + return -EPERM; |
| 1402 | +} |
| 1403 | +#endif /* !CONFIG_X86_64 */ |
| 1404 | + |
| 1405 | +/** |
| 1406 | + * fpu_xstate_prctl - xstate permission operations |
| 1407 | + * @tsk: Redundant pointer to current |
| 1408 | + * @option: A subfunction of arch_prctl() |
| 1409 | + * @arg2: option argument |
| 1410 | + * Return: 0 if successful; otherwise, an error code |
| 1411 | + * |
| 1412 | + * Option arguments: |
| 1413 | + * |
| 1414 | + * ARCH_GET_XCOMP_SUPP: Pointer to user space u64 to store the info |
| 1415 | + * ARCH_GET_XCOMP_PERM: Pointer to user space u64 to store the info |
| 1416 | + * ARCH_REQ_XCOMP_PERM: Facility number requested |
| 1417 | + * |
| 1418 | + * For facilities which require more than one XSTATE component, the request |
| 1419 | + * must be the highest state component number related to that facility, |
| 1420 | + * e.g. for AMX which requires XFEATURE_XTILE_CFG(17) and |
| 1421 | + * XFEATURE_XTILE_DATA(18) this would be XFEATURE_XTILE_DATA(18). |
| 1422 | + */ |
| 1423 | +long fpu_xstate_prctl(struct task_struct *tsk, int option, unsigned long arg2) |
| 1424 | +{ |
| 1425 | + u64 __user *uptr = (u64 __user *)arg2; |
| 1426 | + u64 permitted, supported; |
| 1427 | + unsigned long idx = arg2; |
| 1428 | + |
| 1429 | + if (tsk != current) |
| 1430 | + return -EPERM; |
| 1431 | + |
| 1432 | + switch (option) { |
| 1433 | + case ARCH_GET_XCOMP_SUPP: |
| 1434 | + supported = fpu_user_cfg.max_features | fpu_user_cfg.legacy_features; |
| 1435 | + return put_user(supported, uptr); |
| 1436 | + |
| 1437 | + case ARCH_GET_XCOMP_PERM: |
| 1438 | + /* |
| 1439 | + * Lockless snapshot as it can also change right after the |
| 1440 | + * dropping the lock. |
| 1441 | + */ |
| 1442 | + permitted = xstate_get_host_group_perm(); |
| 1443 | + permitted &= XFEATURE_MASK_USER_SUPPORTED; |
| 1444 | + return put_user(permitted, uptr); |
| 1445 | + |
| 1446 | + case ARCH_REQ_XCOMP_PERM: |
| 1447 | + if (!IS_ENABLED(CONFIG_X86_64)) |
| 1448 | + return -EOPNOTSUPP; |
| 1449 | + |
| 1450 | + return xstate_request_perm(idx); |
| 1451 | + |
| 1452 | + default: |
| 1453 | + return -EINVAL; |
| 1454 | + } |
| 1455 | +} |
| 1456 | + |
1301 | 1457 | #ifdef CONFIG_PROC_PID_ARCH_STATUS
|
1302 | 1458 | /*
|
1303 | 1459 | * Report the amount of time elapsed in millisecond since last AVX512
|
|
0 commit comments