gbranden pushed a commit to branch master
in repository groff.

commit 834afa4e0d80ff8b27b25e6aaee7ed17bcadf1fb
Author: G. Branden Robinson <[email protected]>
AuthorDate: Sat Jul 13 13:09:21 2024 -0500

    [libgroff]: Fix Savannah #65980 (open directory).
    
    * src/libs/libgroff/searchpath.cpp (is_directory): New function uses
      stat(2) to check file name argument to see if it's a directory, and
      returns a Boolean.
    
      (search_path::open_file):
      (search_path::open_file_cautious): Use `is_directory()` before
      attempting to `fopen()` a file specification; fail and set `errno` to
      `EISDIR` if it's a directory so that the caller reports a useful
      diagnostic.
    
    * bootstrap.conf: Add gnulib `stat` module, because the story of
      POSIX and non-POSIX systems alike trying and failing to sensibly
      implement the fundamental Unix file system model is a sorry tale of
      indifference and self-owns by rock star programmers.  (Seriously, read
      the "sys/stat.h" and "stat" sections of the gnulib manual.)
    
    Fixes <https://savannah.gnu.org/bugs/?65980>.  Thanks to Dave Kemper for
    the report.
---
 ChangeLog                        | 21 +++++++++++++++++++++
 bootstrap.conf                   |  1 +
 src/libs/libgroff/searchpath.cpp | 34 +++++++++++++++++++++++++++++++++-
 3 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index 59b7091e0..38817d964 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2024-07-13  G. Branden Robinson <[email protected]>
+
+       * src/libs/libgroff/searchpath.cpp (is_directory): New function
+       uses stat(2) to check file name argument to see if it's a
+       directory, and returns a Boolean.
+       (search_path::open_file):
+       (search_path::open_file_cautious): Use `is_directory()` before
+       attempting to `fopen()` a file specification; fail and set
+       `errno` to `EISDIR` if it's a directory so that the caller
+       reports a useful diagnostic.
+
+       * bootstrap.conf: Add gnulib `stat` module, because the story of
+       POSIX and non-POSIX systems alike trying and failing to sensibly
+       implement the fundamental Unix file system model is a sorry tale
+       of indifference and self-owns by rock star programmers.
+       {Seriously, read the "sys/stat.h" and "stat" sections of the
+       gnulib manual.}
+
+       Fixes <https://savannah.gnu.org/bugs/?65980>.  Thanks to Dave
+       Kemper for the report.
+
 2024-07-13  G. Branden Robinson <[email protected]>
 
        * tmac/an-ext.tmac: Fix incomplete changes to support `YS` with
diff --git a/bootstrap.conf b/bootstrap.conf
index aa96ac6df..20bee83f1 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -43,6 +43,7 @@ gnulib_modules="
     fprintf-posix
     snprintf
     vsnprintf
+    stat
     stdbool-c99
     stdint
     sys_wait
diff --git a/src/libs/libgroff/searchpath.cpp b/src/libs/libgroff/searchpath.cpp
index 0fc465b28..f11ef2295 100644
--- a/src/libs/libgroff/searchpath.cpp
+++ b/src/libs/libgroff/searchpath.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 1989-2020 Free Software Foundation, Inc.
+/* Copyright (C) 1989-2024 Free Software Foundation, Inc.
      Written by James Clark ([email protected])
 
 This file is part of groff.
@@ -26,6 +26,11 @@ along with this program.  If not, see 
<http://www.gnu.org/licenses/>. */
 #include <errno.h>
 #include <stdlib.h>
 
+// for stat(2)
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
 #include "searchpath.h"
 #include "nonposix.h"
 
@@ -35,6 +40,17 @@ along with this program.  If not, see 
<http://www.gnu.org/licenses/>. */
 # define relocate(path) strsave(path)
 #endif
 
+static bool is_directory(const char *name)
+{
+  struct stat statbuf;
+  // If stat() fails, a later fopen() will fail anyway (he said
+  // TOCTTOUishly).
+  if ((stat(name, &statbuf) == 0)
+      && ((statbuf.st_mode & S_IFMT) == S_IFDIR))
+    return true;
+  return false;
+}
+
 search_path::search_path(const char *envvar, const char *standard,
                         int add_home, int add_current)
 {
@@ -99,6 +115,10 @@ FILE *search_path::open_file(const char *name, char **pathp)
 {
   assert(name != 0 /* nullptr */);
   if (IS_ABSOLUTE(name) || *dirs == '\0') {
+    if (is_directory(name)) {
+      errno = EISDIR;
+      return 0 /* nullptr */;
+    }
     FILE *fp = fopen(name, "r");
     if (fp != 0 /* nullptr */) {
       if (pathp != 0 /* nullptr */)
@@ -128,6 +148,10 @@ FILE *search_path::open_file(const char *name, char 
**pathp)
 #if 0
     fprintf(stderr, "trying '%s'\n", path);
 #endif
+    if (is_directory(name)) {
+      errno = EISDIR;
+      return 0 /* nullptr */;
+    }
     FILE *fp = fopen(path, "r");
     int err = errno;
     if (fp != 0 /* nullptr */) {
@@ -160,6 +184,10 @@ FILE *search_path::open_file_cautious(const char *name, 
char **pathp,
     return (reading ? stdin : stdout);
   }
   if (!reading || IS_ABSOLUTE(name) || *dirs == '\0') {
+    if (is_directory(name)) {
+      errno = EISDIR;
+      return 0 /* nullptr */;
+    }
     FILE *fp = fopen(name, mode);
     if (fp != 0 /* nullptr */) {
       if (pathp != 0 /* nullptr */)
@@ -190,6 +218,10 @@ FILE *search_path::open_file_cautious(const char *name, 
char **pathp,
 #if 0
     fprintf(stderr, "trying '%s'\n", path);
 #endif
+    if (is_directory(name)) {
+      errno = EISDIR;
+      return 0 /* nullptr */;
+    }
     FILE *fp = fopen(path, mode);
     int err = errno;
     if (fp != 0 /* nullptr */) {

_______________________________________________
Groff-commit mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/groff-commit

Reply via email to