From patchwork Wed Jun 6 18:11:51 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 137835 Delivered-To: patch@linaro.org Received: by 2002:a2e:970d:0:0:0:0:0 with SMTP id r13-v6csp1110245lji; Wed, 6 Jun 2018 11:12:14 -0700 (PDT) X-Google-Smtp-Source: ADUXVKJc+BJ83xK3b7HzLnsExwsN21Igsu5QmPkuEqPS8POqfk390rkU1RMnPwRJ5Y8GLeyM5UHk X-Received: by 2002:a63:2a11:: with SMTP id q17-v6mr3504695pgq.60.1528308734328; Wed, 06 Jun 2018 11:12:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1528308734; cv=none; d=google.com; s=arc-20160816; b=LD1ZvGHzobHY2OeboE7a6DbFmf6ySy1L7ug/puqLBdTy++9i+ykNmITDEYjklQ1odH PcTNR6XLn80gsPMub2fxeoJy0On13JlSbBlMJl8WArHHB3dVNVgCKNxRffoYwzE4UeZT gB/H9L8aPWYZ6Z9d8Gob4G7l3Wjolae6wpC9QuUh1ERm5E1I0OT4bhThniVcbKdN+hEX E6uTWyZgRSUNwwa3TwcWGzPNi4lz3fHNU4XnLhSV0xJA+hkvFtpG+AlIXP3clsj+Pkjr iwBOD4FVetxSaGA1zLBt+1sjxdYGJn/wMT2CisX67e1k7QQxgj1mSYcQFz573b76x0Hh E9Lw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=message-id:date:subject:to:from:delivered-to:sender:list-help :list-post:list-archive:list-subscribe:list-unsubscribe:list-id :precedence:mailing-list:dkim-signature:domainkey-signature :arc-authentication-results; bh=PL0dr+KBNd5buOd2OogUHrVnpNcI5Sdb0RCcl8IEOT0=; b=Gf+ui6tE6kU7AkZb+HB39c/6JnXrQKs//nUwy61Ax+wcAQyI/nnNQWssq/x25MwASW a7vdaSWVCHIeFlHccBsej3QMS/xtQuCY7Q6QW8usp543XNplnEeTBLfMPgR6fITtUcd7 fz3+s/fbDhIY7lrkfUBT49CW9BdtYUXLSMhe53XH+n/3DjCllYOgbyb2+le2zZFDX5rD X9KcDpY/C56qszW3qjrSQEK85mnrXMLvKtXJTzHmpLpzeR0NrkVGXIgSDeLPZ0BbrQ+3 jSNt3PmRakMUQgigoCP2ol3jY0FFIIIP55s6COp5fts/KWYuZLlf5nhwcymF3uMzWfPI C/Cg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=pIyk/EAl; spf=pass (google.com: domain of libc-alpha-return-92944-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom=libc-alpha-return-92944-patch=linaro.org@sourceware.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id e12-v6si8880091pgt.243.2018.06.06.11.12.13 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Jun 2018 11:12:14 -0700 (PDT) Received-SPF: pass (google.com: domain of libc-alpha-return-92944-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Authentication-Results: mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=pIyk/EAl; spf=pass (google.com: domain of libc-alpha-return-92944-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom=libc-alpha-return-92944-patch=linaro.org@sourceware.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id; q=dns; s= default; b=d8Fu1I1GlLOw1gddpJzsaeYWI9AXRtzY7UrmrsaYrGyXBwyQOV/qk 6DJaLkj5e4kH6hYrqni7lfWBso1Wwm9c+CM/Spxal5FX3otmuTy7ONWdRYPoCOyJ YReNxMh7FE2C/YLMSgLaLIdG+X/0DML+sMpQ40Sn5p68X5V824fbjQ= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id; s=default; bh=w4OAWC6K6Z55bOQbgAMcCkbdiZQ=; b=pIyk/EAlF3VoTiltpiMmvLaZDmrO M7asvuFIse3VK3/Qzg5AI0/tg3/xA9XIPl9jh6PxjuwB0B9xpyZSus1h5dpTvPGb prCETXyrZl0/9nzSCLsayatrOINhkmg9yC1a2OlrEmimPI9LfuFSZXHRVjhIFI9e JbrLVonmVDCzQSQ= Received: (qmail 54792 invoked by alias); 6 Jun 2018 18:12:05 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 54065 invoked by uid 89); 6 Jun 2018 18:12:04 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.5 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=faulty X-HELO: mail-qt0-f170.google.com X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id; bh=PL0dr+KBNd5buOd2OogUHrVnpNcI5Sdb0RCcl8IEOT0=; b=dSLKO5RqcMwIDceiN+KU23/PVOfmo8TzVWb+C9JtZJLBCOthiqQGO5nQ0owIqshZGL mRy0Nq+EOvFEtEr5CZIafzzNFnzUOjYUH752m3JTP3DXU66jQuLLUY8m8rMqxur365I0 2RlAZbd0tpQCEndpiANM2/ZiyAacll2fgi4mGettb1Uo5YxPne2sBKblTonJwqE+P2Yd AQBE0VZhFdGpnv/vaGB0e/2maTOT9pw2Gs0IuPTCksEZHlL2jmQ4V0Hj4KVJUIZaEZWE rfO7ZD8EmKNhVbLtHtiNnprZA8teW7C1H1B9gIX26+zcDA7chl/BOLH4qCWAoCgyNxhw TNOQ== X-Gm-Message-State: APt69E3jF6zr//iv8O91fc2O2bPoHFATyAqbUXyLKkya/yhKqU4lil4U yWITbvO1Aw/kTPhUzuPsog+t/j4IgXQ= X-Received: by 2002:a0c:b5af:: with SMTP id g47-v6mr3761735qve.94.1528308719778; Wed, 06 Jun 2018 11:11:59 -0700 (PDT) From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH] posix: Fix posix_spawnpi to not execute invalid binaries in non compat mode (BZ#23264) Date: Wed, 6 Jun 2018 15:11:51 -0300 Message-Id: <1528308711-25964-1-git-send-email-adhemerval.zanella@linaro.org> Current posix_spawnp implementation wrongly tries to execute invalid binaries (for instance script without shebang) as a shell script in non compat mode. It was a regression introduced by 9ff72da471a509a8c19791efe469f47fa6977410 when __spawni started to use __execvpe instead of __execve (glibc __execvpe try to execute ENOEXEC as shell script regardless). This patch fixes it by using an internal symbol (__execvpex) with the faulty semantic (since compat mode is handled by spawni.c itself). It was reported by Daniel Drake on libc-help [1]. Checked on x86_64-linux-gnu and i686-linux-gnu. [BZ #23264] * include/unistd.h (__execvpex): New prototype. * posix/Makefile (tests): Add tst-spawn4. (tests-internal): Add tst-spawn4-compat. * posix/execvpe.c (__execvpe_common, __execvpex): New functions. * posix/tst-spawn4-compat.c: New file. * posix/tst-spawn4.c: Likewise. * sysdeps/unix/sysv/linux/spawni.c (__spawni): Do not interpret invalid binaries as shell scripts. * sysdeps/posix/spawni.c (__spawni): Likewise. [1] https://sourceware.org/ml/libc-help/2018-06/msg00012.html --- ChangeLog | 13 ++++++ include/unistd.h | 2 + posix/Makefile | 4 +- posix/execvpe.c | 26 ++++++++---- posix/tst-spawn4-compat.c | 85 ++++++++++++++++++++++++++++++++++++++++ posix/tst-spawn4.c | 56 ++++++++++++++++++++++++++ sysdeps/posix/spawni.c | 4 +- sysdeps/unix/sysv/linux/spawni.c | 4 +- 8 files changed, 183 insertions(+), 11 deletions(-) create mode 100644 posix/tst-spawn4-compat.c create mode 100644 posix/tst-spawn4.c -- 2.7.4 diff --git a/include/unistd.h b/include/unistd.h index 0f91b8b..a171b00 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -77,6 +77,8 @@ extern char *__getcwd (char *__buf, size_t __size) attribute_hidden; extern int __rmdir (const char *__path) attribute_hidden; extern int __execvpe (const char *file, char *const argv[], char *const envp[]) attribute_hidden; +extern int __execvpex (const char *file, char *const argv[], + char *const envp[]) attribute_hidden; /* Get the canonical absolute name of the named directory, and put it in SIZE bytes of BUF. Returns NULL if the directory couldn't be determined or diff --git a/posix/Makefile b/posix/Makefile index e9730ee..4a9a1b5 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -95,10 +95,10 @@ tests := test-errno tstgetopt testfnm runtests runptests \ tst-posix_spawn-fd tst-posix_spawn-setsid \ tst-posix_fadvise tst-posix_fadvise64 \ tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve \ - tst-glob-tilde test-ssize-max + tst-glob-tilde test-ssize-max tst-spawn4 tests-internal := bug-regex5 bug-regex20 bug-regex33 \ tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 \ - tst-glob_lstat_compat + tst-glob_lstat_compat tst-spawn4-compat xtests := bug-ga2 tst-getaddrinfo4 tst-getaddrinfo5 ifeq (yes,$(build-shared)) test-srcs := globtest diff --git a/posix/execvpe.c b/posix/execvpe.c index 859c0f6..8de9c14 100644 --- a/posix/execvpe.c +++ b/posix/execvpe.c @@ -67,11 +67,9 @@ maybe_script_execute (const char *file, char *const argv[], char *const envp[]) __execve (new_argv[0], new_argv, envp); } - -/* Execute FILE, searching in the `PATH' environment variable if it contains - no slashes, with arguments ARGV and environment from ENVP. */ -int -__execvpe (const char *file, char *const argv[], char *const envp[]) +static int +__execvpe_common (const char *file, char *const argv[], char *const envp[], + bool exec_script) { /* We check the simple case first. */ if (*file == '\0') @@ -85,7 +83,7 @@ __execvpe (const char *file, char *const argv[], char *const envp[]) { __execve (file, argv, envp); - if (errno == ENOEXEC) + if (errno == ENOEXEC && exec_script) maybe_script_execute (file, argv, envp); return -1; @@ -137,7 +135,7 @@ __execvpe (const char *file, char *const argv[], char *const envp[]) __execve (buffer, argv, envp); - if (errno == ENOEXEC) + if (errno == ENOEXEC && exec_script) /* This has O(P*C) behavior, where P is the length of the path and C is the argument count. A better strategy would be allocate the substitute argv and reuse it each time through the loop (so it @@ -184,4 +182,18 @@ __execvpe (const char *file, char *const argv[], char *const envp[]) return -1; } +/* Execute FILE, searching in the `PATH' environment variable if it contains + no slashes, with arguments ARGV and environment from ENVP. */ +int +__execvpe (const char *file, char *const argv[], char *const envp[]) +{ + return __execvpe_common (file, argv, envp, true); +} weak_alias (__execvpe, execvpe) + +/* Same as __EXECVPE, but does not try to issue ENOEXEC files. */ +int +__execvpex (const char *file, char *const argv[], char *const envp[]) +{ + return __execvpe_common (file, argv, envp, false); +} diff --git a/posix/tst-spawn4-compat.c b/posix/tst-spawn4-compat.c new file mode 100644 index 0000000..7b2b07a --- /dev/null +++ b/posix/tst-spawn4-compat.c @@ -0,0 +1,85 @@ +/* Check if posix_spawn does handle correctly ENOEXEC files. + Copyright (C) 2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_15) + +compat_symbol_reference (libc, posix_spawn, posix_spawn, GLIBC_2_2); +compat_symbol_reference (libc, posix_spawnp, posix_spawnp, GLIBC_2_2); + +static int +do_test (void) +{ + char *scriptname; + int fd = create_temp_file ("tst-spawn4.", &scriptname); + TEST_VERIFY_EXIT (fd >= 0); + +#define EXPECTED_EXIT_CODE 65 +#define STR_HELPER(x) #x +#define STR(x) STR_HELPER(x) + + const char script[] = "exit " STR(EXPECTED_EXIT_CODE); + write (fd, script, sizeof (script) - 1); + + TEST_VERIFY_EXIT (close (fd) == 0); + + TEST_VERIFY_EXIT (chmod (scriptname, 0x775) == 0); + + pid_t pid; + int status; + + /* For compat symbol it verifies that trying to issued a shell script + without a shebang is correctly executed. */ + status = posix_spawn (&pid, scriptname, NULL, NULL, (char *[]) { 0 }, + (char *[]) { 0 }); + TEST_VERIFY_EXIT (status == 0); + + TEST_VERIFY_EXIT (waitpid (pid, &status, 0) == pid); + TEST_VERIFY_EXIT (WIFEXITED (status) == 1 + && WEXITSTATUS (status) == EXPECTED_EXIT_CODE); + + status = posix_spawnp (&pid, scriptname, NULL, NULL, (char *[]) { 0 }, + (char *[]) { 0 }); + TEST_VERIFY_EXIT (status == 0); + + TEST_VERIFY_EXIT (waitpid (pid, &status, 0) == pid); + TEST_VERIFY_EXIT (WIFEXITED (status) == 1 + && WEXITSTATUS (status) == EXPECTED_EXIT_CODE); + + return 0; +} +#else +static int +do_test (void) +{ + return 77; +} +#endif + +#include diff --git a/posix/tst-spawn4.c b/posix/tst-spawn4.c new file mode 100644 index 0000000..f1a7858 --- /dev/null +++ b/posix/tst-spawn4.c @@ -0,0 +1,56 @@ +/* Check if posix_spawn does handle correctly ENOEXEC files. + Copyright (C) 2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include + +#include +#include + +static int +do_test (void) +{ + char *scriptname; + int fd = create_temp_file ("tst-spawn4.", &scriptname); + TEST_VERIFY_EXIT (fd >= 0); + + const char script[] = "echo it should not happen"; + write (fd, script, sizeof (script) - 1); + + TEST_VERIFY_EXIT (close (fd) == 0); + + TEST_VERIFY_EXIT (chmod (scriptname, 0x775) == 0); + + pid_t pid; + int status; + + /* Check if scripts without shebang are correctly not executed. */ + status = posix_spawn (&pid, scriptname, NULL, NULL, (char *[]) { 0 }, + (char *[]) { 0 }); + TEST_VERIFY_EXIT (status == ENOEXEC); + + status = posix_spawnp (&pid, scriptname, NULL, NULL, (char *[]) { 0 }, + (char *[]) { 0 }); + TEST_VERIFY_EXIT (status == ENOEXEC); + + return 0; +} + +#include diff --git a/sysdeps/posix/spawni.c b/sysdeps/posix/spawni.c index 36bb5b4..b138ab4 100644 --- a/sysdeps/posix/spawni.c +++ b/sysdeps/posix/spawni.c @@ -310,6 +310,8 @@ __spawni (pid_t * pid, const char *file, const posix_spawnattr_t * attrp, char *const argv[], char *const envp[], int xflags) { + /* It uses __execvpex to avoid run ENOEXEC in non compatibility mode (it + will be handled by maybe_script_execute). */ return __spawnix (pid, file, acts, attrp, argv, envp, xflags, - xflags & SPAWN_XFLAGS_USE_PATH ? __execvpe : __execve); + xflags & SPAWN_XFLAGS_USE_PATH ? __execvpex : __execve); } diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c index 0391b9b..cf0213e 100644 --- a/sysdeps/unix/sysv/linux/spawni.c +++ b/sysdeps/unix/sysv/linux/spawni.c @@ -404,6 +404,8 @@ __spawni (pid_t * pid, const char *file, const posix_spawnattr_t * attrp, char *const argv[], char *const envp[], int xflags) { + /* It uses __execvpex to avoid run ENOEXEC in non compatibility mode (it + will be handled by maybe_script_execute). */ return __spawnix (pid, file, acts, attrp, argv, envp, xflags, - xflags & SPAWN_XFLAGS_USE_PATH ? __execvpe : __execve); + xflags & SPAWN_XFLAGS_USE_PATH ? __execvpex :__execve); }