diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h index 5700451b300fb514f782d2631a54a0ce90ef3655..b5084e655ddc9db7072acc7c776541afdccf115f 100644 --- a/include/linux/fwnode.h +++ b/include/linux/fwnode.h @@ -13,6 +13,7 @@ #include #include #include +#include struct fwnode_operations; struct device; @@ -45,6 +46,8 @@ struct fwnode_handle { struct list_head suppliers; struct list_head consumers; u8 flags; + KABI_RESERVE(1) + KABI_RESERVE(2) }; /* @@ -164,6 +167,10 @@ struct fwnode_operations { void __iomem *(*iomap)(struct fwnode_handle *fwnode, int index); int (*irq_get)(const struct fwnode_handle *fwnode, unsigned int index); int (*add_links)(struct fwnode_handle *fwnode); + KABI_RESERVE(1) + KABI_RESERVE(2) + KABI_RESERVE(3) + KABI_RESERVE(4) }; #define fwnode_has_op(fwnode, op) \ diff --git a/include/linux/module.h b/include/linux/module.h index c6ee29331e87d078d64be29c3dd01d6ec27ac19f..4db2878d9e422a240cab075314e9341ca496a44f 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -602,6 +602,10 @@ struct module { #ifdef CONFIG_DYNAMIC_DEBUG_CORE struct _ddebug_info dyndbg_info; #endif + KABI_RESERVE(1) + KABI_RESERVE(2) + KABI_RESERVE(3) + KABI_RESERVE(4) } ____cacheline_aligned __randomize_layout; #ifndef MODULE_ARCH_INIT #define MODULE_ARCH_INIT {} diff --git a/include/linux/sched.h b/include/linux/sched.h index 4f18d450561881bfbc193b3be9e18d5f8ab17137..0c7ece3af645b20096bf94688c20f76596ec3715 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -39,6 +39,7 @@ #include #include #include +#include /* task_struct member predeclarations (sorted alphabetically): */ struct audit_context; @@ -595,6 +596,10 @@ struct sched_entity { */ struct sched_avg avg; #endif + KABI_RESERVE(1) + KABI_RESERVE(2) + KABI_RESERVE(3) + KABI_RESERVE(4) }; struct sched_rt_entity { @@ -613,6 +618,8 @@ struct sched_rt_entity { /* rq "owned" by this entity/group: */ struct rt_rq *my_q; #endif + KABI_RESERVE(1) + KABI_RESERVE(2) } __randomize_layout; struct sched_dl_entity { @@ -751,6 +758,11 @@ struct kmap_ctrl { #endif }; +struct task_struct_resvd { + /* pointer back to the main task_struct */ + struct task_struct *task; +}; + struct task_struct { #ifdef CONFIG_THREAD_INFO_IN_TASK /* @@ -1570,6 +1582,24 @@ struct task_struct { */ randomized_struct_fields_end + KABI_RESERVE(1) + KABI_RESERVE(2) + KABI_RESERVE(3) + KABI_RESERVE(4) + KABI_RESERVE(5) + KABI_RESERVE(6) + KABI_RESERVE(7) + KABI_RESERVE(8) + KABI_RESERVE(9) + KABI_RESERVE(10) + KABI_RESERVE(11) + KABI_RESERVE(12) + KABI_RESERVE(13) + KABI_RESERVE(14) + KABI_RESERVE(15) + KABI_RESERVE(16) + KABI_AUX_PTR(task_struct) + /* CPU-specific state of this task: */ struct thread_struct thread; diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h index 0014d3adaf8460b03b4ad2e4ccaf97b17b7a8884..75e71a0ce2d15082b7721180c4bbbd92d52942ea 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h @@ -12,6 +12,7 @@ #include #include #include +#include /* * Types defining task->signal and task->sighand and APIs using them: @@ -245,6 +246,10 @@ struct signal_struct { * and may have inconsistent * permissions. */ + KABI_RESERVE(1) + KABI_RESERVE(2) + KABI_RESERVE(3) + KABI_RESERVE(4) } __randomize_layout; /* diff --git a/init/init_task.c b/init/init_task.c index 2101c6e3432d23d2db222aee7f510d5c9a820ae1..ee1cdf5735e17da1bed6a9add500a072318c3ebb 100644 --- a/init/init_task.c +++ b/init/init_task.c @@ -57,6 +57,10 @@ unsigned long init_shadow_call_stack[SCS_SIZE / sizeof(long)] }; #endif +static struct task_struct_resvd init_task_struct_resvd = { + .task = &init_task, +}; + /* * Set up the first task table, touch at your own risk!. Base=0, * limit=0x1fffff (=2MB) @@ -216,6 +220,7 @@ struct task_struct init_task #ifdef CONFIG_BPF_SCHED .tag = 0, #endif + ._resvd = &init_task_struct_resvd, }; EXPORT_SYMBOL(init_task); diff --git a/kernel/fork.c b/kernel/fork.c index fd0405523f07f5ee8d4b5eba6716fad6dcce44f4..00e5886c9e04cdab995e22b7a0e63c3435308319 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -179,6 +179,7 @@ static inline struct task_struct *alloc_task_struct_node(int node) static inline void free_task_struct(struct task_struct *tsk) { + kfree(tsk->_resvd); kmem_cache_free(task_struct_cachep, tsk); } #endif @@ -1112,6 +1113,18 @@ void set_task_stack_end_magic(struct task_struct *tsk) *stackend = STACK_END_MAGIC; /* for overflow detection */ } +static bool dup_resvd_task_struct(struct task_struct *dst, + struct task_struct *orig, int node) +{ + dst->_resvd = kzalloc_node(sizeof(struct task_struct_resvd), + GFP_KERNEL, node); + if (!dst->_resvd) + return false; + + dst->_resvd->task = dst; + return true; +} + static struct task_struct *dup_task_struct(struct task_struct *orig, int node) { struct task_struct *tsk; @@ -1122,9 +1135,15 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node) tsk = alloc_task_struct_node(node); if (!tsk) return NULL; + /* + * before proceeding, we need to make tsk->_resvd = NULL, + * otherwise the error paths below, if taken, might end up causing + * a double-free for task_struct_resvd extension object. + */ + WRITE_ONCE(tsk->_resvd, NULL); err = arch_dup_task_struct(tsk, orig); - if (err) + if (err || !dup_resvd_task_struct(tsk, orig, node)) goto free_tsk; err = alloc_thread_stack_node(tsk, node); diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 88dbcbe3d7c1edf4a9ffcf6c35feda407570c383..189fd23c2d259fffc2baf2b222b7165afe315b01 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -285,6 +285,8 @@ struct rt_bandwidth { u64 rt_runtime; struct hrtimer rt_period_timer; unsigned int rt_period_active; + KABI_RESERVE(1) + KABI_RESERVE(2) }; void __dl_clear_params(struct task_struct *p); @@ -360,6 +362,14 @@ struct cfs_bandwidth { u64 throttled_time; u64 burst_time; #endif + KABI_RESERVE(1) + KABI_RESERVE(2) + KABI_RESERVE(3) + KABI_RESERVE(4) + KABI_RESERVE(5) + KABI_RESERVE(6) + KABI_RESERVE(7) + KABI_RESERVE(8) }; @@ -721,7 +731,14 @@ struct cfs_rq { unsigned long qos_idle_h_nr_running_padding; }; #endif - + KABI_RESERVE(1) + KABI_RESERVE(2) + KABI_RESERVE(3) + KABI_RESERVE(4) + KABI_RESERVE(5) + KABI_RESERVE(6) + KABI_RESERVE(7) + KABI_RESERVE(8) }; static inline int rt_bandwidth_enabled(void) @@ -768,6 +785,8 @@ struct rt_rq { struct rq *rq; struct task_group *tg; #endif + KABI_RESERVE(1) + KABI_RESERVE(2) }; static inline bool rt_rq_is_runnable(struct rt_rq *rt_rq) @@ -962,6 +981,8 @@ struct root_domain { * CPUs of the rd. Protected by RCU. */ struct perf_domain __rcu *pd; + KABI_RESERVE(1) + KABI_RESERVE(2) }; extern void init_defrootdomain(void); @@ -1256,6 +1277,14 @@ struct rq { call_single_data_t cfsb_csd; struct list_head cfsb_csd_list; #endif + KABI_RESERVE(1) + KABI_RESERVE(2) + KABI_RESERVE(3) + KABI_RESERVE(4) + KABI_RESERVE(5) + KABI_RESERVE(6) + KABI_RESERVE(7) + KABI_RESERVE(8) }; #ifdef CONFIG_FAIR_GROUP_SCHED @@ -2021,6 +2050,8 @@ struct sched_group { struct sched_group_capacity *sgc; int asym_prefer_cpu; /* CPU of highest priority in group */ int flags; + KABI_RESERVE(1) + KABI_RESERVE(2) /* * The CPUs this group covers. @@ -2404,6 +2435,8 @@ struct sched_class { #ifdef CONFIG_SCHED_CORE int (*task_is_throttled)(struct task_struct *p, int cpu); #endif + KABI_RESERVE(1) + KABI_RESERVE(2) }; static inline void put_prev_task(struct rq *rq, struct task_struct *prev)