From nobody Wed Jul 30 09:31:56 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 4bsRn83n91z63PyD; Wed, 30 Jul 2025 09:31:56 +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 "R10" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4bsRn831Fyz46Bx; Wed, 30 Jul 2025 09:31:56 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1753867916; 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=Pip+AjgLGal9WVLQ4EIrEBf8SB/uyS0uOIIkwabNsu4=; b=hn+uedkCu/mlxKGVKXzhfDT8YuyD7ZF4oTEUvxsnD80nm8ZZlC36NbpiO4gvQkRDCO+PfK Js8YqgT03LqntSz78LRySMfZTPtNF+7u3hyJBUiv/+LwxajQBVvDaKUtBOjZszBqCO8Sly hc4mnGrYSkH2LsbMp0u/Ksd1/C3xdq+u2d8iASRox8gS+btfsgQzl1EapsPdPcbuhsJ3+v ir18lyU6hHeQ+jxMahKqcqSGMN6vv58pGsfXbuOhJUJrVOahNfoOgyIH76ByAslOfU+sGx cp/V4JfCZX8wnVeJGdQ9QFILWd+1bfo2TI1Y9EPn0bcnOCAiRGzqEYi6mCkSEg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1753867916; 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=Pip+AjgLGal9WVLQ4EIrEBf8SB/uyS0uOIIkwabNsu4=; b=SLqY8Na/2Y2Qrlb8AO5XYuExMoDQdmsUUzMb8aBNMK/pedkqNmVe99Ur/cqZB8y+1Gx6yg cY9d+Ma7qnqAdw1NifyI6E4H7Rn/aP65RjNRlDc0Tbtjq3iGNlZJ6hRdUvirSqwuC9snZo SavLrmhfqEqb4kyrUCee7bPjZuIn7rCBCGNwBlYt1C39d8eSUJkM/XpI+TOQZ7b4GvQGGU bGPXE5GqJi18hbgrirgsVUCt3b7FsE1BL+y0KKmzBCCyu7rywQcrQliWcI0p5HG39pWr7t g0RHuQsL4w4aAmp5dWN73bEF56ukah6/GNVF0biJ2eEjEN+riWVGHGrnRcS5cg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1753867916; a=rsa-sha256; cv=none; b=kNmTSRZYHv3mbN3p//B5EK2bfxrLCdB59jAOh5V40vVuCxq5+VTwJcEtgWuUJt0N4gr4tf W6iRCskApR/KAmTsVtLp49RCzKJ/sguPWua6gAyf8P6Rhhsc5gXh9MjZywL9D29XripGMs hsS5mu0oVWipcaK10UKp/8jrUp50+ICCXoxIjCYG8uOUMgAgv4lgpHi8PzWDRplAVa9KNU YcUBzpinVQbuzpbUBYpPg1PG8wb3elh9h3TiGCsZvQuj3ZRhc4qq4onK+xuStqF8VNjCVf F/1w+r0V1Jyuxho3hhZr/FeIWoYNKuu8El9sfVlDnoDGWoNy7Tsg4czlbJLh7Q== 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 4bsRn82KwMz19G4; Wed, 30 Jul 2025 09:31:56 +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 56U9Vuf6083287; Wed, 30 Jul 2025 09:31:56 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 56U9Vu8Q083284; Wed, 30 Jul 2025 09:31:56 GMT (envelope-from git) Date: Wed, 30 Jul 2025 09:31:56 GMT Message-Id: <202507300931.56U9Vu8Q083284@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Bojan =?utf-8?Q?Novkovi=C4=87?= Subject: git: 14598537acec - main - db/hash.c: Allow O_WRONLY in dbm_open 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: bnovkov X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 14598537acecb512432e33e001762c912cc25799 Auto-Submitted: auto-generated The branch main has been updated by bnovkov: URL: https://cgit.FreeBSD.org/src/commit/?id=14598537acecb512432e33e001762c912cc25799 commit 14598537acecb512432e33e001762c912cc25799 Author: Bojan Novković AuthorDate: 2025-07-25 09:01:52 +0000 Commit: Bojan Novković CommitDate: 2025-07-30 09:31:16 +0000 db/hash.c: Allow O_WRONLY in dbm_open The dbm(3) manpage explicitly states that O_WRONLY is not allowed in dbm_open, but a more recent comment in ` __hash_open` suggests otherwise. Furthermore, POSIX.1 allows O_WRONLY in dbm_open and states that the underlying file must be opened for both reading and writing. Fix this by correcting the O_WRONLY check and moving it further into the function to make sure that the original flags are stored in hashp. Sponsored by: Klara, Inc. Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D51514 --- lib/libc/db/hash/hash.c | 15 +++--- lib/libc/db/man/dbm.3 | 5 +- lib/libc/db/man/dbopen.3 | 5 +- lib/libc/tests/db/Makefile | 1 + lib/libc/tests/db/dbm_open_test.c | 23 ++++++--- lib/libc/tests/db/dbm_perm_test.c | 98 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 126 insertions(+), 21 deletions(-) diff --git a/lib/libc/db/hash/hash.c b/lib/libc/db/hash/hash.c index cc96fb5ce326..1eb01ee0f0c5 100644 --- a/lib/libc/db/hash/hash.c +++ b/lib/libc/db/hash/hash.c @@ -99,11 +99,6 @@ __hash_open(const char *file, int flags, int mode, DB *dbp; int bpages, hdrsize, new_table, nsegs, save_errno; - if ((flags & O_ACCMODE) == O_WRONLY) { - errno = EINVAL; - return (NULL); - } - if (!(hashp = (HTAB *)calloc(1, sizeof(HTAB)))) return (NULL); hashp->fp = -1; @@ -115,6 +110,10 @@ __hash_open(const char *file, int flags, int mode, * we can check accesses. */ hashp->flags = flags; + if ((flags & O_ACCMODE) == O_WRONLY) { + flags &= ~O_WRONLY; + flags |= O_RDWR; + } if (file) { if ((hashp->fp = _open(file, flags | O_CLOEXEC, mode)) == -1) @@ -180,7 +179,7 @@ __hash_open(const char *file, int flags, int mode, __buf_init(hashp, DEF_BUFSIZE); hashp->new_file = new_table; - hashp->save_file = file && (hashp->flags & O_RDWR); + hashp->save_file = file && (flags & O_RDWR); hashp->cbucket = -1; if (!(dbp = (DB *)malloc(sizeof(DB)))) { save_errno = errno; @@ -524,6 +523,10 @@ hash_get(const DB *dbp, const DBT *key, DBT *data, u_int32_t flag) hashp->error = errno = EINVAL; return (ERROR); } + if ((hashp->flags & O_ACCMODE) == O_WRONLY) { + hashp->error = errno = EPERM; + return (ERROR); + } return (hash_access(hashp, HASH_GET, (DBT *)key, data)); } diff --git a/lib/libc/db/man/dbm.3 b/lib/libc/db/man/dbm.3 index c5a83c7acef4..30787600ad2d 100644 --- a/lib/libc/db/man/dbm.3 +++ b/lib/libc/db/man/dbm.3 @@ -13,7 +13,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd April 2, 2022 +.Dd July 25, 2025 .Dt DBM 3 .Os .Sh NAME @@ -99,9 +99,6 @@ is a typical value for .Li 0660 is a typical value for .Fa mode . -.Dv O_WRONLY -is not allowed in -.Fa flags . The pointer returned by .Fn dbm_open identifies the database and is the diff --git a/lib/libc/db/man/dbopen.3 b/lib/libc/db/man/dbopen.3 index 64cef88506d8..7fe515f17849 100644 --- a/lib/libc/db/man/dbopen.3 +++ b/lib/libc/db/man/dbopen.3 @@ -76,13 +76,10 @@ are as specified to the .Xr open 2 routine, however, only the .Dv O_CREAT , O_EXCL , O_EXLOCK , O_NOFOLLOW , O_NONBLOCK , -.Dv O_RDONLY , O_RDWR , O_SHLOCK , O_SYNC +.Dv O_RDONLY , O_RDWR , O_SHLOCK , O_SYNC, O_WRONLY, and .Dv O_TRUNC flags are meaningful. -(Note, opening a database file -.Dv O_WRONLY -is not possible.) .\"Three additional options may be specified by .\".Em or Ns 'ing .\"them into the diff --git a/lib/libc/tests/db/Makefile b/lib/libc/tests/db/Makefile index 54b38b94a581..cc181cc81160 100644 --- a/lib/libc/tests/db/Makefile +++ b/lib/libc/tests/db/Makefile @@ -8,6 +8,7 @@ PROGS+= h_lfsr ${PACKAGE}FILES+= README ATF_TESTS_C+= dbm_open_test +ATF_TESTS_C+= dbm_perm_test NETBSD_ATF_TESTS_C+= db_hash_seq_test NETBSD_ATF_TESTS_SH+= db_test diff --git a/lib/libc/tests/db/dbm_open_test.c b/lib/libc/tests/db/dbm_open_test.c index 18d398e16b2a..8a3e888bf72c 100644 --- a/lib/libc/tests/db/dbm_open_test.c +++ b/lib/libc/tests/db/dbm_open_test.c @@ -4,14 +4,15 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include - #include #include #include #include +static const char *path = "tmp"; +static const char *dbname = "tmp.db"; + ATF_TC(dbm_open_missing_test); ATF_TC_HEAD(dbm_open_missing_test, tc) { @@ -21,23 +22,31 @@ ATF_TC_HEAD(dbm_open_missing_test, tc) ATF_TC_BODY(dbm_open_missing_test, tc) { - const char *path = "tmp"; - const char *dbname = "tmp.db"; /* * POSIX.1 specifies that a missing database file should * always get created if O_CREAT is present, except when * O_EXCL is specified as well. */ - ATF_CHECK(dbm_open(path, O_RDONLY, _PROT_ALL) == NULL); + ATF_CHECK(dbm_open(path, O_RDONLY, 0755) == NULL); + ATF_REQUIRE(!atf_utils_file_exists(dbname)); + ATF_CHECK(dbm_open(path, O_RDONLY | O_CREAT, 0755) != NULL); + ATF_REQUIRE(atf_utils_file_exists(dbname)); + ATF_CHECK(dbm_open(path, O_RDONLY | O_CREAT | O_EXCL, 0755) == NULL); +} + +ATF_TC_WITHOUT_HEAD(dbm_open_wronly_test); +ATF_TC_BODY(dbm_open_wronly_test, tc) +{ + ATF_CHECK(dbm_open(path, O_WRONLY, 0755) == NULL); ATF_REQUIRE(!atf_utils_file_exists(dbname)); - ATF_CHECK(dbm_open(path, O_RDONLY | O_CREAT, _PROT_ALL) != NULL); + ATF_CHECK(dbm_open(path, O_WRONLY | O_CREAT, 0755) != NULL); ATF_REQUIRE(atf_utils_file_exists(dbname)); - ATF_CHECK(dbm_open(path, O_RDONLY | O_CREAT | O_EXCL, _PROT_ALL) == NULL); } ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, dbm_open_missing_test); + ATF_TP_ADD_TC(tp, dbm_open_wronly_test); return (atf_no_error()); } diff --git a/lib/libc/tests/db/dbm_perm_test.c b/lib/libc/tests/db/dbm_perm_test.c new file mode 100644 index 000000000000..c07210292014 --- /dev/null +++ b/lib/libc/tests/db/dbm_perm_test.c @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + +#include + +static const char *path = "tmp"; +static const char *dbname = "tmp.db"; + +static void +create_db(void) +{ + DB *db; + datum data, key; + + data.dptr = "bar"; + data.dsize = strlen("bar"); + key.dptr = "foo"; + key.dsize = strlen("foo"); + + db = dbm_open(path, O_RDWR | O_CREAT, 0755); + ATF_CHECK(db != NULL); + ATF_REQUIRE(atf_utils_file_exists(dbname)); + ATF_REQUIRE(dbm_store(db, key, data, DBM_INSERT) != -1); + dbm_close(db); +} + +ATF_TC_WITHOUT_HEAD(dbm_rdonly_test); +ATF_TC_BODY(dbm_rdonly_test, tc) +{ + DB *db; + datum data, key; + + bzero(&data, sizeof(data)); + key.dptr = "foo"; + key.dsize = strlen("foo"); + create_db(); + + db = dbm_open(path, O_RDONLY, 0755); + data = dbm_fetch(db, key); + ATF_REQUIRE(data.dptr != NULL); + ATF_REQUIRE(strncmp((const char*)data.dptr, "bar", data.dsize) == 0); + ATF_REQUIRE(dbm_store(db, key, data, DBM_REPLACE) == -1); + ATF_REQUIRE(errno == EPERM); +} + +ATF_TC_WITHOUT_HEAD(dbm_wronly_test); +ATF_TC_BODY(dbm_wronly_test, tc) +{ + DB *db; + datum data, key; + + key.dptr = "foo"; + key.dsize = strlen("foo"); + data.dptr = "baz"; + data.dsize = strlen("baz"); + create_db(); + + db = dbm_open(path, O_WRONLY, 0755); + data = dbm_fetch(db, key); + ATF_REQUIRE(data.dptr == NULL); + ATF_REQUIRE(errno == EPERM); + ATF_REQUIRE(dbm_store(db, key, data, DBM_REPLACE) != -1); +} + +ATF_TC_WITHOUT_HEAD(dbm_rdwr_test); +ATF_TC_BODY(dbm_rdwr_test, tc) +{ + DB *db; + datum data, key; + + key.dptr = "foo"; + key.dsize = strlen("foo"); + create_db(); + + db = dbm_open(path, O_RDWR, 0755); + data = dbm_fetch(db, key); + ATF_REQUIRE(data.dptr != NULL); + data.dptr = "baz"; + data.dsize = strlen("baz"); + ATF_REQUIRE(dbm_store(db, key, data, DBM_REPLACE) != -1); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, dbm_rdonly_test); + ATF_TP_ADD_TC(tp, dbm_wronly_test); + ATF_TP_ADD_TC(tp, dbm_rdwr_test); + + return (atf_no_error()); +}