James, would you pick up this patch?
Tetsuo Handa wrote: > James, please apply. > > Kevin, does "cause OOM" mean something like the OOM killer or kmalloc() > failure > is triggerred by frequent prctl() requests by userspace applications? > If yes, we should backport to stable as this affects any 2.6.29 and later > kernels. > -------------------- > From 1cb92c00bd1529f5d16a3f13c09f2bd6b6f7c6ca Mon Sep 17 00:00:00 2001 > From: Tetsuo Handa <penguin-ker...@i-love.sakura.ne.jp> > Date: Thu, 19 Dec 2013 06:23:04 +0900 > Subject: [PATCH] commoncap: don't alloc the credential unless needed in > cap_task_prctl > > In function cap_task_prctl(), we would allocate a credential > unconditionally and then check if we support the requested function. > If not we would release this credential with abort_creds() by using > RCU method. But on some archs such as powerpc, the sys_prctl is heavily > used to get/set the floating point exception mode. So the unnecessary > allocating/releasing of credential not only introduce runtime overhead > but also do cause OOM due to the RCU implementation. > > This patch removes abort_creds() from cap_task_prctl() by calling > prepare_creds() only when we need to modify it. > > Reported-by: Kevin Hao <haoke...@gmail.com> > Signed-off-by: Tetsuo Handa <penguin-ker...@i-love.sakura.ne.jp> > Acked-by: Serge E. Hallyn <serge.hal...@ubuntu.com> > --- > security/commoncap.c | 134 +++++++++++++++++++++++++------------------------ > 1 files changed, 68 insertions(+), 66 deletions(-) > > diff --git a/security/commoncap.c b/security/commoncap.c > index b9d613e..2b62f44 100644 > --- a/security/commoncap.c > +++ b/security/commoncap.c > @@ -818,19 +818,75 @@ int cap_task_setnice(struct task_struct *p, int nice) > return cap_safe_nice(p); > } > > +static int cap_prctl_read(const struct cred *old, unsigned long arg2) > +{ > + if (!cap_valid(arg2)) > + return -EINVAL; > + return !!cap_raised(old->cap_bset, arg2); > +} > + > /* > * Implement PR_CAPBSET_DROP. Attempt to remove the specified capability > from > * the current task's bounding set. Returns 0 on success, -ve on error. > */ > -static long cap_prctl_drop(struct cred *new, unsigned long cap) > +static int cap_prctl_drop(const struct cred *old, unsigned long cap) > { > - if (!ns_capable(current_user_ns(), CAP_SETPCAP)) > + struct cred *new; > + > + if (!ns_capable(old->user_ns, CAP_SETPCAP)) > return -EPERM; > if (!cap_valid(cap)) > return -EINVAL; > - > + new = prepare_creds(); > + if (!new) > + return -ENOMEM; > cap_lower(new->cap_bset, cap); > - return 0; > + return commit_creds(new); > +} > + > +static int cap_prctl_securebits(const struct cred *old, unsigned long arg2) > +{ > + struct cred *new; > + > + if ((((old->securebits & SECURE_ALL_LOCKS) >> 1) > + & (old->securebits ^ arg2)) /*[1]*/ > + || ((old->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ > + || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ > + || (cap_capable(old, old->user_ns, CAP_SETPCAP, > + SECURITY_CAP_AUDIT) != 0) /*[4]*/ > + /* > + * [1] no changing of bits that are locked > + * [2] no unlocking of locks > + * [3] no setting of unsupported bits > + * [4] doing anything requires privilege (go read about > + * the "sendmail capabilities bug") > + */ > + ) > + /* cannot change a locked bit */ > + return -EPERM; > + new = prepare_creds(); > + if (!new) > + return -ENOMEM; > + new->securebits = arg2; > + return commit_creds(new); > +} > + > +static int cap_prctl_keepcaps(unsigned long arg2) > +{ > + struct cred *new; > + > + if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */ > + return -EINVAL; > + if (issecure(SECURE_KEEP_CAPS_LOCKED)) > + return -EPERM; > + new = prepare_creds(); > + if (!new) > + return -ENOMEM; > + if (arg2) > + new->securebits |= issecure_mask(SECURE_KEEP_CAPS); > + else > + new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); > + return commit_creds(new); > } > > /** > @@ -848,26 +904,14 @@ static long cap_prctl_drop(struct cred *new, unsigned > long cap) > int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, > unsigned long arg4, unsigned long arg5) > { > - struct cred *new; > - long error = 0; > - > - new = prepare_creds(); > - if (!new) > - return -ENOMEM; > + const struct cred *old = current_cred(); > > switch (option) { > case PR_CAPBSET_READ: > - error = -EINVAL; > - if (!cap_valid(arg2)) > - goto error; > - error = !!cap_raised(new->cap_bset, arg2); > - goto no_change; > + return cap_prctl_read(old, arg2); > > case PR_CAPBSET_DROP: > - error = cap_prctl_drop(new, arg2); > - if (error < 0) > - goto error; > - goto changed; > + return cap_prctl_drop(old, arg2); > > /* > * The next four prctl's remain to assist with transitioning a > @@ -889,63 +933,21 @@ int cap_task_prctl(int option, unsigned long arg2, > unsigned long arg3, > * capability-based-privilege environment. > */ > case PR_SET_SECUREBITS: > - error = -EPERM; > - if ((((new->securebits & SECURE_ALL_LOCKS) >> 1) > - & (new->securebits ^ arg2)) /*[1]*/ > - || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ > - || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ > - || (cap_capable(current_cred(), > - current_cred()->user_ns, CAP_SETPCAP, > - SECURITY_CAP_AUDIT) != 0) /*[4]*/ > - /* > - * [1] no changing of bits that are locked > - * [2] no unlocking of locks > - * [3] no setting of unsupported bits > - * [4] doing anything requires privilege (go read about > - * the "sendmail capabilities bug") > - */ > - ) > - /* cannot change a locked bit */ > - goto error; > - new->securebits = arg2; > - goto changed; > + return cap_prctl_securebits(old, arg2); > > case PR_GET_SECUREBITS: > - error = new->securebits; > - goto no_change; > + return old->securebits; > > case PR_GET_KEEPCAPS: > - if (issecure(SECURE_KEEP_CAPS)) > - error = 1; > - goto no_change; > + return !!issecure(SECURE_KEEP_CAPS); > > case PR_SET_KEEPCAPS: > - error = -EINVAL; > - if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */ > - goto error; > - error = -EPERM; > - if (issecure(SECURE_KEEP_CAPS_LOCKED)) > - goto error; > - if (arg2) > - new->securebits |= issecure_mask(SECURE_KEEP_CAPS); > - else > - new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); > - goto changed; > + return cap_prctl_keepcaps(arg2); > > default: > /* No functionality available - continue with default */ > - error = -ENOSYS; > - goto error; > + return -ENOSYS; > } > - > - /* Functionality provided */ > -changed: > - return commit_creds(new); > - > -no_change: > -error: > - abort_creds(new); > - return error; > } > > /** > -- > 1.7.1 > -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/