public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Oleg Nesterov <oleg@redhat.com>
To: David Howells <dhowells@redhat.com>
Cc: Andrew Morton <akpm@linux-foundation.org>,
	Linus Torvalds <torvalds@linux-foundation.org>,
	David Smith <dsmith@redhat.com>,
	"Frank Ch. Eigler" <fche@redhat.com>,
	Larry Woodman <lwoodman@redhat.com>,
	Peter Zijlstra <peterz@infradead.org>, Tejun Heo <tj@kernel.org>,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 2/2] cred: change keyctl_session_to_parent() to use task_work_queue()
Date: Thu, 12 Apr 2012 19:34:03 +0200	[thread overview]
Message-ID: <20120412173403.GA24541@redhat.com> (raw)
In-Reply-To: <9202.1334222995@redhat.com>

On 04/12, David Howells wrote:
>
> Oleg Nesterov <oleg@redhat.com> wrote:
>
> > Change keyctl_session_to_parent() to use task_work_queue() and
> > move key_replace_session_keyring() logic into task_work->func().
>
> I'm generally okay with this, but there are a couple of issues with the patch.

Great, thanks.

I'll send v3 soon. I'll also update 1/2 a little bit and add the
3rd patch with the new user of task_work.

> > +static void replace_session_keyring(struct task_work *twork)
>
> Can you keep this in process_keys.c please?  Then everything that actually
> updates a process's keyrings is done there.  Admittedly, on that basis, you
> can argue that I should move a chunk of keyctl_session_to_parent() there too.

Sure. But then I need to export it in internal.h.

> And, also, can you please keep the "key_" on the front of the name?

Oh, yes, just I do not know how to name it.

The obviously good name is the old name, but until we remove the
->replacement_session_keyring code from arch/* we can't use it.

OK, how about key_change_session_keyring() ?

> >  long keyctl_session_to_parent(void)
> >  {
> > -#ifdef TIF_NOTIFY_RESUME
>
> Unless TIF_NOTIFY_RESUME is defined, this operation cannot be performed and
> should generate an error.  I don't see how this happens now.

Yes, see below. I forgot about -EOPNOTSUPP.

> > +	if (!task_work_queue(parent, newwork))
>
> I hate this type of construct.  "if not function()" indicating the function
> succeeded.  Can you make it "== 0" instead?

Agreed. Even better, we can rename "int ret" to "int err" and do

	err = task_work_queue();
	if (!err)
		...;

this also allows us to kill already_same/not_permitted error paths.

> Also, shouldn't we tell the user
> that it failed?

>From the changelog:

	We do not report the error if we race with the exiting parent
	and task_work_queue() fails, this matches the current behaviour.

Yes. task_work_queue() can only fail if it races with the exiting
parent. The window before it calls exit_notify() is small, and this
doesn't differ from the case when the parent does do_exit() right
after we queue the work.

But! As you pointed out, I forgot about TIF_NOTIFY_RESUME problems,
so lets report the error.

Thanks. Before I re-check and send v3, perhaps you can look at the
updated keyctl_session_to_parent() below.

Oleg.


long keyctl_session_to_parent(void)
{
	struct task_struct *me, *parent;
	const struct cred *mycred, *pcred;
	struct task_work *newwork, *oldwork;
	key_ref_t keyring_r;
	struct cred *cred;
	int err;

	keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK);
	if (IS_ERR(keyring_r))
		return PTR_ERR(keyring_r);

	err = -ENOMEM;
	newwork = kmalloc(sizeof(struct task_work), GFP_KERNEL);
	if (!newwork)
		goto error_keyring;

	/* our parent is going to need a new cred struct, a new tgcred struct
	 * and new security data, so we allocate them here to prevent ENOMEM in
	 * our parent */
	cred = cred_alloc_blank();
	if (!cred)
		goto error_keyring;

	cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r);
	init_task_work(newwork, replace_session_keyring, cred);

	me = current;
	rcu_read_lock();
	write_lock_irq(&tasklist_lock);

	err = -EPERM;
	oldwork = NULL;
	parent = me->real_parent;

	/* the parent mustn't be init and mustn't be a kernel thread */
	if (parent->pid <= 1 || !parent->mm)
		goto unlock;

	/* the parent must be single threaded */
	if (!thread_group_empty(parent))
		goto unlock;

	/* the parent and the child must have different session keyrings or
	 * there's no point */
	mycred = current_cred();
	pcred = __task_cred(parent);
	if (mycred == pcred ||
	    mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) {
	    	err = 0;
		goto unlock;
	}

	/* the parent must have the same effective ownership and mustn't be
	 * SUID/SGID */
	if (pcred->uid	!= mycred->euid	||
	    pcred->euid	!= mycred->euid	||
	    pcred->suid	!= mycred->euid	||
	    pcred->gid	!= mycred->egid	||
	    pcred->egid	!= mycred->egid	||
	    pcred->sgid	!= mycred->egid)
		goto unlock;

	/* the keyrings must have the same UID */
	if ((pcred->tgcred->session_keyring &&
	     pcred->tgcred->session_keyring->uid != mycred->euid) ||
	    mycred->tgcred->session_keyring->uid != mycred->euid)
		goto unlock;

	/* cancel an already pending keyring replacement */
	oldwork = task_work_cancel(parent, replace_session_keyring);

	/* the replacement session keyring is applied just prior to userspace
	 * restarting */
	err = task_work_queue(parent, newwork);
	if (!err)
		newwork = NULL;
 unlock:
	write_unlock_irq(&tasklist_lock);
	rcu_read_unlock();
	free_cred_work(oldwork);
	free_cred_work(newwork);
	return err;

error_keyring:
	kfree(newwork);
	key_ref_put(keyring_r);
	return err;
}


      reply	other threads:[~2012-04-12 17:34 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-04-12  2:47 [PATCH v2 0/2] task_work_queue() && keyctl_session_to_parent() Oleg Nesterov
2012-04-12  2:48 ` [PATCH v2 1/2] task_work_queue: add generic process-context callbacks Oleg Nesterov
2012-04-12  4:00   ` hlist_for_each_entry && pos (Was: task_work_queue) Oleg Nesterov
2012-04-12  4:12     ` Linus Torvalds
2012-04-12  4:28       ` Oleg Nesterov
2012-04-12  4:39         ` Linus Torvalds
2012-04-12  5:02           ` Al Viro
2012-04-16 22:35     ` Paul E. McKenney
2012-04-17 20:43       ` Oleg Nesterov
2012-04-12  9:35   ` TIF_NOTIFY_RESUME [was Re: [PATCH v2 1/2] task_work_queue: add generic process-context callbacks] David Howells
2012-04-12 17:41     ` Oleg Nesterov
2012-04-12  2:48 ` [PATCH v2 2/2] cred: change keyctl_session_to_parent() to use task_work_queue() Oleg Nesterov
2012-04-12  9:29   ` David Howells
2012-04-12 17:34     ` Oleg Nesterov [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120412173403.GA24541@redhat.com \
    --to=oleg@redhat.com \
    --cc=akpm@linux-foundation.org \
    --cc=dhowells@redhat.com \
    --cc=dsmith@redhat.com \
    --cc=fche@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lwoodman@redhat.com \
    --cc=peterz@infradead.org \
    --cc=tj@kernel.org \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox