From nobody Thu Oct 30 23:52:37 2025 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4cyLWp506Jz6FnjG; Thu, 30 Oct 2025 23:52:38 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4cyLWn3HBqz3cV5; Thu, 30 Oct 2025 23:52:37 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1761868357; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=NfnqEbxQnHBjVphEstCUdOnpFQ3BWCNaU3wrdA8CSls=; b=SAlue8S3P6WOIaW8IEVbHwV0ia18p64ElAjnjfqjJU5mtH1mMIUKITjKVItZ1x/488c2Sn Gx+NZXk3i6t7aoVgHzFHgadZBjGqa9U9rFqPPKGR/Gmx5bCzQCon0e8l4WhCCBO9JKh1cw XyHPYZitI0wTFBE98HT1nPxrDzw/URlZAn/QP7x2V5a3wsZoAi41uNLDN0i+vzJ1VASCel 2MhSvYntjvlf0h9wSHaujTT8l+jiPRmxxxqEgxb2qKb5EuKeCFrVgKOfyl9Xq8R9dSvYao Pn6c2RoYAXgbAOHv8eRobfXniH2Lj6k/BjjYlyCP17zLKo4lg+TweqoweFLfnQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1761868357; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=NfnqEbxQnHBjVphEstCUdOnpFQ3BWCNaU3wrdA8CSls=; b=UYkUGNEcnM8um/FsiXYee0YVdqrXaEDM4mbAVK2ywCUlcHysOV4mirTMkClk0mJ/XzZKsR Ey5/YjiGxdMyZk581O5gYTmoY3PP9zOGc0aM+bAYROeq4i6Yt7ZuFHMJOOYu+VWhyQtkzW +LprA3/CK80SwW7A0YwVnSGIYnJrty43JF9T1kfqfBueS31MKlmQgPPMGDQrgp7E7imMLw OuBZWfdgwRxHfhd8aMtbFV5rnuBQ0yaht0pMPmuTa8fNfg9o4CyrEFVZnWEbtdBzv6s8Mm 3BqYNz5Bszr8xeur8CBwO5X5ZrUkohQ8wIowMPtFXCVC3jvA1wfarEJuF0YRxw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1761868357; a=rsa-sha256; cv=none; b=tsvpmG+GIvBJ/aNxlGOENpI3oc2kPGR4yH32HqeXSFqKBahm15a5vLSyNLRgcTmBFsE9pU aNvL2KNof3FcJdgIIau8nTyMkUxYSvLAk6A5UsnAd/wfPF7miP+ZDhjmlrxw0mY43Gjhci 0jkpZrzKZ1xb5hFTjeF/fVL/6UVGbEta6lqfwHevysTzwPVr4Xwo7JRJWyObTvjwfUMjZE PXjnJndbH57gvCqw+VR7HBBNc4y23JRi4OL9ZGEX2kKHryBpJ7+cSz0dXzsBNW2QsyiPnn Ax591Mg6itqdFf+NGlQ9WojBTvR2Fn28ksqJ7480tpi1WzZmotaBvpVqtqjkDg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4cyLWn2q9RzkxP; Thu, 30 Oct 2025 23:52:37 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 59UNqbNV088439; Thu, 30 Oct 2025 23:52:37 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 59UNqbE6088436; Thu, 30 Oct 2025 23:52:37 GMT (envelope-from git) Date: Thu, 30 Oct 2025 23:52:37 GMT Message-Id: <202510302352.59UNqbE6088436@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Colin Percival Subject: git: 4dc6fd2b9bab - releng/15.0 - realpath: Additional test cases List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: cperciva X-Git-Repository: src X-Git-Refname: refs/heads/releng/15.0 X-Git-Reftype: branch X-Git-Commit: 4dc6fd2b9babc2121e90d11b7ddeb306ddbbb950 Auto-Submitted: auto-generated The branch releng/15.0 has been updated by cperciva: URL: https://cgit.FreeBSD.org/src/commit/?id=4dc6fd2b9babc2121e90d11b7ddeb306ddbbb950 commit 4dc6fd2b9babc2121e90d11b7ddeb306ddbbb950 Author: Dag-Erling Smørgrav AuthorDate: 2025-10-13 11:53:04 +0000 Commit: Colin Percival CommitDate: 2025-10-30 23:49:46 +0000 realpath: Additional test cases * Passing NULL should result in EINVAL * Passing an empty path should result in ENOENT * Failure with a non-null buffer should leave a partial result. As pointed out in a comment in the test case, this reveals a discrepancy between the documentation and reality. Approved by: re (cperciva) Sponsored by: Klara, Inc. Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D53024 (cherry picked from commit f3386dfeb429faaa30a915a4a422a25e07c8bf39) (cherry picked from commit 5debbcb6b7a5a25511e8d63142fbc5e8498a8f46) --- lib/libc/tests/gen/realpath2_test.c | 113 ++++++++++++++++++++++++++++++++---- 1 file changed, 101 insertions(+), 12 deletions(-) diff --git a/lib/libc/tests/gen/realpath2_test.c b/lib/libc/tests/gen/realpath2_test.c index f89dd99cbb72..b8f951d9b10f 100644 --- a/lib/libc/tests/gen/realpath2_test.c +++ b/lib/libc/tests/gen/realpath2_test.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2017 Jan Kokemüller * All rights reserved. + * Copyright (c) 2025 Klara, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,6 +26,8 @@ */ #include +#include + #include #include #include @@ -34,6 +37,31 @@ #include +ATF_TC(realpath_null); +ATF_TC_HEAD(realpath_null, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test null input"); +} +ATF_TC_BODY(realpath_null, tc) +{ + ATF_REQUIRE_ERRNO(EINVAL, realpath(NULL, NULL) == NULL); +} + +ATF_TC(realpath_empty); +ATF_TC_HEAD(realpath_empty, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test empty input"); +} +ATF_TC_BODY(realpath_empty, tc) +{ + char resb[PATH_MAX] = ""; + + ATF_REQUIRE_EQ(0, mkdir("foo", 0755)); + ATF_REQUIRE_EQ(0, chdir("foo")); + ATF_REQUIRE_ERRNO(ENOENT, realpath("", resb) == NULL); + ATF_REQUIRE_STREQ("", resb); +} + ATF_TC(realpath_buffer_overflow); ATF_TC_HEAD(realpath_buffer_overflow, tc) { @@ -44,16 +72,11 @@ ATF_TC_HEAD(realpath_buffer_overflow, tc) ATF_TC_BODY(realpath_buffer_overflow, tc) { - char path[MAXPATHLEN] = { 0 }; - char resb[MAXPATHLEN] = { 0 }; - size_t i; + char path[PATH_MAX] = ""; + char resb[PATH_MAX] = ""; - path[0] = 'a'; + memset(path, 'a', sizeof(path) - 1); path[1] = '/'; - for (i = 2; i < sizeof(path) - 1; ++i) { - path[i] = 'a'; - } - ATF_REQUIRE(realpath(path, resb) == NULL); } @@ -66,9 +89,9 @@ ATF_TC_HEAD(realpath_empty_symlink, tc) ATF_TC_BODY(realpath_empty_symlink, tc) { - char path[MAXPATHLEN] = { 0 }; - char slnk[MAXPATHLEN] = { 0 }; - char resb[MAXPATHLEN] = { 0 }; + char path[PATH_MAX] = ""; + char slnk[PATH_MAX] = ""; + char resb[PATH_MAX] = ""; int fd; (void)strlcat(slnk, "empty_symlink", sizeof(slnk)); @@ -89,11 +112,77 @@ ATF_TC_BODY(realpath_empty_symlink, tc) ATF_REQUIRE(unlink(slnk) == 0); } -ATF_TP_ADD_TCS(tp) +ATF_TC(realpath_partial); +ATF_TC_HEAD(realpath_partial, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test that failure leaves a partial result"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} + +ATF_TC_BODY(realpath_partial, tc) { + char resb[PATH_MAX] = ""; + size_t len; + + /* scenario 1: missing directory */ + ATF_REQUIRE_EQ(0, mkdir("foo", 0755)); + ATF_REQUIRE_ERRNO(ENOENT, realpath("foo/bar/baz", resb) == NULL); + len = strnlen(resb, sizeof(resb)); + ATF_REQUIRE(len > 8 && len < sizeof(resb)); + ATF_REQUIRE_STREQ("/foo/bar", resb + len - 8); + + /* scenario 2: dead link 1 */ + ATF_REQUIRE_EQ(0, symlink("nix", "foo/bar")); + ATF_REQUIRE_ERRNO(ENOENT, realpath("foo/bar/baz", resb) == NULL); + len = strnlen(resb, sizeof(resb)); + ATF_REQUIRE(len > 8 && len < sizeof(resb)); + ATF_REQUIRE_STREQ("/foo/nix", resb + len - 8); + + /* scenario 3: missing file */ + ATF_REQUIRE_EQ(0, unlink("foo/bar")); + ATF_REQUIRE_EQ(0, mkdir("foo/bar", 0755)); + ATF_REQUIRE_ERRNO(ENOENT, realpath("foo/bar/baz", resb) == NULL); + len = strnlen(resb, sizeof(resb)); + ATF_REQUIRE(len > 12 && len < sizeof(resb)); + ATF_REQUIRE_STREQ("/foo/bar/baz", resb + len - 12); + + /* scenario 4: dead link 2 */ + ATF_REQUIRE_EQ(0, symlink("nix", "foo/bar/baz")); + ATF_REQUIRE_ERRNO(ENOENT, realpath("foo/bar/baz", resb) == NULL); + len = strnlen(resb, sizeof(resb)); + ATF_REQUIRE(len > 12 && len < sizeof(resb)); + ATF_REQUIRE_STREQ("/foo/bar/nix", resb + len - 12); + + /* scenario 5: unreadable directory */ + ATF_REQUIRE_EQ(0, chmod("foo", 000)); + ATF_REQUIRE_ERRNO(EACCES, realpath("foo/bar/baz", resb) == NULL); + len = strnlen(resb, sizeof(resb)); + ATF_REQUIRE(len > 8 && len < sizeof(resb)); + /* + * This is arguably wrong. The problem is not with bar, but with + * foo. However, since foo exists and is a directory and the only + * reliable way to detect whether a directory is readable is to + * attempt to read it, we do not detect the problem until we try + * to access bar. + */ + ATF_REQUIRE_STREQ("/foo/bar", resb + len - 8); + + /* scenario 6: not a directory */ + ATF_REQUIRE_EQ(0, close(creat("bar", 0644))); + ATF_REQUIRE_ERRNO(ENOTDIR, realpath("bar/baz", resb) == NULL); + len = strnlen(resb, sizeof(resb)); + ATF_REQUIRE(len > 4 && len < sizeof(resb)); + ATF_REQUIRE_STREQ("/bar", resb + len - 4); +} +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, realpath_null); + ATF_TP_ADD_TC(tp, realpath_empty); ATF_TP_ADD_TC(tp, realpath_buffer_overflow); ATF_TP_ADD_TC(tp, realpath_empty_symlink); + ATF_TP_ADD_TC(tp, realpath_partial); return atf_no_error(); }