Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/arm64/mm/extable.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Based on arch/arm/mm/extable.c
4
*/
5
6
#include <linux/bitfield.h>
7
#include <linux/extable.h>
8
#include <linux/uaccess.h>
9
10
#include <asm/asm-extable.h>
11
#include <asm/esr.h>
12
#include <asm/ptrace.h>
13
14
static bool cpy_faulted_on_uaccess(const struct exception_table_entry *ex,
15
unsigned long esr)
16
{
17
bool uaccess_is_write = FIELD_GET(EX_DATA_UACCESS_WRITE, ex->data);
18
bool fault_on_write = esr & ESR_ELx_WNR;
19
20
return uaccess_is_write == fault_on_write;
21
}
22
23
bool insn_may_access_user(unsigned long addr, unsigned long esr)
24
{
25
const struct exception_table_entry *ex = search_exception_tables(addr);
26
27
if (!ex)
28
return false;
29
30
switch (ex->type) {
31
case EX_TYPE_UACCESS_CPY:
32
return cpy_faulted_on_uaccess(ex, esr);
33
default:
34
return true;
35
}
36
}
37
38
static inline unsigned long
39
get_ex_fixup(const struct exception_table_entry *ex)
40
{
41
return ((unsigned long)&ex->fixup + ex->fixup);
42
}
43
44
static bool ex_handler_uaccess_err_zero(const struct exception_table_entry *ex,
45
struct pt_regs *regs)
46
{
47
int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data);
48
int reg_zero = FIELD_GET(EX_DATA_REG_ZERO, ex->data);
49
50
pt_regs_write_reg(regs, reg_err, -EFAULT);
51
pt_regs_write_reg(regs, reg_zero, 0);
52
53
regs->pc = get_ex_fixup(ex);
54
return true;
55
}
56
57
static bool ex_handler_uaccess_cpy(const struct exception_table_entry *ex,
58
struct pt_regs *regs, unsigned long esr)
59
{
60
/* Do not fix up faults on kernel memory accesses */
61
if (!cpy_faulted_on_uaccess(ex, esr))
62
return false;
63
64
regs->pc = get_ex_fixup(ex);
65
return true;
66
}
67
68
static bool
69
ex_handler_load_unaligned_zeropad(const struct exception_table_entry *ex,
70
struct pt_regs *regs)
71
{
72
int reg_data = FIELD_GET(EX_DATA_REG_DATA, ex->data);
73
int reg_addr = FIELD_GET(EX_DATA_REG_ADDR, ex->data);
74
unsigned long data, addr, offset;
75
76
addr = pt_regs_read_reg(regs, reg_addr);
77
78
offset = addr & 0x7UL;
79
addr &= ~0x7UL;
80
81
data = *(unsigned long*)addr;
82
83
#ifndef __AARCH64EB__
84
data >>= 8 * offset;
85
#else
86
data <<= 8 * offset;
87
#endif
88
89
pt_regs_write_reg(regs, reg_data, data);
90
91
regs->pc = get_ex_fixup(ex);
92
return true;
93
}
94
95
bool fixup_exception(struct pt_regs *regs, unsigned long esr)
96
{
97
const struct exception_table_entry *ex;
98
99
ex = search_exception_tables(instruction_pointer(regs));
100
if (!ex)
101
return false;
102
103
switch (ex->type) {
104
case EX_TYPE_BPF:
105
return ex_handler_bpf(ex, regs);
106
case EX_TYPE_UACCESS_ERR_ZERO:
107
case EX_TYPE_KACCESS_ERR_ZERO:
108
return ex_handler_uaccess_err_zero(ex, regs);
109
case EX_TYPE_UACCESS_CPY:
110
return ex_handler_uaccess_cpy(ex, regs, esr);
111
case EX_TYPE_LOAD_UNALIGNED_ZEROPAD:
112
return ex_handler_load_unaligned_zeropad(ex, regs);
113
}
114
115
BUG();
116
}
117
118