From owner-freebsd-stable@freebsd.org Sun Dec 1 14:48:28 2019 Return-Path: Delivered-To: freebsd-stable@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 412E41ADD82 for ; Sun, 1 Dec 2019 14:48:28 +0000 (UTC) (envelope-from kostikbel@gmail.com) Received: from kib.kiev.ua (kib.kiev.ua [IPv6:2001:470:d5e7:1::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 47Qrhq0VYlz3PMy for ; Sun, 1 Dec 2019 14:48:26 +0000 (UTC) (envelope-from kostikbel@gmail.com) Received: from tom.home (kib@localhost [127.0.0.1]) by kib.kiev.ua (8.15.2/8.15.2) with ESMTPS id xB1EmDpD055444 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NO); Sun, 1 Dec 2019 16:48:17 +0200 (EET) (envelope-from kostikbel@gmail.com) DKIM-Filter: OpenDKIM Filter v2.10.3 kib.kiev.ua xB1EmDpD055444 Received: (from kostik@localhost) by tom.home (8.15.2/8.15.2/Submit) id xB1EmDqZ055443; Sun, 1 Dec 2019 16:48:13 +0200 (EET) (envelope-from kostikbel@gmail.com) X-Authentication-Warning: tom.home: kostik set sender to kostikbel@gmail.com using -f Date: Sun, 1 Dec 2019 16:48:13 +0200 From: Konstantin Belousov To: Dmitry Marakasov Cc: freebsd-stable@freebsd.org Subject: Re: How can kill(-1, 0) return EPERM? Message-ID: <20191201144813.GD10580@kib.kiev.ua> References: <20191129151606.GD4071@hades.panopticon> <20191129164509.GE4071@hades.panopticon> <20191129225834.GY10580@kib.kiev.ua> <20191201002411.GF4071@hades.panopticon> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20191201002411.GF4071@hades.panopticon> User-Agent: Mutt/1.12.2 (2019-09-21) X-Spam-Status: No, score=-1.0 required=5.0 tests=ALL_TRUSTED,BAYES_00, DKIM_ADSP_CUSTOM_MED,FORGED_GMAIL_RCVD,FREEMAIL_FROM, NML_ADSP_CUSTOM_MED autolearn=no autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on tom.home X-Rspamd-Queue-Id: 47Qrhq0VYlz3PMy X-Spamd-Bar: / Authentication-Results: mx1.freebsd.org; dkim=none; dmarc=fail reason="No valid SPF, No valid DKIM" header.from=gmail.com (policy=none); spf=softfail (mx1.freebsd.org: 2001:470:d5e7:1::1 is neither permitted nor denied by domain of kostikbel@gmail.com) smtp.mailfrom=kostikbel@gmail.com X-Spamd-Result: default: False [-1.00 / 15.00]; ARC_NA(0.00)[]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; DMARC_POLICY_SOFTFAIL(0.10)[gmail.com : No valid SPF, No valid DKIM,none]; RCVD_TLS_ALL(0.00)[]; FROM_HAS_DN(0.00)[]; TO_DN_SOME(0.00)[]; FREEMAIL_FROM(0.00)[gmail.com]; NEURAL_HAM_LONG(-1.00)[-1.000,0]; MIME_GOOD(-0.10)[text/plain]; HAS_XAW(0.00)[]; R_SPF_SOFTFAIL(0.00)[~all]; IP_SCORE_FREEMAIL(0.00)[]; TO_MATCH_ENVRCPT_SOME(0.00)[]; RCPT_COUNT_TWO(0.00)[2]; IP_SCORE(0.00)[ip: (-2.70), ipnet: 2001:470::/32(-4.64), asn: 6939(-3.52), country: US(-0.05)]; FROM_EQ_ENVFROM(0.00)[]; R_DKIM_NA(0.00)[]; SUBJECT_ENDS_QUESTION(1.00)[]; ASN(0.00)[asn:6939, ipnet:2001:470::/32, country:US]; MIME_TRACE(0.00)[0:+]; FREEMAIL_ENVFROM(0.00)[gmail.com]; RCVD_COUNT_TWO(0.00)[2] X-BeenThere: freebsd-stable@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Production branch of FreeBSD source code List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 01 Dec 2019 14:48:28 -0000 On Sun, Dec 01, 2019 at 03:24:11AM +0300, Dmitry Marakasov wrote: > * Konstantin Belousov (kostikbel@gmail.com) wrote: > > > > > I'm helping to investigate some userspace issue [1], where kill(-1, SIGKILL) > > > > fails with EPERM. I've managed to isolate this case in a small program: > > > > > > > > > > > > ``` > > > > #include > > > > #include > > > > #include > > > > #include > > > > #include > > > > #include > > > > > > > > int main() { > > > > if (setuid(66) == -1) // uucp, just for the test > > > > err(1, "setuid"); > > > > > > > > int res = kill(-1, 0); // <- fails with EPERM > > > > fprintf(stderr, "kill(-1, 0) result=%d, errno=%s\n", res, strerror(errno)); > > > > > > > > return 0; > > > > } > > > > ``` > > > > > > > > when run from root on 12.1 kill call fails with EPERM. However I cannot > > > > comprehend what it is caused by and how it's even possible: kill(2) manpage > > > > says that with pid=-1 kill should only send (and in this case of sig=0, > > > > /not/ send) signals to the processes belonging to the current uid, so there > > > > should be no permission problems. I've also looked into the kernel code > > > > (sys_kill, killpg1), and it matches to what manpage says, I see no way > > > > for it to return EPERM: sys_kill() should fall through to the switch, call > > > > killpg1() with all=1 and killpg1() if(all) branch may only set `ret` to > > > > either 0 or ESRCH. Am I missing something, or is there a problem somewhere? > > > > > > It looks like I have misread the `else if' path of this core. > > > > > > if (all) { > > > /* > > > * broadcast > > > */ > > > sx_slock(&allproc_lock); > > > FOREACH_PROC_IN_SYSTEM(p) { > > > if (p->p_pid <= 1 || p->p_flag & P_SYSTEM || > > > p == td->td_proc || p->p_state == PRS_NEW) { > > > continue; > > > } > > > PROC_LOCK(p); > > > err = p_cansignal(td, p, sig); > > > if (err == 0) { > > > if (sig) > > > pksignal(p, sig, ksi); > > > ret = err; > > > } > > > else if (ret == ESRCH) > > > ret = err; > > > PROC_UNLOCK(p); > > > } > > > sx_sunlock(&allproc_lock); > > > } ... > > > > > > so it's clear now where EPERM comes from. However it looks like the > > > behavior contradicts the manpage - there are no signs of check that > > > the signalled process has the same uid as the caller. > > > > I am not sure what you mean by 'signs of check'. Look at p_cansignal() > > and cr_cansignal() implementation. > > I've meant that according to the manpage > > If pid is -1: > If the user has super-user privileges, the signal is sent to all > processes excluding system processes (with P_SYSTEM flag set), > process with ID 1 (usually init(8)), and the process sending the > signal. If the user is not the super user, the signal is sent to > all processes with the same uid as the user excluding the process > sending the signal. No error is returned if any process could be > signaled. > > IMO there should be an additional check in this condition: > > if (p->p_pid <= 1 || p->p_flag & P_SYSTEM || > p == td->td_proc || p->p_state == PRS_NEW) { > continue; > } > > E.g. something like > > if (p->p_pid <= 1 || p->p_flag & P_SYSTEM || > p == td->td_proc || p->p_state == PRS_NEW || > (td->td_ucred->cr_ruid != 0 && > p->td_ucred->cr_ruid != td->td_ucred->cr_ruid) { > continue; > } > > e.g. it should not even attempt to signal processes with other uids. Why ? You are trying to outguess p_cansignal(), which could deny action for much more reasons, so you would get EPERM still, e.g. if the target is suid. Or, p_cansignal() also might allow to send the signal even for mismatched uids, again look at it code. I might guess that your complain is really about a different aspect of it. If you look at the posix description of the EPERM error from kill(2) (really kill(3)), it says [EPERM] The process does not have permission to send the signal to any receiving process. In other words, we should not return EPERM if we signalled at least one of the process. Is this the problem ?