mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 14:53:58 -04:00
Merge tag 'riscv-for-linus-v7.0-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux
Pull RISC-V updates from Paul Walmsley:
"Before v7.0 is released, fix a few issues with the CFI patchset,
merged earlier in v7.0-rc, that primarily affect interfaces to
non-kernel code:
- Improve the prctl() interface for per-task indirect branch landing
pad control to expand abbreviations and to resemble the speculation
control prctl() interface
- Expand the "LP" and "SS" abbreviations in the ptrace uapi header
file to "branch landing pad" and "shadow stack", to improve
readability
- Fix a typo in a CFI-related macro name in the ptrace uapi header
file
- Ensure that the indirect branch tracking state and shadow stack
state are unlocked immediately after an exec() on the new task so
that libc subsequently can control it
- While working in this area, clean up the kernel-internal,
cross-architecture prctl() function names by expanding the
abbreviations mentioned above"
* tag 'riscv-for-linus-v7.0-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux:
prctl: cfi: change the branch landing pad prctl()s to be more descriptive
riscv: ptrace: cfi: expand "SS" references to "shadow stack" in uapi headers
prctl: rename branch landing pad implementation functions to be more explicit
riscv: ptrace: expand "LP" references to "branch landing pads" in uapi headers
riscv: cfi: clear CFI lock status in start_thread()
riscv: ptrace: cfi: fix "PRACE" typo in uapi header
This commit is contained in:
@@ -76,34 +76,49 @@ the program.
|
|||||||
4. prctl() enabling
|
4. prctl() enabling
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
:c:macro:`PR_SET_INDIR_BR_LP_STATUS` / :c:macro:`PR_GET_INDIR_BR_LP_STATUS` /
|
Per-task indirect branch tracking state can be monitored and
|
||||||
:c:macro:`PR_LOCK_INDIR_BR_LP_STATUS` are three prctls added to manage indirect
|
controlled via the :c:macro:`PR_GET_CFI` and :c:macro:`PR_SET_CFI`
|
||||||
branch tracking. These prctls are architecture-agnostic and return -EINVAL if
|
``prctl()` arguments (respectively), by supplying
|
||||||
the underlying functionality is not supported.
|
:c:macro:`PR_CFI_BRANCH_LANDING_PADS` as the second argument. These
|
||||||
|
are architecture-agnostic, and will return -EINVAL if the underlying
|
||||||
|
functionality is not supported.
|
||||||
|
|
||||||
* prctl(PR_SET_INDIR_BR_LP_STATUS, unsigned long arg)
|
* prctl(:c:macro:`PR_SET_CFI`, :c:macro:`PR_CFI_BRANCH_LANDING_PADS`, unsigned long arg)
|
||||||
|
|
||||||
If arg1 is :c:macro:`PR_INDIR_BR_LP_ENABLE` and if CPU supports
|
arg is a bitmask.
|
||||||
``zicfilp`` then the kernel will enable indirect branch tracking for the
|
|
||||||
task. The dynamic loader can issue this :c:macro:`prctl` once it has
|
If :c:macro:`PR_CFI_ENABLE` is set in arg, and the CPU supports
|
||||||
|
``zicfilp``, then the kernel will enable indirect branch tracking for
|
||||||
|
the task. The dynamic loader can issue this ``prctl()`` once it has
|
||||||
determined that all the objects loaded in the address space support
|
determined that all the objects loaded in the address space support
|
||||||
indirect branch tracking. Additionally, if there is a `dlopen` to an
|
indirect branch tracking.
|
||||||
object which wasn't compiled with ``zicfilp``, the dynamic loader can
|
|
||||||
issue this prctl with arg1 set to 0 (i.e. :c:macro:`PR_INDIR_BR_LP_ENABLE`
|
|
||||||
cleared).
|
|
||||||
|
|
||||||
* prctl(PR_GET_INDIR_BR_LP_STATUS, unsigned long * arg)
|
Indirect branch tracking state can also be locked once enabled. This
|
||||||
|
prevents the task from subsequently disabling it. This is done by
|
||||||
|
setting the bit :c:macro:`PR_CFI_LOCK` in arg. Either indirect branch
|
||||||
|
tracking must already be enabled for the task, or the bit
|
||||||
|
:c:macro:`PR_CFI_ENABLE` must also be set in arg. This is intended
|
||||||
|
for environments that wish to run with a strict security posture that
|
||||||
|
do not wish to load objects without ``zicfilp`` support.
|
||||||
|
|
||||||
Returns the current status of indirect branch tracking. If enabled
|
Indirect branch tracking can also be disabled for the task, assuming
|
||||||
it'll return :c:macro:`PR_INDIR_BR_LP_ENABLE`
|
that it has not previously been enabled and locked. If there is a
|
||||||
|
``dlopen()`` to an object which wasn't compiled with ``zicfilp``, the
|
||||||
|
dynamic loader can issue this ``prctl()`` with arg set to
|
||||||
|
:c:macro:`PR_CFI_DISABLE`. Disabling indirect branch tracking for the
|
||||||
|
task is not possible if it has previously been enabled and locked.
|
||||||
|
|
||||||
* prctl(PR_LOCK_INDIR_BR_LP_STATUS, unsigned long arg)
|
|
||||||
|
|
||||||
Locks the current status of indirect branch tracking on the task. User
|
* prctl(:c:macro:`PR_GET_CFI`, :c:macro:`PR_CFI_BRANCH_LANDING_PADS`, unsigned long * arg)
|
||||||
space may want to run with a strict security posture and wouldn't want
|
|
||||||
loading of objects without ``zicfilp`` support in them, to disallow
|
Returns the current status of indirect branch tracking into a bitmask
|
||||||
disabling of indirect branch tracking. In this case, user space can
|
stored into the memory location pointed to by arg. The bitmask will
|
||||||
use this prctl to lock the current settings.
|
have the :c:macro:`PR_CFI_ENABLE` bit set if indirect branch tracking
|
||||||
|
is currently enabled for the task, and if it is locked, will
|
||||||
|
additionally have the :c:macro:`PR_CFI_LOCK` bit set. If indirect
|
||||||
|
branch tracking is currently disabled for the task, the
|
||||||
|
:c:macro:`PR_CFI_DISABLE` bit will be set.
|
||||||
|
|
||||||
|
|
||||||
5. violations related to indirect branch tracking
|
5. violations related to indirect branch tracking
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ void set_active_shstk(struct task_struct *task, unsigned long shstk_addr);
|
|||||||
bool is_shstk_enabled(struct task_struct *task);
|
bool is_shstk_enabled(struct task_struct *task);
|
||||||
bool is_shstk_locked(struct task_struct *task);
|
bool is_shstk_locked(struct task_struct *task);
|
||||||
bool is_shstk_allocated(struct task_struct *task);
|
bool is_shstk_allocated(struct task_struct *task);
|
||||||
void set_shstk_lock(struct task_struct *task);
|
void set_shstk_lock(struct task_struct *task, bool lock);
|
||||||
void set_shstk_status(struct task_struct *task, bool enable);
|
void set_shstk_status(struct task_struct *task, bool enable);
|
||||||
unsigned long get_active_shstk(struct task_struct *task);
|
unsigned long get_active_shstk(struct task_struct *task);
|
||||||
int restore_user_shstk(struct task_struct *tsk, unsigned long shstk_ptr);
|
int restore_user_shstk(struct task_struct *tsk, unsigned long shstk_ptr);
|
||||||
@@ -47,7 +47,7 @@ int save_user_shstk(struct task_struct *tsk, unsigned long *saved_shstk_ptr);
|
|||||||
bool is_indir_lp_enabled(struct task_struct *task);
|
bool is_indir_lp_enabled(struct task_struct *task);
|
||||||
bool is_indir_lp_locked(struct task_struct *task);
|
bool is_indir_lp_locked(struct task_struct *task);
|
||||||
void set_indir_lp_status(struct task_struct *task, bool enable);
|
void set_indir_lp_status(struct task_struct *task, bool enable);
|
||||||
void set_indir_lp_lock(struct task_struct *task);
|
void set_indir_lp_lock(struct task_struct *task, bool lock);
|
||||||
|
|
||||||
#define PR_SHADOW_STACK_SUPPORTED_STATUS_MASK (PR_SHADOW_STACK_ENABLE)
|
#define PR_SHADOW_STACK_SUPPORTED_STATUS_MASK (PR_SHADOW_STACK_ENABLE)
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ void set_indir_lp_lock(struct task_struct *task);
|
|||||||
|
|
||||||
#define is_shstk_allocated(task) false
|
#define is_shstk_allocated(task) false
|
||||||
|
|
||||||
#define set_shstk_lock(task) do {} while (0)
|
#define set_shstk_lock(task, lock) do {} while (0)
|
||||||
|
|
||||||
#define set_shstk_status(task, enable) do {} while (0)
|
#define set_shstk_status(task, enable) do {} while (0)
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ void set_indir_lp_lock(struct task_struct *task);
|
|||||||
|
|
||||||
#define set_indir_lp_status(task, enable) do {} while (0)
|
#define set_indir_lp_status(task, enable) do {} while (0)
|
||||||
|
|
||||||
#define set_indir_lp_lock(task) do {} while (0)
|
#define set_indir_lp_lock(task, lock) do {} while (0)
|
||||||
|
|
||||||
#define restore_user_shstk(tsk, shstk_ptr) -EINVAL
|
#define restore_user_shstk(tsk, shstk_ptr) -EINVAL
|
||||||
|
|
||||||
|
|||||||
@@ -132,26 +132,28 @@ struct __sc_riscv_cfi_state {
|
|||||||
unsigned long ss_ptr; /* shadow stack pointer */
|
unsigned long ss_ptr; /* shadow stack pointer */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PTRACE_CFI_LP_EN_BIT 0
|
#define PTRACE_CFI_BRANCH_LANDING_PAD_EN_BIT 0
|
||||||
#define PTRACE_CFI_LP_LOCK_BIT 1
|
#define PTRACE_CFI_BRANCH_LANDING_PAD_LOCK_BIT 1
|
||||||
#define PTRACE_CFI_ELP_BIT 2
|
#define PTRACE_CFI_BRANCH_EXPECTED_LANDING_PAD_BIT 2
|
||||||
#define PTRACE_CFI_SS_EN_BIT 3
|
#define PTRACE_CFI_SHADOW_STACK_EN_BIT 3
|
||||||
#define PTRACE_CFI_SS_LOCK_BIT 4
|
#define PTRACE_CFI_SHADOW_STACK_LOCK_BIT 4
|
||||||
#define PTRACE_CFI_SS_PTR_BIT 5
|
#define PTRACE_CFI_SHADOW_STACK_PTR_BIT 5
|
||||||
|
|
||||||
#define PTRACE_CFI_LP_EN_STATE _BITUL(PTRACE_CFI_LP_EN_BIT)
|
#define PTRACE_CFI_BRANCH_LANDING_PAD_EN_STATE _BITUL(PTRACE_CFI_BRANCH_LANDING_PAD_EN_BIT)
|
||||||
#define PTRACE_CFI_LP_LOCK_STATE _BITUL(PTRACE_CFI_LP_LOCK_BIT)
|
#define PTRACE_CFI_BRANCH_LANDING_PAD_LOCK_STATE \
|
||||||
#define PTRACE_CFI_ELP_STATE _BITUL(PTRACE_CFI_ELP_BIT)
|
_BITUL(PTRACE_CFI_BRANCH_LANDING_PAD_LOCK_BIT)
|
||||||
#define PTRACE_CFI_SS_EN_STATE _BITUL(PTRACE_CFI_SS_EN_BIT)
|
#define PTRACE_CFI_BRANCH_EXPECTED_LANDING_PAD_STATE \
|
||||||
#define PTRACE_CFI_SS_LOCK_STATE _BITUL(PTRACE_CFI_SS_LOCK_BIT)
|
_BITUL(PTRACE_CFI_BRANCH_EXPECTED_LANDING_PAD_BIT)
|
||||||
#define PTRACE_CFI_SS_PTR_STATE _BITUL(PTRACE_CFI_SS_PTR_BIT)
|
#define PTRACE_CFI_SHADOW_STACK_EN_STATE _BITUL(PTRACE_CFI_SHADOW_STACK_EN_BIT)
|
||||||
|
#define PTRACE_CFI_SHADOW_STACK_LOCK_STATE _BITUL(PTRACE_CFI_SHADOW_STACK_LOCK_BIT)
|
||||||
|
#define PTRACE_CFI_SHADOW_STACK_PTR_STATE _BITUL(PTRACE_CFI_SHADOW_STACK_PTR_BIT)
|
||||||
|
|
||||||
#define PRACE_CFI_STATE_INVALID_MASK ~(PTRACE_CFI_LP_EN_STATE | \
|
#define PTRACE_CFI_STATE_INVALID_MASK ~(PTRACE_CFI_BRANCH_LANDING_PAD_EN_STATE | \
|
||||||
PTRACE_CFI_LP_LOCK_STATE | \
|
PTRACE_CFI_BRANCH_LANDING_PAD_LOCK_STATE | \
|
||||||
PTRACE_CFI_ELP_STATE | \
|
PTRACE_CFI_BRANCH_EXPECTED_LANDING_PAD_STATE | \
|
||||||
PTRACE_CFI_SS_EN_STATE | \
|
PTRACE_CFI_SHADOW_STACK_EN_STATE | \
|
||||||
PTRACE_CFI_SS_LOCK_STATE | \
|
PTRACE_CFI_SHADOW_STACK_LOCK_STATE | \
|
||||||
PTRACE_CFI_SS_PTR_STATE)
|
PTRACE_CFI_SHADOW_STACK_PTR_STATE)
|
||||||
|
|
||||||
struct __cfi_status {
|
struct __cfi_status {
|
||||||
__u64 cfi_state;
|
__u64 cfi_state;
|
||||||
|
|||||||
@@ -160,6 +160,7 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
|
|||||||
* clear shadow stack state on exec.
|
* clear shadow stack state on exec.
|
||||||
* libc will set it later via prctl.
|
* libc will set it later via prctl.
|
||||||
*/
|
*/
|
||||||
|
set_shstk_lock(current, false);
|
||||||
set_shstk_status(current, false);
|
set_shstk_status(current, false);
|
||||||
set_shstk_base(current, 0, 0);
|
set_shstk_base(current, 0, 0);
|
||||||
set_active_shstk(current, 0);
|
set_active_shstk(current, 0);
|
||||||
@@ -167,6 +168,7 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
|
|||||||
* disable indirect branch tracking on exec.
|
* disable indirect branch tracking on exec.
|
||||||
* libc will enable it later via prctl.
|
* libc will enable it later via prctl.
|
||||||
*/
|
*/
|
||||||
|
set_indir_lp_lock(current, false);
|
||||||
set_indir_lp_status(current, false);
|
set_indir_lp_status(current, false);
|
||||||
|
|
||||||
#ifdef CONFIG_64BIT
|
#ifdef CONFIG_64BIT
|
||||||
|
|||||||
@@ -303,18 +303,18 @@ static int riscv_cfi_get(struct task_struct *target,
|
|||||||
regs = task_pt_regs(target);
|
regs = task_pt_regs(target);
|
||||||
|
|
||||||
if (is_indir_lp_enabled(target)) {
|
if (is_indir_lp_enabled(target)) {
|
||||||
user_cfi.cfi_status.cfi_state |= PTRACE_CFI_LP_EN_STATE;
|
user_cfi.cfi_status.cfi_state |= PTRACE_CFI_BRANCH_LANDING_PAD_EN_STATE;
|
||||||
user_cfi.cfi_status.cfi_state |= is_indir_lp_locked(target) ?
|
user_cfi.cfi_status.cfi_state |= is_indir_lp_locked(target) ?
|
||||||
PTRACE_CFI_LP_LOCK_STATE : 0;
|
PTRACE_CFI_BRANCH_LANDING_PAD_LOCK_STATE : 0;
|
||||||
user_cfi.cfi_status.cfi_state |= (regs->status & SR_ELP) ?
|
user_cfi.cfi_status.cfi_state |= (regs->status & SR_ELP) ?
|
||||||
PTRACE_CFI_ELP_STATE : 0;
|
PTRACE_CFI_BRANCH_EXPECTED_LANDING_PAD_STATE : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_shstk_enabled(target)) {
|
if (is_shstk_enabled(target)) {
|
||||||
user_cfi.cfi_status.cfi_state |= (PTRACE_CFI_SS_EN_STATE |
|
user_cfi.cfi_status.cfi_state |= (PTRACE_CFI_SHADOW_STACK_EN_STATE |
|
||||||
PTRACE_CFI_SS_PTR_STATE);
|
PTRACE_CFI_SHADOW_STACK_PTR_STATE);
|
||||||
user_cfi.cfi_status.cfi_state |= is_shstk_locked(target) ?
|
user_cfi.cfi_status.cfi_state |= is_shstk_locked(target) ?
|
||||||
PTRACE_CFI_SS_LOCK_STATE : 0;
|
PTRACE_CFI_SHADOW_STACK_LOCK_STATE : 0;
|
||||||
user_cfi.shstk_ptr = get_active_shstk(target);
|
user_cfi.shstk_ptr = get_active_shstk(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,15 +349,15 @@ static int riscv_cfi_set(struct task_struct *target,
|
|||||||
* rsvd field should be set to zero so that if those fields are needed in future
|
* rsvd field should be set to zero so that if those fields are needed in future
|
||||||
*/
|
*/
|
||||||
if ((user_cfi.cfi_status.cfi_state &
|
if ((user_cfi.cfi_status.cfi_state &
|
||||||
(PTRACE_CFI_LP_EN_STATE | PTRACE_CFI_LP_LOCK_STATE |
|
(PTRACE_CFI_BRANCH_LANDING_PAD_EN_STATE | PTRACE_CFI_BRANCH_LANDING_PAD_LOCK_STATE |
|
||||||
PTRACE_CFI_SS_EN_STATE | PTRACE_CFI_SS_LOCK_STATE)) ||
|
PTRACE_CFI_SHADOW_STACK_EN_STATE | PTRACE_CFI_SHADOW_STACK_LOCK_STATE)) ||
|
||||||
(user_cfi.cfi_status.cfi_state & PRACE_CFI_STATE_INVALID_MASK))
|
(user_cfi.cfi_status.cfi_state & PTRACE_CFI_STATE_INVALID_MASK))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* If lpad is enabled on target and ptrace requests to set / clear elp, do that */
|
/* If lpad is enabled on target and ptrace requests to set / clear elp, do that */
|
||||||
if (is_indir_lp_enabled(target)) {
|
if (is_indir_lp_enabled(target)) {
|
||||||
if (user_cfi.cfi_status.cfi_state &
|
if (user_cfi.cfi_status.cfi_state &
|
||||||
PTRACE_CFI_ELP_STATE) /* set elp state */
|
PTRACE_CFI_BRANCH_EXPECTED_LANDING_PAD_STATE) /* set elp state */
|
||||||
regs->status |= SR_ELP;
|
regs->status |= SR_ELP;
|
||||||
else
|
else
|
||||||
regs->status &= ~SR_ELP; /* clear elp state */
|
regs->status &= ~SR_ELP; /* clear elp state */
|
||||||
@@ -365,7 +365,7 @@ static int riscv_cfi_set(struct task_struct *target,
|
|||||||
|
|
||||||
/* If shadow stack enabled on target, set new shadow stack pointer */
|
/* If shadow stack enabled on target, set new shadow stack pointer */
|
||||||
if (is_shstk_enabled(target) &&
|
if (is_shstk_enabled(target) &&
|
||||||
(user_cfi.cfi_status.cfi_state & PTRACE_CFI_SS_PTR_STATE))
|
(user_cfi.cfi_status.cfi_state & PTRACE_CFI_SHADOW_STACK_PTR_STATE))
|
||||||
set_active_shstk(target, user_cfi.shstk_ptr);
|
set_active_shstk(target, user_cfi.shstk_ptr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -74,9 +74,9 @@ void set_shstk_status(struct task_struct *task, bool enable)
|
|||||||
csr_write(CSR_ENVCFG, task->thread.envcfg);
|
csr_write(CSR_ENVCFG, task->thread.envcfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_shstk_lock(struct task_struct *task)
|
void set_shstk_lock(struct task_struct *task, bool lock)
|
||||||
{
|
{
|
||||||
task->thread_info.user_cfi_state.ubcfi_locked = 1;
|
task->thread_info.user_cfi_state.ubcfi_locked = lock;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_indir_lp_enabled(struct task_struct *task)
|
bool is_indir_lp_enabled(struct task_struct *task)
|
||||||
@@ -104,9 +104,9 @@ void set_indir_lp_status(struct task_struct *task, bool enable)
|
|||||||
csr_write(CSR_ENVCFG, task->thread.envcfg);
|
csr_write(CSR_ENVCFG, task->thread.envcfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_indir_lp_lock(struct task_struct *task)
|
void set_indir_lp_lock(struct task_struct *task, bool lock)
|
||||||
{
|
{
|
||||||
task->thread_info.user_cfi_state.ufcfi_locked = 1;
|
task->thread_info.user_cfi_state.ufcfi_locked = lock;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* If size is 0, then to be compatible with regular stack we want it to be as big as
|
* If size is 0, then to be compatible with regular stack we want it to be as big as
|
||||||
@@ -452,28 +452,27 @@ int arch_lock_shadow_stack_status(struct task_struct *task,
|
|||||||
!is_shstk_enabled(task) || arg != 0)
|
!is_shstk_enabled(task) || arg != 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
set_shstk_lock(task);
|
set_shstk_lock(task, true);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int arch_get_indir_br_lp_status(struct task_struct *t, unsigned long __user *status)
|
int arch_prctl_get_branch_landing_pad_state(struct task_struct *t,
|
||||||
|
unsigned long __user *state)
|
||||||
{
|
{
|
||||||
unsigned long fcfi_status = 0;
|
unsigned long fcfi_status = 0;
|
||||||
|
|
||||||
if (!is_user_lpad_enabled())
|
if (!is_user_lpad_enabled())
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* indirect branch tracking is enabled on the task or not */
|
fcfi_status = (is_indir_lp_enabled(t) ? PR_CFI_ENABLE : PR_CFI_DISABLE);
|
||||||
fcfi_status |= (is_indir_lp_enabled(t) ? PR_INDIR_BR_LP_ENABLE : 0);
|
fcfi_status |= (is_indir_lp_locked(t) ? PR_CFI_LOCK : 0);
|
||||||
|
|
||||||
return copy_to_user(status, &fcfi_status, sizeof(fcfi_status)) ? -EFAULT : 0;
|
return copy_to_user(state, &fcfi_status, sizeof(fcfi_status)) ? -EFAULT : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int arch_set_indir_br_lp_status(struct task_struct *t, unsigned long status)
|
int arch_prctl_set_branch_landing_pad_state(struct task_struct *t, unsigned long state)
|
||||||
{
|
{
|
||||||
bool enable_indir_lp = false;
|
|
||||||
|
|
||||||
if (!is_user_lpad_enabled())
|
if (!is_user_lpad_enabled())
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@@ -481,28 +480,28 @@ int arch_set_indir_br_lp_status(struct task_struct *t, unsigned long status)
|
|||||||
if (is_indir_lp_locked(t))
|
if (is_indir_lp_locked(t))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Reject unknown flags */
|
if (!(state & (PR_CFI_ENABLE | PR_CFI_DISABLE)))
|
||||||
if (status & ~PR_INDIR_BR_LP_ENABLE)
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
enable_indir_lp = (status & PR_INDIR_BR_LP_ENABLE);
|
if (state & PR_CFI_ENABLE && state & PR_CFI_DISABLE)
|
||||||
set_indir_lp_status(t, enable_indir_lp);
|
return -EINVAL;
|
||||||
|
|
||||||
|
set_indir_lp_status(t, !!(state & PR_CFI_ENABLE));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int arch_lock_indir_br_lp_status(struct task_struct *task,
|
int arch_prctl_lock_branch_landing_pad_state(struct task_struct *task)
|
||||||
unsigned long arg)
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* If indirect branch tracking is not supported or not enabled on task,
|
* If indirect branch tracking is not supported or not enabled on task,
|
||||||
* nothing to lock here
|
* nothing to lock here
|
||||||
*/
|
*/
|
||||||
if (!is_user_lpad_enabled() ||
|
if (!is_user_lpad_enabled() ||
|
||||||
!is_indir_lp_enabled(task) || arg != 0)
|
!is_indir_lp_enabled(task))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
set_indir_lp_lock(task);
|
set_indir_lp_lock(task, true);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -229,8 +229,8 @@ static inline bool cpu_attack_vector_mitigated(enum cpu_attack_vectors v)
|
|||||||
#define smt_mitigations SMT_MITIGATIONS_OFF
|
#define smt_mitigations SMT_MITIGATIONS_OFF
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int arch_get_indir_br_lp_status(struct task_struct *t, unsigned long __user *status);
|
int arch_prctl_get_branch_landing_pad_state(struct task_struct *t, unsigned long __user *state);
|
||||||
int arch_set_indir_br_lp_status(struct task_struct *t, unsigned long status);
|
int arch_prctl_set_branch_landing_pad_state(struct task_struct *t, unsigned long state);
|
||||||
int arch_lock_indir_br_lp_status(struct task_struct *t, unsigned long status);
|
int arch_prctl_lock_branch_landing_pad_state(struct task_struct *t);
|
||||||
|
|
||||||
#endif /* _LINUX_CPU_H_ */
|
#endif /* _LINUX_CPU_H_ */
|
||||||
|
|||||||
@@ -397,30 +397,23 @@ struct prctl_mm_map {
|
|||||||
# define PR_RSEQ_SLICE_EXT_ENABLE 0x01
|
# define PR_RSEQ_SLICE_EXT_ENABLE 0x01
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the current indirect branch tracking configuration for the current
|
* Get or set the control flow integrity (CFI) configuration for the
|
||||||
* thread, this will be the value configured via PR_SET_INDIR_BR_LP_STATUS.
|
* current thread.
|
||||||
|
*
|
||||||
|
* Some per-thread control flow integrity settings are not yet
|
||||||
|
* controlled through this prctl(); see for example
|
||||||
|
* PR_{GET,SET,LOCK}_SHADOW_STACK_STATUS
|
||||||
*/
|
*/
|
||||||
#define PR_GET_INDIR_BR_LP_STATUS 80
|
#define PR_GET_CFI 80
|
||||||
|
#define PR_SET_CFI 81
|
||||||
/*
|
/*
|
||||||
* Set the indirect branch tracking configuration. PR_INDIR_BR_LP_ENABLE will
|
* Forward-edge CFI variants (excluding ARM64 BTI, which has its own
|
||||||
* enable cpu feature for user thread, to track all indirect branches and ensure
|
* prctl()s).
|
||||||
* they land on arch defined landing pad instruction.
|
|
||||||
* x86 - If enabled, an indirect branch must land on an ENDBRANCH instruction.
|
|
||||||
* arch64 - If enabled, an indirect branch must land on a BTI instruction.
|
|
||||||
* riscv - If enabled, an indirect branch must land on an lpad instruction.
|
|
||||||
* PR_INDIR_BR_LP_DISABLE will disable feature for user thread and indirect
|
|
||||||
* branches will no more be tracked by cpu to land on arch defined landing pad
|
|
||||||
* instruction.
|
|
||||||
*/
|
*/
|
||||||
#define PR_SET_INDIR_BR_LP_STATUS 81
|
#define PR_CFI_BRANCH_LANDING_PADS 0
|
||||||
# define PR_INDIR_BR_LP_ENABLE (1UL << 0)
|
/* Return and control values for PR_{GET,SET}_CFI */
|
||||||
|
# define PR_CFI_ENABLE _BITUL(0)
|
||||||
/*
|
# define PR_CFI_DISABLE _BITUL(1)
|
||||||
* Prevent further changes to the specified indirect branch tracking
|
# define PR_CFI_LOCK _BITUL(2)
|
||||||
* configuration. All bits may be locked via this call, including
|
|
||||||
* undefined bits.
|
|
||||||
*/
|
|
||||||
#define PR_LOCK_INDIR_BR_LP_STATUS 82
|
|
||||||
|
|
||||||
#endif /* _LINUX_PRCTL_H */
|
#endif /* _LINUX_PRCTL_H */
|
||||||
|
|||||||
30
kernel/sys.c
30
kernel/sys.c
@@ -2388,17 +2388,18 @@ int __weak arch_lock_shadow_stack_status(struct task_struct *t, unsigned long st
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int __weak arch_get_indir_br_lp_status(struct task_struct *t, unsigned long __user *status)
|
int __weak arch_prctl_get_branch_landing_pad_state(struct task_struct *t,
|
||||||
|
unsigned long __user *state)
|
||||||
{
|
{
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int __weak arch_set_indir_br_lp_status(struct task_struct *t, unsigned long status)
|
int __weak arch_prctl_set_branch_landing_pad_state(struct task_struct *t, unsigned long state)
|
||||||
{
|
{
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int __weak arch_lock_indir_br_lp_status(struct task_struct *t, unsigned long status)
|
int __weak arch_prctl_lock_branch_landing_pad_state(struct task_struct *t)
|
||||||
{
|
{
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -2888,20 +2889,23 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
error = rseq_slice_extension_prctl(arg2, arg3);
|
error = rseq_slice_extension_prctl(arg2, arg3);
|
||||||
break;
|
break;
|
||||||
case PR_GET_INDIR_BR_LP_STATUS:
|
case PR_GET_CFI:
|
||||||
if (arg3 || arg4 || arg5)
|
if (arg2 != PR_CFI_BRANCH_LANDING_PADS)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
error = arch_get_indir_br_lp_status(me, (unsigned long __user *)arg2);
|
if (arg4 || arg5)
|
||||||
|
return -EINVAL;
|
||||||
|
error = arch_prctl_get_branch_landing_pad_state(me, (unsigned long __user *)arg3);
|
||||||
break;
|
break;
|
||||||
case PR_SET_INDIR_BR_LP_STATUS:
|
case PR_SET_CFI:
|
||||||
if (arg3 || arg4 || arg5)
|
if (arg2 != PR_CFI_BRANCH_LANDING_PADS)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
error = arch_set_indir_br_lp_status(me, arg2);
|
if (arg4 || arg5)
|
||||||
break;
|
|
||||||
case PR_LOCK_INDIR_BR_LP_STATUS:
|
|
||||||
if (arg3 || arg4 || arg5)
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
error = arch_lock_indir_br_lp_status(me, arg2);
|
error = arch_prctl_set_branch_landing_pad_state(me, arg3);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
if (arg3 & PR_CFI_LOCK && !(arg3 & PR_CFI_DISABLE))
|
||||||
|
error = arch_prctl_lock_branch_landing_pad_state(me);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
trace_task_prctl_unknown(option, arg2, arg3, arg4, arg5);
|
trace_task_prctl_unknown(option, arg2, arg3, arg4, arg5);
|
||||||
|
|||||||
@@ -397,30 +397,24 @@ struct prctl_mm_map {
|
|||||||
# define PR_RSEQ_SLICE_EXT_ENABLE 0x01
|
# define PR_RSEQ_SLICE_EXT_ENABLE 0x01
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the current indirect branch tracking configuration for the current
|
* Get or set the control flow integrity (CFI) configuration for the
|
||||||
* thread, this will be the value configured via PR_SET_INDIR_BR_LP_STATUS.
|
* current thread.
|
||||||
|
*
|
||||||
|
* Some per-thread control flow integrity settings are not yet
|
||||||
|
* controlled through this prctl(); see for example
|
||||||
|
* PR_{GET,SET,LOCK}_SHADOW_STACK_STATUS
|
||||||
*/
|
*/
|
||||||
#define PR_GET_INDIR_BR_LP_STATUS 80
|
#define PR_GET_CFI 80
|
||||||
|
#define PR_SET_CFI 81
|
||||||
/*
|
/*
|
||||||
* Set the indirect branch tracking configuration. PR_INDIR_BR_LP_ENABLE will
|
* Forward-edge CFI variants (excluding ARM64 BTI, which has its own
|
||||||
* enable cpu feature for user thread, to track all indirect branches and ensure
|
* prctl()s).
|
||||||
* they land on arch defined landing pad instruction.
|
|
||||||
* x86 - If enabled, an indirect branch must land on an ENDBRANCH instruction.
|
|
||||||
* arch64 - If enabled, an indirect branch must land on a BTI instruction.
|
|
||||||
* riscv - If enabled, an indirect branch must land on an lpad instruction.
|
|
||||||
* PR_INDIR_BR_LP_DISABLE will disable feature for user thread and indirect
|
|
||||||
* branches will no more be tracked by cpu to land on arch defined landing pad
|
|
||||||
* instruction.
|
|
||||||
*/
|
*/
|
||||||
#define PR_SET_INDIR_BR_LP_STATUS 81
|
#define PR_CFI_BRANCH_LANDING_PADS 0
|
||||||
# define PR_INDIR_BR_LP_ENABLE (1UL << 0)
|
/* Return and control values for PR_{GET,SET}_CFI */
|
||||||
|
# define PR_CFI_ENABLE _BITUL(0)
|
||||||
|
# define PR_CFI_DISABLE _BITUL(1)
|
||||||
|
# define PR_CFI_LOCK _BITUL(2)
|
||||||
|
|
||||||
/*
|
|
||||||
* Prevent further changes to the specified indirect branch tracking
|
|
||||||
* configuration. All bits may be locked via this call, including
|
|
||||||
* undefined bits.
|
|
||||||
*/
|
|
||||||
#define PR_LOCK_INDIR_BR_LP_STATUS 82
|
|
||||||
|
|
||||||
#endif /* _LINUX_PRCTL_H */
|
#endif /* _LINUX_PRCTL_H */
|
||||||
|
|||||||
@@ -94,9 +94,9 @@ bool cfi_ptrace_test(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (ptrace_test_num) {
|
switch (ptrace_test_num) {
|
||||||
#define CFI_ENABLE_MASK (PTRACE_CFI_LP_EN_STATE | \
|
#define CFI_ENABLE_MASK (PTRACE_CFI_BRANCH_LANDING_PAD_EN_STATE | \
|
||||||
PTRACE_CFI_SS_EN_STATE | \
|
PTRACE_CFI_SHADOW_STACK_EN_STATE | \
|
||||||
PTRACE_CFI_SS_PTR_STATE)
|
PTRACE_CFI_SHADOW_STACK_PTR_STATE)
|
||||||
case 0:
|
case 0:
|
||||||
if ((cfi_reg.cfi_status.cfi_state & CFI_ENABLE_MASK) != CFI_ENABLE_MASK)
|
if ((cfi_reg.cfi_status.cfi_state & CFI_ENABLE_MASK) != CFI_ENABLE_MASK)
|
||||||
ksft_exit_fail_msg("%s: ptrace_getregset failed, %llu\n", __func__,
|
ksft_exit_fail_msg("%s: ptrace_getregset failed, %llu\n", __func__,
|
||||||
@@ -106,7 +106,8 @@ bool cfi_ptrace_test(void)
|
|||||||
__func__);
|
__func__);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (!(cfi_reg.cfi_status.cfi_state & PTRACE_CFI_ELP_STATE))
|
if (!(cfi_reg.cfi_status.cfi_state &
|
||||||
|
PTRACE_CFI_BRANCH_EXPECTED_LANDING_PAD_STATE))
|
||||||
ksft_exit_fail_msg("%s: elp must have been set\n", __func__);
|
ksft_exit_fail_msg("%s: elp must have been set\n", __func__);
|
||||||
/* clear elp state. not interested in anything else */
|
/* clear elp state. not interested in anything else */
|
||||||
cfi_reg.cfi_status.cfi_state = 0;
|
cfi_reg.cfi_status.cfi_state = 0;
|
||||||
@@ -145,11 +146,11 @@ int main(int argc, char *argv[])
|
|||||||
* pads for user mode except lighting up a bit in senvcfg via a prctl.
|
* pads for user mode except lighting up a bit in senvcfg via a prctl.
|
||||||
* Enable landing pad support throughout the execution of the test binary.
|
* Enable landing pad support throughout the execution of the test binary.
|
||||||
*/
|
*/
|
||||||
ret = my_syscall5(__NR_prctl, PR_GET_INDIR_BR_LP_STATUS, &lpad_status, 0, 0, 0);
|
ret = my_syscall5(__NR_prctl, PR_GET_CFI, PR_CFI_BRANCH_LANDING_PADS, &lpad_status, 0, 0);
|
||||||
if (ret)
|
if (ret)
|
||||||
ksft_exit_fail_msg("Get landing pad status failed with %d\n", ret);
|
ksft_exit_fail_msg("Get landing pad status failed with %d\n", ret);
|
||||||
|
|
||||||
if (!(lpad_status & PR_INDIR_BR_LP_ENABLE))
|
if (!(lpad_status & PR_CFI_ENABLE))
|
||||||
ksft_exit_fail_msg("Landing pad is not enabled, should be enabled via glibc\n");
|
ksft_exit_fail_msg("Landing pad is not enabled, should be enabled via glibc\n");
|
||||||
|
|
||||||
ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &ss_status, 0, 0, 0);
|
ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &ss_status, 0, 0, 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user