git: 1176390d2d2b - main - catopen(3): align returned errors with IEEE Std 1003.1™-2024

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sun, 03 Nov 2024 17:00:27 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=1176390d2d2bbb1e207c840d1f7a66a6ac1096ff

commit 1176390d2d2bbb1e207c840d1f7a66a6ac1096ff
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2024-11-03 12:50:32 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2024-11-03 16:59:15 +0000

    catopen(3): align returned errors with IEEE Std 1003.1™-2024
    
    - Invalid/non-existent/unable to use message catalog file should result in
      ENOENT, and not in EFTYPE.
    - Added detection of several cases of wrong file format due to length [*].
    - Update man page.
    
    * Based on the original patch from PR.
    
    PR:     172805
    Reviewed by:    emaste
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D47413
---
 lib/libc/nls/catopen.3 | 13 +++++++------
 lib/libc/nls/msgcat.c  | 30 +++++++++++++++++++-----------
 2 files changed, 26 insertions(+), 17 deletions(-)

diff --git a/lib/libc/nls/catopen.3 b/lib/libc/nls/catopen.3
index 6fd50956be1f..6fb2e2522e85 100644
--- a/lib/libc/nls/catopen.3
+++ b/lib/libc/nls/catopen.3
@@ -130,16 +130,17 @@ Otherwise, (nl_catd) -1 is returned and
 is set to indicate the error.
 .Sh ERRORS
 .Bl -tag -width Er
-.It Bq Er EINVAL
-Argument
-.Fa name
-does not point to a valid message catalog, or catalog is corrupt.
 .It Bq Er ENAMETOOLONG
 An entire path to the message catalog exceeded 1024 characters.
 .It Bq Er ENOENT
-The named message catalog does not exists, or the
+Argument
 .Fa name
-argument points to an empty string.
+does not point to a valid message catalog name,
+or it points to an empty string.
+.It Bq Er ENOENT
+The named message catalog does not exist.
+.It Bq Er ENOENT
+The named message catalog file is in wrong format.
 .It Bq Er ENOMEM
 Insufficient memory is available.
 .El
diff --git a/lib/libc/nls/msgcat.c b/lib/libc/nls/msgcat.c
index 32fa191c4c67..61c09b65f434 100644
--- a/lib/libc/nls/msgcat.c
+++ b/lib/libc/nls/msgcat.c
@@ -136,7 +136,7 @@ __catopen_l(const char *name, int type, locale_t locale)
 
 	/* sanity checking */
 	if (name == NULL || *name == '\0')
-		NLRETERR(EINVAL);
+		NLRETERR(ENOENT);
 
 	if (strchr(name, '/') != NULL)
 		/* have a pathname */
@@ -390,7 +390,7 @@ load_msgcat(const char *path, const char *name, const char *lang)
 	struct catentry *np;
 	void *data;
 	char *copy_path, *copy_name, *copy_lang;
-	int fd;
+	int fd, saved_errno;
 
 	/* path/name will never be NULL here */
 
@@ -414,9 +414,17 @@ load_msgcat(const char *path, const char *name, const char *lang)
 	}
 
 	if (_fstat(fd, &st) != 0) {
+		saved_errno = errno;
 		_close(fd);
-		SAVEFAIL(name, lang, EFTYPE);
-		NLRETERR(EFTYPE);
+		SAVEFAIL(name, lang, saved_errno);
+		NLRETERR(saved_errno);
+	}
+
+	/* The file is too small to contain a _NLS_MAGIC. */
+	if (st.st_size < sizeof(u_int32_t)) {
+		_close(fd);
+		SAVEFAIL(name, lang, ENOENT);
+		NLRETERR(ENOENT);
 	}
 
 	/*
@@ -426,13 +434,13 @@ load_msgcat(const char *path, const char *name, const char *lang)
 	 */
 	if (st.st_size > SIZE_T_MAX) {
 		_close(fd);
-		SAVEFAIL(name, lang, EFBIG);
-		NLRETERR(EFBIG);
+		SAVEFAIL(name, lang, ENOENT);
+		NLRETERR(ENOENT);
 	}
 
-	if ((data = mmap(0, (size_t)st.st_size, PROT_READ,
-	    MAP_FILE|MAP_SHARED, fd, (off_t)0)) == MAP_FAILED) {
-		int saved_errno = errno;
+	data = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+	if (data == MAP_FAILED) {
+		saved_errno = errno;
 		_close(fd);
 		SAVEFAIL(name, lang, saved_errno);
 		NLRETERR(saved_errno);
@@ -442,8 +450,8 @@ load_msgcat(const char *path, const char *name, const char *lang)
 	if (ntohl((u_int32_t)((struct _nls_cat_hdr *)data)->__magic) !=
 	    _NLS_MAGIC) {
 		munmap(data, (size_t)st.st_size);
-		SAVEFAIL(name, lang, EFTYPE);
-		NLRETERR(EFTYPE);
+		SAVEFAIL(name, lang, ENOENT);
+		NLRETERR(ENOENT);
 	}
 
 	copy_name = strdup(name);