Hello Igor,
+/*
+ * The following two variables are statically allocated by the linker
+ * script at the the boundaries of the memory region (rounded up to
+ * multiples of PAGE_SIZE) reserved for __wr_after_init.
+ */
+extern long __start_wr_after_init;
+extern long __end_wr_after_init;
+
+static inline bool is_wr_after_init(unsigned long ptr, __kernel_size_t size)
+{
+ unsigned long start = (unsigned long)&__start_wr_after_init;
+ unsigned long end = (unsigned long)&__end_wr_after_init;
+ unsigned long low = ptr;
+ unsigned long high = ptr + size;
+
+ return likely(start <= low && low <= high && high <= end);
+}
+
+void *__wr_op(unsigned long dst, unsigned long src, __kernel_size_t len,
+ enum wr_op_type op)
+{
+ temporary_mm_state_t prev;
+ unsigned long offset;
+ unsigned long wr_poking_addr;
+
+ /* Confirm that the writable mapping exists. */
+ if (WARN_ONCE(!wr_ready, "No writable mapping available"))
+ return (void *)dst;
+
+ if (WARN_ONCE(op >= WR_OPS_NUMBER, "Invalid WR operation.") ||
+ WARN_ONCE(!is_wr_after_init(dst, len), "Invalid WR range."))
+ return (void *)dst;
+
+ offset = dst - (unsigned long)&__start_wr_after_init;
+ wr_poking_addr = wr_poking_base + offset;
+ local_irq_disable();
+ prev = use_temporary_mm(wr_poking_mm);
+
+ if (op == WR_MEMCPY)
+ copy_to_user((void __user *)wr_poking_addr, (void *)src, len);
+ else if (op == WR_MEMSET)
+ memset_user((void __user *)wr_poking_addr, (u8)src, len);
+
+ unuse_temporary_mm(prev);
+ local_irq_enable();
+ return (void *)dst;
+}
There's a lot of casting back and forth between unsigned long and void *
(also in the previous patch). Is there a reason for that?
My impression
is that there would be less casts if variables holding addresses were
declared as void * in the first place.
In that case, it wouldn't hurt to
have an additional argument in __rw_op() to carry the byte value for the
WR_MEMSET operation.
+
+#define TB (1UL << 40)
+
+struct mm_struct *copy_init_mm(void);
+void __init wr_poking_init(void)
+{
+ unsigned long start = (unsigned long)&__start_wr_after_init;
+ unsigned long end = (unsigned long)&__end_wr_after_init;
+ unsigned long i;
+ unsigned long wr_range;
+
+ wr_poking_mm = copy_init_mm();
+ if (WARN_ONCE(!wr_poking_mm, "No alternate mapping available."))
+ return;
+
+ wr_range = round_up(end - start, PAGE_SIZE);
+
+ /* Randomize the poking address base*/
+ wr_poking_base = TASK_UNMAPPED_BASE +
+ (kaslr_get_random_long("Write Rare Poking") & PAGE_MASK) %
+ (TASK_SIZE - (TASK_UNMAPPED_BASE + wr_range));
+
+ /*
+ * Place 64TB of kernel address space within 128TB of user address
+ * space, at a random page aligned offset.
+ */
+ wr_poking_base = (((unsigned long)kaslr_get_random_long("WR Poke")) &
+ PAGE_MASK) % (64 * _BITUL(40));
You're setting wr_poking_base twice in a row? Is this an artifact from
rebase?