From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751857AbbHLSqU (ORCPT ); Wed, 12 Aug 2015 14:46:20 -0400 Received: from out03.mta.xmission.com ([166.70.13.233]:46579 "EHLO out03.mta.xmission.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751773AbbHLSqS (ORCPT ); Wed, 12 Aug 2015 14:46:18 -0400 From: ebiederm@xmission.com (Eric W. Biederman) To: Oleg Nesterov Cc: "Kirill A. Shutemov" , Andrew Morton , Kees Cook , David Howells , linux-kernel@vger.kernel.org, Peter Zijlstra , Ingo Molnar , "Kirill A. Shutemov" , Rik van Riel , Vladimir Davydov , Ricky Zhou , Julien Tinnes In-Reply-To: <20150812174847.GA6703@redhat.com> (Oleg Nesterov's message of "Wed, 12 Aug 2015 19:48:47 +0200") References: <20150728171500.GA2871@www.outflux.net> <20150728143504.5aa996ba5955522a19c2d5f1@linux-foundation.org> <20150728221111.GA23391@node.dhcp.inet.fi> <20150805172356.GA20490@redhat.com> <87wpx9sjhq.fsf@x220.int.ebiederm.org> <87614tr2jd.fsf@x220.int.ebiederm.org> <20150806130629.GA4728@redhat.com> <20150806134426.GA6843@redhat.com> <871tf9cnbi.fsf_-_@x220.int.ebiederm.org> <87vbclb8op.fsf_-_@x220.int.ebiederm.org> <20150812174847.GA6703@redhat.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3 (gnu/linux) Date: Wed, 12 Aug 2015 13:39:27 -0500 Message-ID: <87614k73mo.fsf@x220.int.ebiederm.org> MIME-Version: 1.0 Content-Type: text/plain X-XM-AID: U2FsdGVkX18dFthyDqSbN38wFVA1hNDqCNcOdKDWzEQ= X-SA-Exim-Connect-IP: 67.3.205.173 X-SA-Exim-Mail-From: ebiederm@xmission.com X-Spam-Report: * -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP * 0.7 XMSubLong Long Subject * 1.5 XMNoVowels Alpha-numberic number with no vowels * 0.0 TVD_RCVD_IP Message was received from an IP address * 0.0 T_TM2_M_HEADER_IN_MSG BODY: No description available. * 0.8 BAYES_50 BODY: Bayes spam probability is 40 to 60% * [score: 0.5000] * -0.0 DCC_CHECK_NEGATIVE Not listed in DCC * [sa04 1397; Body=1 Fuz1=1 Fuz2=1] X-Spam-DCC: XMission; sa04 1397; Body=1 Fuz1=1 Fuz2=1 X-Spam-Combo: **;Oleg Nesterov X-Spam-Relay-Country: X-Spam-Timing: total 677 ms - load_scoreonly_sql: 0.07 (0.0%), signal_user_changed: 4.6 (0.7%), b_tie_ro: 3.1 (0.5%), parse: 1.47 (0.2%), extract_message_metadata: 4.0 (0.6%), get_uri_detail_list: 2.4 (0.4%), tests_pri_-1000: 3.8 (0.6%), tests_pri_-950: 1.17 (0.2%), tests_pri_-900: 0.96 (0.1%), tests_pri_-400: 25 (3.7%), check_bayes: 24 (3.6%), b_tokenize: 8 (1.2%), b_tok_get_all: 8 (1.2%), b_comp_prob: 2.4 (0.4%), b_tok_touch_all: 3.2 (0.5%), b_finish: 0.72 (0.1%), tests_pri_0: 620 (91.5%), tests_pri_500: 6 (0.9%), rewrite_mail: 0.00 (0.0%) Subject: Re: [PATCH 1/2] unshare: Unsharing a thread does not require unsharing a vm X-Spam-Flag: No X-SA-Exim-Version: 4.2.1 (built Wed, 24 Sep 2014 11:00:52 -0600) X-SA-Exim-Scanned: Yes (on in02.mta.xmission.com) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Oleg Nesterov writes: > On 08/11, Eric W. Biederman wrote: >> >> --- a/kernel/fork.c >> +++ b/kernel/fork.c >> @@ -1866,13 +1866,17 @@ static int check_unshare_flags(unsigned long unshare_flags) >> CLONE_NEWUSER|CLONE_NEWPID)) >> return -EINVAL; >> /* >> - * Not implemented, but pretend it works if there is nothing to >> - * unshare. Note that unsharing CLONE_THREAD or CLONE_SIGHAND >> - * needs to unshare vm. >> + * Not implemented, but pretend it works if there is nothing >> + * to unshare. Note that unsharing the address space or the >> + * signal handlers also need to unshare the signal queues (aka >> + * CLONE_THREAD). >> */ >> if (unshare_flags & (CLONE_THREAD | CLONE_SIGHAND | CLONE_VM)) { >> - /* FIXME: get_task_mm() increments ->mm_users */ >> - if (atomic_read(¤t->mm->mm_users) > 1) >> + if (!thread_group_empty(current)) >> + return -EINVAL; >> + } >> + if (unshare_flags & CLONE_VM) { >> + if (!current_is_single_threaded()) >> return -EINVAL; >> } > > OK, but then you can remove "| CLONE_VM" from the previous check... As an optimization, but I don't think anything cares enough for the optimization to be worth the confusion. >> @@ -1941,16 +1945,16 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags) >> if (unshare_flags & CLONE_NEWUSER) >> unshare_flags |= CLONE_THREAD | CLONE_FS; >> /* >> - * If unsharing a thread from a thread group, must also unshare vm. >> - */ >> - if (unshare_flags & CLONE_THREAD) >> - unshare_flags |= CLONE_VM; > > OK, > >> /* >> + * If unsharing a signal handlers, must also unshare the signal queues. >> + */ >> + if (unshare_flags & CLONE_SIGHAND) >> + unshare_flags |= CLONE_THREAD; > > This looks unnecessary, check_unshare_flags() checks "THREAD | SIGHAND". > And to me the comment looks misleading although I won't argue. I absolutely can not understand this code if we jump 5 steps ahead and optimize out the individual dependencies, and try for a flattened dependency tree instead. I can validate the individual dependencies from first principles. If we jump several steps ahead I can not validate the individual dependencies. It really is important to say if you want your own private struct sighand_struct, you also need to have your own private struct signal_struct. > And in fact this doesn't look exactly right, or I am totally confused. > Shouldn't we do > > if (unshare_flags & CLONE_SIGHAND) > unshare_flags |= CLONE_VM; Nope. The backward definitions of the flags in unshare has gotten you. CLONE_SIGHAND means that you want a struct sighand_struct with a count of 1. Nothing about a sighand_struct with a count of 1 implies or requires mm_users == 1. clone can quite happily create those. > ? Or change check_unshare_flags()... > > Otherwise suppose that a single threaded process does clone(VM | SIGHAND) > and (say) child does sys_unshare(SIGHAND). This will wrongly succeed > afaics. Why would it be wrong to succeed in that case? struct sighand_struct has a count of 1. unshare(CLONE_SIGHAND) requests a sighand_struct with a count of 1. I expect part of the confusion is the code in unshare has been wrongly requiring an unshared vm to support a sighand_struct with a count of 1 since the day the code was merged. Ugh. This patch has a bug where we don't check for sighand->count == 1. clone(VM) ---> mm_users = 2 sighand->count == 1 signal->live == 1 clone(VM|SIGHAND) --> mm_users = 2 sighand->count == 2 signal->live == 1 unshare(SIGHAND) needs to guarantee that when it returns sighand->count == 1. So unshare(SIGHAND) needs to test for sighand->count == 1. Ugh. Untangling this ancient mess is a pain. One more pass at this patch it seems. Eric