From patchwork Tue Oct 27 14:35:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 40886 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 44AC03953827; Tue, 27 Oct 2020 14:35:41 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 44AC03953827 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1603809341; bh=BTA5M2tyt0pBcHKrnG/m8ZAG8fcziW10FqFgv52Oco8=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=M4F/vohPcuqTEsZfzNGPKuMcvysQvxJf5OJrMflyxNKRYJWwbdq9TOS1RktuniIQQ e1ptkB3vJVM1qKgUBOpHH1rChmCWXPjuKfpLhQqKgDE4jeQIT3HGjTUTCvZ6B4zGAc QEuM5ha7yX+u/380U45HzcROGjeBz+ntmIoo3lsU= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qk1-x72d.google.com (mail-qk1-x72d.google.com [IPv6:2607:f8b0:4864:20::72d]) by sourceware.org (Postfix) with ESMTPS id 104923851C34 for ; Tue, 27 Oct 2020 14:35:38 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 104923851C34 Received: by mail-qk1-x72d.google.com with SMTP id 140so1332855qko.2 for ; Tue, 27 Oct 2020 07:35:38 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=BTA5M2tyt0pBcHKrnG/m8ZAG8fcziW10FqFgv52Oco8=; b=G4bZDbtQJ0glgz/B92lZF4DdrFn/ouDyCM9mhcyutImJWyJGprFN23jB0llDTnRc/z wUrM4Jm7Q+f19jElvvwb3c21WhuvH6vdEICE3dT5XKaZZV+MjIgouGjiCf1MNcdpL2Zj m5qNaANh0Wo5G/4Fd9rBLHWA9GdAig6g5LNxwDcZDMLyml8JVQMql+m4Z0d0m1wyOrFe sZdg7iY/MBHeJ+UTzfBjXVg00HazrdTbfyAqsJjcMWr4tKiQiYfUSfndmRPBg0hQrtrP oeMMpW3e8BCyyW7M8nWjrVghkvELlRQmTZ21SBvoqPYgDjk8LalsmeA5+2bar9eQx/uJ gWuQ== X-Gm-Message-State: AOAM5311KVT3sCngPloU4aOtULlYZny3sWCin8czsX8ir5pMb8JPGp7G YaDHktY8VV/0X9xxh9Po5ojPKvFgCgajfQ== X-Google-Smtp-Source: ABdhPJyIa0OkmyGGHzKC/XtFvr85FnEHJmfS+XzgYNwaSMLHbXmAW8MmYzVuE0ZgojOePhOpCbzYmw== X-Received: by 2002:a05:620a:10b7:: with SMTP id h23mr2309961qkk.132.1603809336573; Tue, 27 Oct 2020 07:35:36 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id 19sm780704qki.33.2020.10.27.07.35.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Oct 2020 07:35:36 -0700 (PDT) To: libc-alpha@sourceware.org Subject: [PATCH v2 1/4] Sync canonicalize with gnulib [BZ #10635] Date: Tue, 27 Oct 2020 11:35:28 -0300 Message-Id: <20201027143531.2448132-1-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 X-Spam-Status: No, score=-14.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Reply-To: Adhemerval Zanella Cc: Andreas Schwab Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" It sync with gnulib version 44358d4d165b with the following exceptions: - All the logic to which __getcwd use. - MAXSYMLINKS define (glibc already handles it on eloop-threshold.h). - The pathmax.h logic to handle //path (neither Linux nor Hurd makes this distinction). - Don't explict set ENOMEM on malloc failure (it is already handled by malloc itself). - The usage of malloca.h routines. Checked on x86_64-linux-gnu --- stdlib/canonicalize.c | 244 +++++++++++++++++++++++------------------- 1 file changed, 131 insertions(+), 113 deletions(-) diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c index 3fcb399a5d..2770f4ae44 100644 --- a/stdlib/canonicalize.c +++ b/stdlib/canonicalize.c @@ -16,8 +16,9 @@ License along with the GNU C Library; if not, see . */ -#include #include + +#include #include #include #include @@ -29,10 +30,10 @@ #include /* Return the canonical absolute name of file NAME. A canonical name - does not contain any `.', `..' components nor any repeated path + does not contain any ".", ".." components nor any repeated path separators ('/') or symlinks. All path components must exist. If RESOLVED is null, the result is malloc'd; otherwise, if the - canonical name is PATH_MAX chars or more, returns null with `errno' + canonical name is PATH_MAX chars or more, returns null with 'errno' set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars, returns the name in RESOLVED. If the name cannot be resolved and RESOLVED is non-NULL, it contains the path of the first component @@ -50,9 +51,9 @@ __realpath (const char *name, char *resolved) if (name == NULL) { /* As per Single Unix Specification V2 we must return an error if - either parameter is a null pointer. We extend this to allow - the RESOLVED parameter to be NULL in case the we are expected to - allocate the room for the return value. */ + either parameter is a null pointer. We extend this to allow + the RESOLVED parameter to be NULL in case the we are expected to + allocate the room for the return value. */ __set_errno (EINVAL); return NULL; } @@ -60,7 +61,7 @@ __realpath (const char *name, char *resolved) if (name[0] == '\0') { /* As per Single Unix Specification V2 we must return an error if - the name argument points to an empty string. */ + the name argument points to an empty string. */ __set_errno (ENOENT); return NULL; } @@ -70,152 +71,169 @@ __realpath (const char *name, char *resolved) #else path_max = __pathconf (name, _PC_PATH_MAX); if (path_max <= 0) - path_max = 1024; + path_max = 8192; #endif if (resolved == NULL) { rpath = malloc (path_max); if (rpath == NULL) - return NULL; + return NULL; } else rpath = resolved; rpath_limit = rpath + path_max; + if (name[0] != '/') { if (!__getcwd (rpath, path_max)) - { - rpath[0] = '\0'; - goto error; - } - dest = __rawmemchr (rpath, '\0'); + { + rpath[0] = '\0'; + goto error; + } + dest = strchr (rpath, '\0'); } else { - rpath[0] = '/'; - dest = rpath + 1; + dest = rpath; + *dest++ = '/'; } + start = name; - for (start = end = name; *start; start = end) + for (end = start; *start; start = end) { +#ifdef _LIBC struct stat64 st; - int n; +#else + struct stat st; +#endif /* Skip sequence of multiple path-separators. */ while (*start == '/') - ++start; + ++start; /* Find end of path component. */ for (end = start; *end && *end != '/'; ++end) - /* Nothing. */; + /* Nothing. */; if (end - start == 0) - break; + break; else if (end - start == 1 && start[0] == '.') - /* nothing */; + /* nothing */; else if (end - start == 2 && start[0] == '.' && start[1] == '.') - { - /* Back up to previous component, ignore if at root already. */ - if (dest > rpath + 1) - while ((--dest)[-1] != '/'); - } + { + /* Back up to previous component, ignore if at root already. */ + if (dest > rpath + 1) + for (--dest; dest > rpath && dest[-1] != '/'; --dest) + continue; + } else - { - size_t new_size; - - if (dest[-1] != '/') - *dest++ = '/'; - - if (dest + (end - start) >= rpath_limit) - { - ptrdiff_t dest_offset = dest - rpath; - char *new_rpath; - - if (resolved) - { - __set_errno (ENAMETOOLONG); - if (dest > rpath + 1) - dest--; - *dest = '\0'; - goto error; - } - new_size = rpath_limit - rpath; - if (end - start + 1 > path_max) - new_size += end - start + 1; - else - new_size += path_max; - new_rpath = (char *) realloc (rpath, new_size); - if (new_rpath == NULL) - goto error; - rpath = new_rpath; - rpath_limit = rpath + new_size; - - dest = rpath + dest_offset; - } - - dest = __mempcpy (dest, start, end - start); - *dest = '\0'; - - if (__lstat64 (rpath, &st) < 0) - goto error; - - if (S_ISLNK (st.st_mode)) - { - char *buf = __alloca (path_max); - size_t len; - - if (++num_links > __eloop_threshold ()) - { - __set_errno (ELOOP); - goto error; - } - - n = __readlink (rpath, buf, path_max - 1); - if (n < 0) - goto error; - buf[n] = '\0'; - - if (!extra_buf) - extra_buf = __alloca (path_max); - - len = strlen (end); - if (path_max - n <= len) - { - __set_errno (ENAMETOOLONG); - goto error; - } - - /* Careful here, end may be a pointer into extra_buf... */ - memmove (&extra_buf[n], end, len + 1); - name = end = memcpy (extra_buf, buf, n); - - if (buf[0] == '/') - dest = rpath + 1; /* It's an absolute symlink */ - else - /* Back up to previous component, ignore if at root already: */ - if (dest > rpath + 1) - while ((--dest)[-1] != '/'); - } - else if (!S_ISDIR (st.st_mode) && *end != '\0') - { - __set_errno (ENOTDIR); - goto error; - } - } + { + size_t new_size; + + if (dest[-1] != '/') + *dest++ = '/'; + + if (dest + (end - start) >= rpath_limit) + { + ptrdiff_t dest_offset = dest - rpath; + char *new_rpath; + + if (resolved) + { + __set_errno (ENAMETOOLONG); + if (dest > rpath + 1) + dest--; + *dest = '\0'; + goto error; + } + new_size = rpath_limit - rpath; + if (end - start + 1 > path_max) + new_size += end - start + 1; + else + new_size += path_max; + new_rpath = (char *) realloc (rpath, new_size); + if (new_rpath == NULL) + goto error; + rpath = new_rpath; + rpath_limit = rpath + new_size; + + dest = rpath + dest_offset; + } + + dest = __mempcpy (dest, start, end - start); + *dest = '\0'; + + if (__lstat64 (rpath, &st) < 0) + goto error; + + if (S_ISLNK (st.st_mode)) + { + char *buf = __alloca (path_max); + size_t len; + ssize_t n; + + if (++num_links > __eloop_threshold ()) + { + __set_errno (ELOOP); + goto error; + } + + n = __readlink (rpath, buf, path_max - 1); + if (n < 0) + goto error; + buf[n] = '\0'; + + if (!extra_buf) + extra_buf = __alloca (path_max); + + len = strlen (end); + /* Check that n + len + 1 doesn't overflow and is <= path_max. */ + if (n >= SIZE_MAX - len || n + len >= path_max) + { + __set_errno (ENAMETOOLONG); + goto error; + } + + /* Careful here, end may be a pointer into extra_buf... */ + memmove (&extra_buf[n], end, len + 1); + name = end = memcpy (extra_buf, buf, n); + + if (buf[0] == '/') + { + dest = rpath; + *dest++ = '/'; /* It's an absolute symlink */ + } + else + { + /* Back up to previous component, ignore if at root + already: */ + if (dest > rpath + 1) + for (--dest; dest > rpath && dest[-1] != '/'; --dest) + continue; + } + } + else if (!S_ISDIR (st.st_mode) && *end != '\0') + { + __set_errno (ENOTDIR); + goto error; + } + } } if (dest > rpath + 1 && dest[-1] == '/') --dest; *dest = '\0'; - assert (resolved == NULL || resolved == rpath); return rpath; error: - assert (resolved == NULL || resolved == rpath); - if (resolved == NULL) - free (rpath); + { + int saved_errno = errno; + if (resolved == NULL) + free (rpath); + __set_errno (saved_errno); + } return NULL; } libc_hidden_def (__realpath) From patchwork Tue Oct 27 14:35:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 40887 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 6E2CC3953C04; Tue, 27 Oct 2020 14:35:43 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6E2CC3953C04 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1603809343; bh=/mOdw471kfnJhpt82Bd5PRaT9dNRYwOkcOe5gHs77fo=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=uJhs1JkIBwA3wR+9DevA0gUJL3M1eWBZXuEcD/DUrv26QTzf2FylUBRoOewDVYmXG ip3oVrLs/JzrMonaqdZo0Efyb+et9lJu/U2OM2yWY/MGkPjj9rLbrhcb19NUc28zJj duJ28aypkFfqpTOB2DmIkCRnTS9Sq65zSRM4RMj8= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qv1-xf2d.google.com (mail-qv1-xf2d.google.com [IPv6:2607:f8b0:4864:20::f2d]) by sourceware.org (Postfix) with ESMTPS id CC5E9386EC51 for ; Tue, 27 Oct 2020 14:35:39 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org CC5E9386EC51 Received: by mail-qv1-xf2d.google.com with SMTP id b11so729588qvr.9 for ; Tue, 27 Oct 2020 07:35:39 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=/mOdw471kfnJhpt82Bd5PRaT9dNRYwOkcOe5gHs77fo=; b=L/TBTOkBcs5MOMJkIKTGhA0COuQ2KGcMq6BQwxsa2CP5iL2f4gyX6AjCy3UKiUeqyP gKJ+u+1ekKFZZVAlwUkGsYFEfm99nc5uMVksK4QTxxuh41AWbtle74BA2No2lxUrr4sa 5VEEORw2dAtDy/vH/j+tOz4ffq0B0thXWMVPuHRifndWuo+IDRM623tfJJ5PolbWev0z H+Ac2GOJgz00+W4RuuIKtjwSc1gesYgLPO9TIbT9z+Mxmc2fzg9iN5A3ywHb5ZAmKUbU y7BqgLcm94Lb1KiAEvGxRto3OJ92wnn1py9GXT1eRnYqT6PHbsuDLb6fkhYOya7ZI37t l2oA== X-Gm-Message-State: AOAM532TlXa2Kl07N/QUB9/7oNWW4VHWJYCGxkZH5WlzCDUhCX7W8Q/w IVXdMNUnaFPg8laDvdsf3beZLHdti8OzbA== X-Google-Smtp-Source: ABdhPJyfZCvvasPnHnQFFctAKY5UMqlr7UjRCe5/2/LHOq006j57hAQ+cBghvnT7TXHvpFmMwDOO2w== X-Received: by 2002:ad4:46a8:: with SMTP id br8mr2766871qvb.24.1603809338726; Tue, 27 Oct 2020 07:35:38 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id 19sm780704qki.33.2020.10.27.07.35.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Oct 2020 07:35:38 -0700 (PDT) To: libc-alpha@sourceware.org Subject: [PATCH v2 2/4] stdlib: Use fixed buffer size for realpath [BZ #26241] Date: Tue, 27 Oct 2020 11:35:29 -0300 Message-Id: <20201027143531.2448132-2-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201027143531.2448132-1-adhemerval.zanella@linaro.org> References: <20201027143531.2448132-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-14.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Reply-To: Adhemerval Zanella Cc: Andreas Schwab Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" It uses both a fixed internal buffer with PATH_MAX size to read and copy the results of the readlink call. Also, if PATH_MAX is not defined it uses a default value of 1024 as for other stdlib implementations. The expected stack usage is about 8k on Linux where PATH_MAX is define as 4096 (plus some internal function usage for local variable). Checked on x86_64-linux-gnu and i686-linux-gnu. --- stdlib/Makefile | 3 +- stdlib/canonicalize.c | 29 +++-- stdlib/tst-canon-bz26341.c | 108 ++++++++++++++++++ support/support_set_small_thread_stack_size.c | 12 +- support/xthread.h | 2 + 5 files changed, 134 insertions(+), 20 deletions(-) create mode 100644 stdlib/tst-canon-bz26341.c diff --git a/stdlib/Makefile b/stdlib/Makefile index f8a1660186..adfdb0b1fb 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -87,7 +87,7 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ tst-makecontext-align test-bz22786 tst-strtod-nan-sign \ tst-swapcontext1 tst-setcontext4 tst-setcontext5 \ tst-setcontext6 tst-setcontext7 tst-setcontext8 \ - tst-setcontext9 tst-bz20544 + tst-setcontext9 tst-bz20544 tst-canon-bz26341 tests-internal := tst-strtod1i tst-strtod3 tst-strtod4 tst-strtod5i \ tst-tls-atexit tst-tls-atexit-nodelete @@ -102,6 +102,7 @@ LDLIBS-test-atexit-race = $(shared-thread-library) LDLIBS-test-at_quick_exit-race = $(shared-thread-library) LDLIBS-test-cxa_atexit-race = $(shared-thread-library) LDLIBS-test-on_exit-race = $(shared-thread-library) +LDLIBS-tst-canon-bz26341 = $(shared-thread-library) LDLIBS-test-dlclose-exit-race = $(shared-thread-library) $(libdl) LDFLAGS-test-dlclose-exit-race = $(LDFLAGS-rdynamic) diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c index 2770f4ae44..50244d0f67 100644 --- a/stdlib/canonicalize.c +++ b/stdlib/canonicalize.c @@ -29,6 +29,14 @@ #include #include +#ifndef PATH_MAX +# ifdef MAXPATHLEN +# define PATH_MAX MAXPATHLEN +# else +# define PATH_MAX 1024 +# endif +#endif + /* Return the canonical absolute name of file NAME. A canonical name does not contain any ".", ".." components nor any repeated path separators ('/') or symlinks. All path components must exist. If @@ -43,10 +51,11 @@ char * __realpath (const char *name, char *resolved) { - char *rpath, *dest, *extra_buf = NULL; + char *rpath, *dest; const char *start, *end, *rpath_limit; - long int path_max; + const size_t path_max = PATH_MAX; int num_links = 0; + char extra_buf[PATH_MAX]; if (name == NULL) { @@ -66,14 +75,6 @@ __realpath (const char *name, char *resolved) return NULL; } -#ifdef PATH_MAX - path_max = PATH_MAX; -#else - path_max = __pathconf (name, _PC_PATH_MAX); - if (path_max <= 0) - path_max = 8192; -#endif - if (resolved == NULL) { rpath = malloc (path_max); @@ -170,24 +171,20 @@ __realpath (const char *name, char *resolved) if (S_ISLNK (st.st_mode)) { - char *buf = __alloca (path_max); + char buf[PATH_MAX]; size_t len; ssize_t n; if (++num_links > __eloop_threshold ()) { __set_errno (ELOOP); - goto error; - } + goto error; } n = __readlink (rpath, buf, path_max - 1); if (n < 0) goto error; buf[n] = '\0'; - if (!extra_buf) - extra_buf = __alloca (path_max); - len = strlen (end); /* Check that n + len + 1 doesn't overflow and is <= path_max. */ if (n >= SIZE_MAX - len || n + len >= path_max) diff --git a/stdlib/tst-canon-bz26341.c b/stdlib/tst-canon-bz26341.c new file mode 100644 index 0000000000..63474bddaa --- /dev/null +++ b/stdlib/tst-canon-bz26341.c @@ -0,0 +1,108 @@ +/* Check if realpath does not consume extra stack space based on symlink + existance in the path (BZ #26341) + Copyright (C) 2020 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 + +static char *filename; +static size_t filenamelen; +static char *linkname; + +static int +maxsymlinks (void) +{ +#ifdef MAXSYMLINKS + return MAXSYMLINKS; +#else + long int sysconf_symloop_max = sysconf (_SC_SYMLOOP_MAX); + return sysconf_symloop_max <= 0 + ? _POSIX_SYMLOOP_MAX + : sysconf_symloop_max; +#endif +} + +#ifndef PATH_MAX +# define PATH_MAX 1024 +#endif + +static void +create_link (void) +{ + int fd = create_temp_file ("tst-canon-bz26341", &filename); + TEST_VERIFY_EXIT (fd != -1); + xclose (fd); + + char *prevlink = filename; + int maxlinks = maxsymlinks (); + for (int i = 0; i < maxlinks; i++) + { + linkname = xasprintf ("%s%d", filename, i); + xsymlink (prevlink, linkname); + add_temp_file (linkname); + prevlink = linkname; + } + + filenamelen = strlen (filename); +} + +static void * +do_realpath (void *arg) +{ + /* Old implementation of realpath allocates a PATH_MAX using alloca + for each symlink in the path, leading to MAXSYMLINKS times PATH_MAX + maximum stack usage. + This stack allocations tries fill the thread allocated stack minus + both the thread (plus some slack) and the realpath (plus some slack). + If realpath uses more than 2 * PATH_MAX plus some slack it will trigger + a stackoverflow. */ + + const size_t realpath_usage = 2 * PATH_MAX + 1024; + const size_t thread_usage = 1 * PATH_MAX + 1024; + size_t stack_size = support_small_thread_stack_size () + - realpath_usage - thread_usage; + char stack[stack_size]; + char *resolved = stack + stack_size - thread_usage + 1024; + + char *p = realpath (linkname, resolved); + TEST_VERIFY (p != NULL); + TEST_COMPARE_BLOB (resolved, filenamelen, filename, filenamelen); + + return NULL; +} + +static int +do_test (void) +{ + create_link (); + + pthread_t th = xpthread_create (support_small_stack_thread_attribute (), + do_realpath, NULL); + xpthread_join (th); + + return 0; +} + +#include diff --git a/support/support_set_small_thread_stack_size.c b/support/support_set_small_thread_stack_size.c index 69d66e97db..74a0e38a72 100644 --- a/support/support_set_small_thread_stack_size.c +++ b/support/support_set_small_thread_stack_size.c @@ -20,8 +20,8 @@ #include #include -void -support_set_small_thread_stack_size (pthread_attr_t *attr) +size_t +support_small_thread_stack_size (void) { /* Some architectures have too small values for PTHREAD_STACK_MIN which cannot be used for creating threads. Ensure that the stack @@ -31,5 +31,11 @@ support_set_small_thread_stack_size (pthread_attr_t *attr) if (stack_size < PTHREAD_STACK_MIN) stack_size = PTHREAD_STACK_MIN; #endif - xpthread_attr_setstacksize (attr, stack_size); + return stack_size; +} + +void +support_set_small_thread_stack_size (pthread_attr_t *attr) +{ + xpthread_attr_setstacksize (attr, support_small_thread_stack_size ()); } diff --git a/support/xthread.h b/support/xthread.h index 05f8d4a7d9..6ba2f5a18b 100644 --- a/support/xthread.h +++ b/support/xthread.h @@ -78,6 +78,8 @@ void xpthread_attr_setguardsize (pthread_attr_t *attr, /* Set the stack size in ATTR to a small value, but still large enough to cover most internal glibc stack usage. */ void support_set_small_thread_stack_size (pthread_attr_t *attr); +/* Return the stack size used on support_set_small_thread_stack_size. */ +size_t support_small_thread_stack_size (void); /* Return a pointer to a thread attribute which requests a small stack. The caller must not free this pointer. */ From patchwork Tue Oct 27 14:35:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 40888 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 07C853953CE6; Tue, 27 Oct 2020 14:35:44 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 07C853953CE6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1603809344; bh=xNBengUZLG6WlMzfYUHgGOiCT5WgWLx0+yoYJVq8+io=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=Jq/yI7TplJzlXcNzXNFEtS6T+zYSuXOq2I06PEB4GCPp3J4+veWBMD9zJmGByVxdp zFqxInOLovZ8pOKLp9EKPCi8m/JRmVU7hlKo8393taWsyCqvpQBiGBEKZi2Hcfm38C GsXte4UMUf5Wg1woAEKS9Ck1xNscUfkcwrtLv8BY= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qk1-x742.google.com (mail-qk1-x742.google.com [IPv6:2607:f8b0:4864:20::742]) by sourceware.org (Postfix) with ESMTPS id 0050D3953819 for ; Tue, 27 Oct 2020 14:35:40 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 0050D3953819 Received: by mail-qk1-x742.google.com with SMTP id r7so1330575qkf.3 for ; Tue, 27 Oct 2020 07:35:40 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=xNBengUZLG6WlMzfYUHgGOiCT5WgWLx0+yoYJVq8+io=; b=Iamu+KnI89jNBpX3/A0rLCEP3vgwdsDrb7nfKvzBaYDHvDhSyOly12eMSv41wHpgMi rLHOd78CUtQjSLpU+YhfnpYns82UuziOgqL2PTJNs7xmk3XOhZ9G2JkdmMqRl2sI/zGd X9wipiuVzKkDpydD4+EyS/Ths/+5mWYnOA5l6evQ0XdoQTSnSeACgnKFKgDwEZ8T/Am8 EuKHb7VnGlRn7hh/pFiJsif7KARO/ITVf5ophl5eM41+o2CfiSOeot3o8M++ba+aFh5n BzygEOV2csCBoqHsZD18Qd0KQ0NCJufHhRyqtOhgRQcJWoGUDnZL3zkxrGLSx/7SXLfP 0vFw== X-Gm-Message-State: AOAM531xcM500omisDRT4SVyJ+gLHHo9oExvjOc5iV9lYC2bpIe2FxV8 pvWzq9UzckT8VjThwcy5zmUpmnfQ3FbGMQ== X-Google-Smtp-Source: ABdhPJy6e2isL9Benuh3cKFStvPozu7ctRl+Yzx4MsPYGK4IPw5CINFtXvdPDs5qJDAxubMtCOtnaw== X-Received: by 2002:a05:620a:a09:: with SMTP id i9mr2269421qka.119.1603809340357; Tue, 27 Oct 2020 07:35:40 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id 19sm780704qki.33.2020.10.27.07.35.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Oct 2020 07:35:39 -0700 (PDT) To: libc-alpha@sourceware.org Subject: [PATCH v2 3/4] stdlib: Fix arithmetic overflows in realpath [BZ #26592] Date: Tue, 27 Oct 2020 11:35:30 -0300 Message-Id: <20201027143531.2448132-3-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201027143531.2448132-1-adhemerval.zanella@linaro.org> References: <20201027143531.2448132-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-14.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Reply-To: Adhemerval Zanella Cc: Andreas Schwab Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" The realpath uses an end-of-array pointer 'rpath_limit', and makes invalid (overflowing) comparisons against it to catch overflow: 117 /* Find end of path component. */ 118 if (dest + (end-start) >= rpath_limit) I could not see a easy way to stress this issue since it rely on how the input argument is layout in memory along with a large filename name that trigger the overflow comparison. However, the fix is simple enough where it simple reorganize arithmetic in the comparison. Checked on x86_64-linux-gnu and i686-linux-gnu. --- stdlib/canonicalize.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c index 50244d0f67..9aa69676e4 100644 --- a/stdlib/canonicalize.c +++ b/stdlib/canonicalize.c @@ -136,7 +136,7 @@ __realpath (const char *name, char *resolved) if (dest[-1] != '/') *dest++ = '/'; - if (dest + (end - start) >= rpath_limit) + if (end - start >= rpath_limit - dest) { ptrdiff_t dest_offset = dest - rpath; char *new_rpath; From patchwork Tue Oct 27 14:35:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 40889 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 993C43953CF8; Tue, 27 Oct 2020 14:35:44 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 993C43953CF8 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1603809344; bh=3VeEU4rCB4/YGoH/ml51HOd+0isTZLG+rDLOD2RfEoU=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=OWAInEwLQ3I2iU4ofCaN3av36LzAwwW/fgtklZcwC5f1ABxd+L7Q0bFrPkQJqQqhA oB9vjODN60nRPBLNs5SzU4xi3IHppeeLR29pjjLlPZbGYhK994vcFvB8G28zvLigku y1bQBy11s7jJbSn68tEyoKdv/8UFpJ3Q2m9taJzw= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qv1-xf42.google.com (mail-qv1-xf42.google.com [IPv6:2607:f8b0:4864:20::f42]) by sourceware.org (Postfix) with ESMTPS id D59A83953C09 for ; Tue, 27 Oct 2020 14:35:42 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org D59A83953C09 Received: by mail-qv1-xf42.google.com with SMTP id w5so726888qvn.12 for ; Tue, 27 Oct 2020 07:35:42 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=3VeEU4rCB4/YGoH/ml51HOd+0isTZLG+rDLOD2RfEoU=; b=tcpfMIHBM0QY9BJ/kzyvnD3CPtI220hMLr/Q7fe7qRRTO1OzmiWl3MHYXe/+PkLelM PS6c1Xh177m/k5ReSN0+lfjofne5kmd/V2mBWQlpYsr6WgM9AS79hN/pgPHepEYcvmzQ Um1aU9O1I36HkqZrVY9lyVOCYJ65QwMORJ8jS4Gw25FVlubL2eMFI6784xILgtg8DXde QfnVqqcMEinoXKoTYDmCCKkp6i36Q6L33n4i1rbE4JetR1kITpGFgUiETa40eZSVWJ+j l3lhj2jD9Mj1GpEYuJZDsXzh0z+p3eymd+9r6h8H4Z2jqgF0jTg/Fu9bNms2NYKMQoZq /SsA== X-Gm-Message-State: AOAM533aE7sDAKpUW8MoGafHzMub1b2i1Iti6ttJzTl+/48pP+CvtxTQ D9Dwyt0GDcG088IXVzEbsBQxCnEyT6RDmA== X-Google-Smtp-Source: ABdhPJzaO/47+UZJw7Q+LaPQKbXS6ij52t+6WN/UvNVwlxja00Sw4oWc9A9MUYvt4fIoPN92f9KsTw== X-Received: by 2002:a05:6214:9a7:: with SMTP id du7mr2389956qvb.21.1603809342215; Tue, 27 Oct 2020 07:35:42 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id 19sm780704qki.33.2020.10.27.07.35.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Oct 2020 07:35:41 -0700 (PDT) To: libc-alpha@sourceware.org Subject: [PATCH v2 4/4] stdlib: Remove lstat usage from realpath [BZ #24970] Date: Tue, 27 Oct 2020 11:35:31 -0300 Message-Id: <20201027143531.2448132-4-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201027143531.2448132-1-adhemerval.zanella@linaro.org> References: <20201027143531.2448132-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-14.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Reply-To: Adhemerval Zanella Cc: Andreas Schwab Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" The readlink already tells whether the file is a symlink, so there is no need to call lstat to check it. However for '..' it requires an extra readlink check if the previous component can be really accessed, otherwise the next iteration will check a possible valid path and end early. It should performance-wise acceptable and a gain over lstat, afaik symlink should not update any inode information. Checked on x86_64-linux-gnu and i686-linux-gnu. --- stdlib/canonicalize.c | 52 ++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c index 9aa69676e4..952f4dca41 100644 --- a/stdlib/canonicalize.c +++ b/stdlib/canonicalize.c @@ -55,6 +55,7 @@ __realpath (const char *name, char *resolved) const char *start, *end, *rpath_limit; const size_t path_max = PATH_MAX; int num_links = 0; + char buf[PATH_MAX]; char extra_buf[PATH_MAX]; if (name == NULL) @@ -104,12 +105,6 @@ __realpath (const char *name, char *resolved) for (end = start; *start; start = end) { -#ifdef _LIBC - struct stat64 st; -#else - struct stat st; -#endif - /* Skip sequence of multiple path-separators. */ while (*start == '/') ++start; @@ -118,12 +113,25 @@ __realpath (const char *name, char *resolved) for (end = start; *end && *end != '/'; ++end) /* Nothing. */; - if (end - start == 0) - break; - else if (end - start == 1 && start[0] == '.') + if (end - start == 1 && start[0] == '.') /* nothing */; else if (end - start == 2 && start[0] == '.' && start[1] == '.') { + ssize_t n; + + if (dest[-1] != '/') + *dest++ = '/'; + *dest = '\0'; + + n = __readlink (rpath, buf, path_max - 1); + if (n == -1) + { + if (errno == ENOTDIR && dest[-1] == '/') + dest[-1] = '\0'; + if (errno != EINVAL) + goto error; + } + /* Back up to previous component, ignore if at root already. */ if (dest > rpath + 1) for (--dest; dest > rpath && dest[-1] != '/'; --dest) @@ -132,6 +140,7 @@ __realpath (const char *name, char *resolved) else { size_t new_size; + ssize_t n; if (dest[-1] != '/') *dest++ = '/'; @@ -166,25 +175,23 @@ __realpath (const char *name, char *resolved) dest = __mempcpy (dest, start, end - start); *dest = '\0'; - if (__lstat64 (rpath, &st) < 0) - goto error; - - if (S_ISLNK (st.st_mode)) + n = __readlink (rpath, buf, path_max - 1); + if (n < 0) + { + if (errno == ENOTDIR && dest[-1] == '/') + dest[-1] = '\0'; + if (errno != EINVAL) + goto error; + } + else { - char buf[PATH_MAX]; size_t len; - ssize_t n; if (++num_links > __eloop_threshold ()) { __set_errno (ELOOP); goto error; } - n = __readlink (rpath, buf, path_max - 1); - if (n < 0) - goto error; - buf[n] = '\0'; - len = strlen (end); /* Check that n + len + 1 doesn't overflow and is <= path_max. */ if (n >= SIZE_MAX - len || n + len >= path_max) @@ -211,11 +218,6 @@ __realpath (const char *name, char *resolved) continue; } } - else if (!S_ISDIR (st.st_mode) && *end != '\0') - { - __set_errno (ENOTDIR); - goto error; - } } } if (dest > rpath + 1 && dest[-1] == '/')