These helpers mirror override_creds/revert_creds and are supposed to be used together in cases when VE creds may be stored and later used by the different VE task.
To keep task_ve consistent for other users, introduce a separate task->overrided_ve field. Nobody should race on it since its updates are supposed to go with override_creds, and non-current processes shouldn't do this. This field is not supposed to be inherited via fork, so report a check for this was added as well. https://virtuozzo.atlassian.net/browse/VSTOR-142405 Signed-off-by: Vladimir Riabchun <[email protected]> --- include/linux/sched.h | 1 + include/linux/ve.h | 27 +++++++++++++++++++++++++++ kernel/capability.c | 6 ++++-- kernel/fork.c | 2 ++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 10545e470d3d..7f4e6b1fde38 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1065,6 +1065,7 @@ struct task_struct { #ifdef CONFIG_VE struct ve_struct *task_ve; struct ve_namespace *ve_ns; + struct ve_struct *overrided_ve; /* NULL when no overrides */ #endif #ifdef CONFIG_PREEMPT_RT struct netdev_xmit net_xmit; diff --git a/include/linux/ve.h b/include/linux/ve.h index 717567775f58..fb8a4cabb951 100644 --- a/include/linux/ve.h +++ b/include/linux/ve.h @@ -295,6 +295,26 @@ static inline struct vdso_image *ve_get_vdso_64(struct ve_struct *ve) return ve->vdso_64; } +static inline struct ve_struct *override_ve(struct ve_struct *new_ve) +{ + struct ve_struct *old_ve = current->overrided_ve; + + /* CT tasks are not supposed to switch VE context, this is a breach */ + if (WARN_ON(new_ve != get_exec_env() && !ve_is_super(get_exec_env()))) + return ERR_PTR(-EPERM); + + current->overrided_ve = new_ve; + return old_ve; +} + +static inline void revert_ve(struct ve_struct *orig_ve) +{ + /* Somebody forgot to check override_ve return value? */ + if (WARN_ON(IS_ERR(orig_ve))) + return; + current->overrided_ve = orig_ve; +} + #else /* CONFIG_VE */ #include <linux/init_task.h> #include <net/net_namespace.h> @@ -405,6 +425,13 @@ static inline struct vdso_image *ve_get_vdso_64(struct ve_struct *ve) } #endif /* CONFIG_X86 */ +static inline struct ve_struct *override_ve(struct ve_struct *new_ve) +{ + return NULL; +} + +static inline void revert_ve(struct ve_struct *orig_ve) {} + #endif /* CONFIG_VE */ struct seq_file; diff --git a/kernel/capability.c b/kernel/capability.c index 34716847c6b8..6de4dcba2283 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -389,10 +389,11 @@ EXPORT_SYMBOL(ns_capable); bool ve_capable(int cap) { struct cred *cred; + struct ve_struct *ve = current->overrided_ve ?: get_exec_env(); bool ret; rcu_read_lock(); - cred = get_exec_env()->init_cred; + cred = ve->init_cred; if (cred == NULL) /* ve isn't running */ cred = ve0.init_cred; @@ -406,10 +407,11 @@ bool ve_capable(int cap) bool ve_capable_noaudit(int cap) { struct cred *cred; + struct ve_struct *ve = current->overrided_ve ?: get_exec_env(); bool ret; rcu_read_lock(); - cred = get_exec_env()->init_cred; + cred = ve->init_cred; if (cred == NULL) /* ve isn't running */ cred = ve0.init_cred; diff --git a/kernel/fork.c b/kernel/fork.c index 25e87cdbeb07..0cb8ccb2f4f3 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1161,6 +1161,8 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node) #ifdef CONFIG_VE memset(tsk->alloc_lat, 0, sizeof(tsk->alloc_lat)); + WARN_ON(orig->overrided_ve); + tsk->overrided_ve = NULL; #endif /* -- 2.52.0 _______________________________________________ Devel mailing list [email protected] https://lists.openvz.org/mailman/listinfo/devel
