mark most percpu globals as __ro_after_init
Subsystems (2)
PATCH 1/1 mark most percpu globals as __ro_after_init
Moving pcpu_base_addr to this section comes from PaX where it's part of KERNEXEC. This extends it to the rest of the globals only written by the init code.
--- mm/percpu.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-)
mm/percpu.c +18 -18
@@ -121,35 +121,35 @@ struct pcpu_chunk {unsigned long populated[];/* populated bitmap */ }; -static int pcpu_unit_pages__read_mostly ; -static int pcpu_unit_size__read_mostly ; -static int pcpu_nr_units__read_mostly ; -static int pcpu_atom_size__read_mostly ; -static int pcpu_nr_slots__read_mostly ; -static size_t pcpu_chunk_struct_size__read_mostly ; +static int pcpu_unit_pages__ro_after_init ; +static int pcpu_unit_size__ro_after_init ; +static int pcpu_nr_units__ro_after_init ; +static int pcpu_atom_size__ro_after_init ; +static int pcpu_nr_slots__ro_after_init ; +static size_t pcpu_chunk_struct_size__ro_after_init ;/* cpus with the lowest and highest unit addresses */ -static unsigned int pcpu_low_unit_cpu__read_mostly ; -static unsigned int pcpu_high_unit_cpu__read_mostly ; +static unsigned int pcpu_low_unit_cpu__ro_after_init ; +static unsigned int pcpu_high_unit_cpu__ro_after_init ;/* the address of the first chunk which starts with the kernel static area */ -void *pcpu_base_addr__read_mostly ; +void *pcpu_base_addr__ro_after_init ;EXPORT_SYMBOL_GPL (pcpu_base_addr); -static const int *pcpu_unit_map__read_mostly ;/* cpu -> unit */ -const unsigned long *pcpu_unit_offsets__read_mostly ;/* cpu -> unit offset */ +static const int *pcpu_unit_map__ro_after_init ;/* cpu -> unit */ +const unsigned long *pcpu_unit_offsets__ro_after_init ;/* cpu -> unit offset */ /* group information, used for vm allocation */ -static int pcpu_nr_groups__read_mostly ; -static const unsigned long *pcpu_group_offsets__read_mostly ; -static const size_t *pcpu_group_sizes__read_mostly ; +static int pcpu_nr_groups__ro_after_init ; +static const unsigned long *pcpu_group_offsets__ro_after_init ; +static const size_t *pcpu_group_sizes__ro_after_init ;/* * The first chunk which always exists. Note that unlike other * chunks, this one can be allocated and mapped in several different * ways and thus often doesn't live in the vmalloc area. */ -static struct pcpu_chunk *pcpu_first_chunk; +static struct pcpu_chunk *pcpu_first_chunk__ro_after_init ;/* * Optional reserved chunk. This chunk reserves part of the first
@@ -158,13 +158,13 @@ static struct pcpu_chunk *pcpu_first_chunk;* area doesn't exist, the following variables contain NULL and 0 * respectively. */ -static struct pcpu_chunk *pcpu_reserved_chunk; -static int pcpu_reserved_chunk_limit; +static struct pcpu_chunk *pcpu_reserved_chunk__ro_after_init ; +static int pcpu_reserved_chunk_limit__ro_after_init ;static DEFINE_SPINLOCK (pcpu_lock);/* all internal data structures */ static DEFINE_MUTEX (pcpu_alloc_mutex);/* chunk create/destroy, [de]pop, map ext */ -static struct list_head *pcpu_slot__read_mostly ;/* chunk list slots */ +static struct list_head *pcpu_slot__ro_after_init ;/* chunk list slots */ /* chunks which need their map areas extended, protected by pcpu_lock */ static LIST_HEAD (pcpu_map_extend_chunks);
Signature · 1 line
2.12.2
Tejun Heo
maintainerHello, Daniel.
Quoted 3 lines · Daniel Micay
Moving
pcpu_base_addrto this section comes from PaX where it's part of KERNEXEC. This extends it to the rest of the globals only written by the init code.
How did you test the patch?
mm/percpu.c static struct pcpu_chunk *pcpu_first_chunk; · line 167
Quoted 2 lines
mm/percpu.c +1
-1-static struct list_head *pcpu_slot__read_mostly ;/* chunk list slots */ +static struct list_head *pcpu_slot__ro_after_init ;/* chunk list slots */
At least this one isn't read only.
Thanks.
Signature · 1 line
tejun
Quoted 10 lines · Tejun Heo
Hello, Daniel.
Quoted 5 lines · Daniel Micay
Moving
pcpu_base_addrto this section comes from PaX where it's part of
KERNEXEC. This extends it to the rest of the globals only written by the
init code.How did you test the patch?
Booted / did some stuff on x86 (it's running right now), and currently building it for a 3.18 arm64 kernel to test there.
Quoted 7 lines
Quoted 5 lines
-static struct
list_head*pcpu_slot__read_mostly; /* chunk list slots */
+static structlist_head*pcpu_slot__ro_after_init; /* chunk list slots */At least this one isn't read only.
It's the array it points to being modified after it gets assigned to during init with pcpu_slot = memblock_virt_alloc(...), not the pointer variable itself. The references after init are all pcpu_slot[...] including taking references to slots in the array so there's always a dereference happening first.
Quoted 2 lines
Booted / did some stuff on x86 (it's running right now), and currently building it for a 3.18 arm64 kernel to test there.
Yeah, confirmed to work on an Android 3.18 arm64 kernel (Pixel phone) too in addition to 4.11 and master for x86_64.
Tejun Heo
maintainerQuoted 23 lines · Daniel Micay
Quoted 10 lines · Tejun Heo
Hello, Daniel.
Quoted 5 lines · Daniel Micay
Moving
pcpu_base_addrto this section comes from PaX where it's part of
KERNEXEC. This extends it to the rest of the globals only written by the
init code.How did you test the patch?
Booted / did some stuff on x86 (it's running right now), and currently building it for a 3.18 arm64 kernel to test there.
Quoted 7 lines
Quoted 5 lines
-static struct
list_head*pcpu_slot__read_mostly; /* chunk list slots */
+static structlist_head*pcpu_slot__ro_after_init; /* chunk list slots */At least this one isn't read only.
Quoted 5 lines
It's the array it points to being modified after it gets assigned to during init with
pcpu_slot=memblock_virt_alloc(...), not the pointer variable itself. The references after init are all pcpu_slot[...] including taking references to slots in the array so there's always a dereference happening first.
Ah, right. Cool, applying to percpu/for-4.13.
Thanks.
Signature · 1 line
tejun
Quoted 5 lines · Daniel Micay
Moving
pcpu_base_addrto this section comes from PaX where it's part of KERNEXEC. This extends it to the rest of the globals only written by the init code.Signed-off-by Daniel Micay <[email protected]>
Excellent, thanks!
-Kees
Quoted 79 lines
--- mm/percpu.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-)mm/percpu.c +18
-19@@ -121,35 +121,35 @@ struct pcpu_chunk {unsigned long populated[];/* populated bitmap */ }; -static int pcpu_unit_pages__read_mostly ; -static int pcpu_unit_size__read_mostly ; -static int pcpu_nr_units__read_mostly ; -static int pcpu_atom_size__read_mostly ; -static int pcpu_nr_slots__read_mostly ; -static size_t pcpu_chunk_struct_size__read_mostly ; +static int pcpu_unit_pages__ro_after_init ; +static int pcpu_unit_size__ro_after_init ; +static int pcpu_nr_units__ro_after_init ; +static int pcpu_atom_size__ro_after_init ; +static int pcpu_nr_slots__ro_after_init ; +static size_t pcpu_chunk_struct_size__ro_after_init ;/* cpus with the lowest and highest unit addresses */ -static unsigned int pcpu_low_unit_cpu__read_mostly ; -static unsigned int pcpu_high_unit_cpu__read_mostly ; +static unsigned int pcpu_low_unit_cpu__ro_after_init ; +static unsigned int pcpu_high_unit_cpu__ro_after_init ;/* the address of the first chunk which starts with the kernel static area */ -void *pcpu_base_addr__read_mostly ; +void *pcpu_base_addr__ro_after_init ;EXPORT_SYMBOL_GPL (pcpu_base_addr); -static const int *pcpu_unit_map__read_mostly ;/* cpu -> unit */ -const unsigned long *pcpu_unit_offsets__read_mostly ;/* cpu -> unit offset */ +static const int *pcpu_unit_map__ro_after_init ;/* cpu -> unit */ +const unsigned long *pcpu_unit_offsets__ro_after_init ;/* cpu -> unit offset */ /* group information, used for vm allocation */ -static int pcpu_nr_groups__read_mostly ; -static const unsigned long *pcpu_group_offsets__read_mostly ; -static const size_t *pcpu_group_sizes__read_mostly ; +static int pcpu_nr_groups__ro_after_init ; +static const unsigned long *pcpu_group_offsets__ro_after_init ; +static const size_t *pcpu_group_sizes__ro_after_init ;/* * The first chunk which always exists. Note that unlike other * chunks, this one can be allocated and mapped in several different * ways and thus often doesn't live in the vmalloc area. */ -static struct pcpu_chunk *pcpu_first_chunk; +static struct pcpu_chunk *pcpu_first_chunk__ro_after_init ;/* * Optional reserved chunk. This chunk reserves part of the first @@ -158,13 +158,13 @@ static struct pcpu_chunk *pcpu_first_chunk;* area doesn't exist, the following variables contain NULL and 0 * respectively. */ -static struct pcpu_chunk *pcpu_reserved_chunk; -static int pcpu_reserved_chunk_limit; +static struct pcpu_chunk *pcpu_reserved_chunk__ro_after_init ; +static int pcpu_reserved_chunk_limit__ro_after_init ;static DEFINE_SPINLOCK (pcpu_lock);/* all internal data structures */ static DEFINE_MUTEX (pcpu_alloc_mutex);/* chunk create/destroy, [de]pop, map ext */ -static struct list_head *pcpu_slot__read_mostly ;/* chunk list slots */ +static struct list_head *pcpu_slot__ro_after_init ;/* chunk list slots */ /* chunks which need their map areas extended, protected by pcpu_lock */ static LIST_HEAD (pcpu_map_extend_chunks); --2.12.2
Signature · 2 lines
Kees Cook Pixel Security