Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package restorecond for openSUSE:Factory 
checked in at 2026-07-13 14:25:14
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/restorecond (Old)
 and      /work/SRC/openSUSE:Factory/.restorecond.new.1991 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "restorecond"

Mon Jul 13 14:25:14 2026 rev:23 rq:1364572 version:3.11

Changes:
--------
--- /work/SRC/openSUSE:Factory/restorecond/restorecond.changes  2026-02-09 
11:43:32.446203314 +0100
+++ /work/SRC/openSUSE:Factory/.restorecond.new.1991/restorecond.changes        
2026-07-13 14:25:16.365684948 +0200
@@ -1,0 +2,19 @@
+Mon Jul  6 15:08:26 UTC 2026 - Cathy Hu <[email protected]>
+
+- Update to version 3.11
+  https://github.com/SELinuxProject/selinux/releases/tag/3.11
+  - User-visible changes:
+    - Improved `restorecond.service` to use new `restorecond -F` option to run 
in
+      foreground
+    - Rewrote restorecond and sandbox/seunshare to eliminate TOCTOU issues on 
their
+      other path-based operations via /proc/self/fd and the use of a 
safe_open()
+      helper.
+    - Multiple documentation improvements.
+  - Development-relevant changes:
+    - Reformatted entire tree based on .clang-format and added new
+      check-format/format make targets to check and/or reformat code to match.
+      This is now a requirement for new patches.
+- Packaging changes:
+  - Refresh harden_restorecond.service.patch to the new systemd service
+
+-------------------------------------------------------------------

Old:
----
  restorecond-3.10.tar.gz
  restorecond-3.10.tar.gz.asc

New:
----
  restorecond-3.11.tar.gz
  restorecond-3.11.tar.gz.asc

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ restorecond.spec ++++++
--- /var/tmp/diff_new_pack.V6orCb/_old  2026-07-13 14:25:18.361753196 +0200
+++ /var/tmp/diff_new_pack.V6orCb/_new  2026-07-13 14:25:18.365753332 +0200
@@ -16,9 +16,9 @@
 #
 
 
-%define libselinux_ver   3.10
+%define libselinux_ver   3.11
 Name:           restorecond
-Version:        3.10
+Version:        3.11
 Release:        0
 Summary:        Daemon to restore SELinux contexts
 License:        GPL-2.0-or-later

++++++ harden_restorecond.service.patch ++++++
--- /var/tmp/diff_new_pack.V6orCb/_old  2026-07-13 14:25:18.397754426 +0200
+++ /var/tmp/diff_new_pack.V6orCb/_new  2026-07-13 14:25:18.401754563 +0200
@@ -1,7 +1,7 @@
-Index: restorecond-3.2/restorecond.service
+Index: restorecond-3.11/restorecond.service
 ===================================================================
---- restorecond-3.2.orig/restorecond.service
-+++ restorecond-3.2/restorecond.service
+--- restorecond-3.11.orig/restorecond.service
++++ restorecond-3.11/restorecond.service
 @@ -5,6 +5,15 @@ ConditionPathExists=/etc/selinux/restore
  ConditionSecurity=selinux
  
@@ -15,7 +15,7 @@
 +ProtectControlGroups=true
 +RestrictRealtime=true
 +# end of automatic additions 
- Type=forking
- ExecStart=/usr/sbin/restorecond
- PIDFile=/run/restorecond.pid
+ Type=simple
+ ExecStart=/usr/sbin/restorecond -F
+ 
 

++++++ restorecond-3.10.tar.gz -> restorecond-3.11.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/restorecond-3.10/Makefile 
new/restorecond-3.11/Makefile
--- old/restorecond-3.10/Makefile       2026-02-02 03:01:16.000000000 +0100
+++ new/restorecond-3.11/Makefile       2026-07-01 18:51:05.000000000 +0200
@@ -18,8 +18,8 @@
 GIO_LIBS = $(shell $(PKG_CONFIG) --libs gio-2.0)
 
 CFLAGS ?= -g -Werror -Wall -W
-override CFLAGS += -I../../libselinux/include $(GIO_CFLAGS)
-override LDFLAGS+= -L../../libselinux/src
+override CFLAGS += -I../libselinux/include $(GIO_CFLAGS)
+override LDFLAGS+= -L../libselinux/src
 override LDLIBS += -lselinux $(GIO_LIBS)
 
 all: restorecond
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/restorecond-3.10/VERSION new/restorecond-3.11/VERSION
--- old/restorecond-3.10/VERSION        2026-02-02 03:01:16.000000000 +0100
+++ new/restorecond-3.11/VERSION        2026-07-01 18:51:05.000000000 +0200
@@ -1 +1 @@
-3.10
+3.11
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/restorecond-3.10/restore.c 
new/restorecond-3.11/restore.c
--- old/restorecond-3.10/restore.c      2026-02-02 03:01:16.000000000 +0100
+++ new/restorecond-3.11/restore.c      2026-07-01 18:51:05.000000000 +0200
@@ -1,16 +1,4 @@
 #include "restore.h"
-#include <glob.h>
-
-#ifndef GLOB_TILDE
-#define GLOB_TILDE 0
-#endif
-
-#ifndef GLOB_BRACE
-#define GLOB_BRACE 0
-#endif
-
-char **exclude_list;
-int exclude_count;
 
 void restore_init(struct restore_opts *opts)
 {
@@ -29,13 +17,13 @@
        }
 
        opts->restorecon_flags = 0;
-       opts->restorecon_flags = opts->nochange | opts->verbose |
-                          opts->progress | opts->set_specctx  |
-                          opts->add_assoc | opts->ignore_digest |
-                          opts->recurse | opts->userealpath |
-                          opts->xdev | opts->abort_on_error |
-                          opts->syslog_changes | opts->log_matches |
-                          opts->ignore_noent | opts->ignore_mounts;
+       opts->restorecon_flags =
+               opts->nochange | opts->verbose | opts->progress |
+               opts->set_specctx | opts->add_assoc | opts->ignore_digest |
+               opts->recurse | opts->userealpath | opts->xdev |
+               opts->abort_on_error | opts->syslog_changes |
+               opts->log_matches | opts->ignore_noent | opts->ignore_mounts |
+               opts->skip_multilink;
 
        /* Use setfiles, restorecon and restorecond own handles */
        selinux_restorecon_set_sehandle(opts->hnd);
@@ -49,80 +37,4 @@
                        exit(-1);
                }
        }
-
-       if (exclude_list)
-               selinux_restorecon_set_exclude_list
-                                                ((const char **)exclude_list);
-}
-
-void restore_finish(void)
-{
-       int i;
-
-       if (exclude_list) {
-               for (i = 0; exclude_list[i]; i++)
-                       free(exclude_list[i]);
-               free(exclude_list);
-       }
-}
-
-int process_glob(char *name, struct restore_opts *opts)
-{
-       glob_t globbuf;
-       size_t i = 0;
-       int len, rc, errors;
-
-       memset(&globbuf, 0, sizeof(globbuf));
-
-       errors = glob(name, GLOB_TILDE | GLOB_PERIOD |
-                         GLOB_NOCHECK | GLOB_BRACE, NULL, &globbuf);
-       if (errors)
-               return errors;
-
-       for (i = 0; i < globbuf.gl_pathc; i++) {
-               len = strlen(globbuf.gl_pathv[i]) - 2;
-               if (len > 0 && strcmp(&globbuf.gl_pathv[i][len--], "/.") == 0)
-                       continue;
-               if (len > 0 && strcmp(&globbuf.gl_pathv[i][len], "/..") == 0)
-                       continue;
-               rc = selinux_restorecon(globbuf.gl_pathv[i],
-                                       opts->restorecon_flags);
-               if (rc < 0)
-                       errors = rc;
-       }
-
-       globfree(&globbuf);
-
-       return errors;
-}
-
-void add_exclude(const char *directory)
-{
-       char **tmp_list;
-
-       if (directory == NULL || directory[0] != '/') {
-               fprintf(stderr, "Full path required for exclude: %s.\n",
-                           directory);
-               exit(-1);
-       }
-
-       /* Add another two entries, one for directory, and the other to
-        * terminate the list.
-        */
-       tmp_list = realloc(exclude_list, sizeof(char *) * (exclude_count + 2));
-       if (!tmp_list) {
-               fprintf(stderr, "realloc failed while excluding %s.\n",
-                           directory);
-               exit(-1);
-       }
-       exclude_list = tmp_list;
-
-       exclude_list[exclude_count] = strdup(directory);
-       if (!exclude_list[exclude_count]) {
-               fprintf(stderr, "strdup failed while excluding %s.\n",
-                           directory);
-               exit(-1);
-       }
-       exclude_count++;
-       exclude_list[exclude_count] = NULL;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/restorecond-3.10/restore.h 
new/restorecond-3.11/restore.h
--- old/restorecond-3.10/restore.h      2026-02-02 03:01:16.000000000 +0100
+++ new/restorecond-3.11/restore.h      2026-07-01 18:51:05.000000000 +0200
@@ -3,13 +3,11 @@
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE
 #endif
-#include <fts.h>
 #include <errno.h>
 #include <string.h>
 #include <stdio.h>
 #include <syslog.h>
 #include <sys/stat.h>
-#include <sepol/sepol.h>
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 #include <selinux/restorecon.h>
@@ -17,13 +15,6 @@
 #include <limits.h>
 #include <stdint.h>
 
-/*
- * STAR_COUNT is also defined in libselinux/src/selinux_restorecon.c where it
- * is used to output "*" for each number of files processed. Defined here for
- * inclusion in man pages.
-*/
-#define STAR_COUNT 1000
-
 /* Things that need to be init'd */
 struct restore_opts {
        unsigned int nochange;
@@ -40,6 +31,7 @@
        unsigned int log_matches;
        unsigned int ignore_noent;
        unsigned int ignore_mounts;
+       unsigned int skip_multilink;
        /* restorecon_flags holds | of above for restore_init() */
        unsigned int restorecon_flags;
        char *rootpath;
@@ -53,9 +45,5 @@
 };
 
 void restore_init(struct restore_opts *opts);
-void restore_finish(void);
-void add_exclude(const char *directory);
-int process_glob(char *name, struct restore_opts *opts);
-extern char **exclude_list;
 
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/restorecond-3.10/restorecond.8 
new/restorecond-3.11/restorecond.8
--- old/restorecond-3.10/restorecond.8  2026-02-02 03:01:16.000000000 +0100
+++ new/restorecond-3.11/restorecond.8  2026-07-01 18:51:05.000000000 +0200
@@ -3,7 +3,7 @@
 restorecond \- daemon that watches for file creation and then sets the default 
SELinux file context
 
 .SH "SYNOPSIS"
-.B restorecond  [\-d] [-h] [\-f restorecond_file ] [\-u] [\-v]
+.B restorecond  [\-d] [-h] [\-f restorecond_file ] [\-F] [\-u] [\-v]
 .P
 
 .SH "DESCRIPTION"
@@ -26,6 +26,9 @@
 .B \-f restorecond_file
 Use alternative restorecond.conf file.
 .TP
+.B \-F
+Run in foreground, do not become a daemon.
+.TP
 .B \-u
 Turns on user mode.  Runs restorecond in the user session and reads 
/etc/selinux/restorecond_user.conf.  Uses dbus to make sure only one 
restorecond is running per user session.
 .TP
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/restorecond-3.10/restorecond.c 
new/restorecond-3.11/restorecond.c
--- old/restorecond-3.10/restorecond.c  2026-02-02 03:01:16.000000000 +0100
+++ new/restorecond-3.11/restorecond.c  2026-07-01 18:51:05.000000000 +0200
@@ -65,8 +65,8 @@
 const char *homedir;
 static int master_fd = -1;
 
-static const char *server_watch_file  = "/etc/selinux/restorecond.conf";
-static const char *user_watch_file  = "/etc/selinux/restorecond_user.conf";
+static const char *server_watch_file = "/etc/selinux/restorecond.conf";
+static const char *user_watch_file = "/etc/selinux/restorecond_user.conf";
 static const char *watch_file;
 struct restore_opts r_opts;
 
@@ -76,8 +76,10 @@
 int terminate = 0;
 int master_wd = -1;
 int run_as_user = 0;
+int foreground_mode = 0;
 
-static void done(void) {
+static void done(void)
+{
        watch_list_free(master_fd);
        close(master_fd);
        utmpwatcher_free();
@@ -94,17 +96,18 @@
        len = snprintf(val, sizeof(val), "%u\n", getpid());
        if (len < 0) {
                syslog(LOG_ERR, "Pid error (%s)", strerror(errno));
-               pidfile = 0;
+               pidfile = NULL;
                return 1;
        }
        pidfd = open(pidfile, O_CREAT | O_TRUNC | O_NOFOLLOW | O_WRONLY, 0644);
        if (pidfd < 0) {
                syslog(LOG_ERR, "Unable to set pidfile (%s)", strerror(errno));
-               pidfile = 0;
+               pidfile = NULL;
                return 1;
        }
        if (write(pidfd, val, (unsigned int)len) != len) {
-               syslog(LOG_ERR, "Unable to write to pidfile (%s)", 
strerror(errno));
+               syslog(LOG_ERR, "Unable to write to pidfile (%s)",
+                      strerror(errno));
                close(pidfd);
                return 1;
        }
@@ -115,7 +118,7 @@
 /*
  * SIGTERM handler
  */
-static void term_handler(int s __attribute__ ((unused)))
+static void term_handler(int s __attribute__((unused)))
 {
        terminate = 1;
        /* trigger a failure in the watch */
@@ -124,7 +127,8 @@
 
 static void usage(char *program)
 {
-       printf("%s [-d] [-f restorecond_file ] [-u] [-v] \n", program);
+       printf("%s [-d] [-f restorecond_file ] [-F] [-n] [-u] [-v] \n",
+              program);
 }
 
 void exitApp(const char *msg)
@@ -150,10 +154,11 @@
 
        watch_file = server_watch_file;
 
-       /* Set all options to zero/NULL except for ignore_noent & digest. */
+       /* Set all options to zero/NULL except for ignore_noent, digest, and 
skip_multilink. */
        memset(&r_opts, 0, sizeof(r_opts));
        r_opts.ignore_noent = SELINUX_RESTORECON_IGNORE_NOENTRY;
        r_opts.ignore_digest = SELINUX_RESTORECON_IGNORE_DIGEST;
+       r_opts.skip_multilink = SELINUX_RESTORECON_SKIP_MULTILINK;
 
        /* As r_opts.selabel_opt_digest = NULL, no digest will be requested. */
        restore_init(&r_opts);
@@ -164,8 +169,8 @@
        sigemptyset(&sa.sa_mask);
        sigaction(SIGTERM, &sa, NULL);
 
-       atexit( done );
-       while ((opt = getopt(argc, argv, "hdf:uv")) > 0) {
+       atexit(done);
+       while ((opt = getopt(argc, argv, "hdf:Fuv")) > 0) {
                switch (opt) {
                case 'd':
                        debug_mode = 1;
@@ -173,6 +178,9 @@
                case 'f':
                        watch_file = optarg;
                        break;
+               case 'F':
+                       foreground_mode = 1;
+                       break;
                case 'u':
                        run_as_user = 1;
                        break;
@@ -209,13 +217,14 @@
 
        read_config(master_fd, watch_file);
 
-       if (!debug_mode) {
+       if (!debug_mode && !foreground_mode) {
                if (daemon(0, 0) < 0)
                        exitApp("daemon");
+               write_pid_file();
+       } else {
+               pidfile = NULL;
        }
 
-       write_pid_file();
-
        while (watch(master_fd, watch_file) == 0) {
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/restorecond-3.10/restorecond.h 
new/restorecond-3.11/restorecond.h
--- old/restorecond-3.10/restorecond.h  2026-02-02 03:01:16.000000000 +0100
+++ new/restorecond-3.11/restorecond.h  2026-07-01 18:51:05.000000000 +0200
@@ -34,7 +34,7 @@
 extern int server(int, const char *watch_file);
 
 extern void exitApp(const char *msg) __attribute__((__noreturn__));
-extern void read_config(int fd,        const char *watch_file);
+extern void read_config(int fd, const char *watch_file);
 
 extern int watch(int fd, const char *watch_file);
 extern void watch_list_add(int inotify_fd, const char *path);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/restorecond-3.10/restorecond.service 
new/restorecond-3.11/restorecond.service
--- old/restorecond-3.10/restorecond.service    2026-02-02 03:01:16.000000000 
+0100
+++ new/restorecond-3.11/restorecond.service    2026-07-01 18:51:05.000000000 
+0200
@@ -5,9 +5,8 @@
 ConditionSecurity=selinux
 
 [Service]
-Type=forking
-ExecStart=/usr/sbin/restorecond
-PIDFile=/run/restorecond.pid
+Type=simple
+ExecStart=/usr/sbin/restorecond -F
 
 [Install]
 WantedBy=multi-user.target
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/restorecond-3.10/stringslist.c 
new/restorecond-3.11/stringslist.c
--- old/restorecond-3.10/stringslist.c  2026-02-02 03:01:16.000000000 +0100
+++ new/restorecond-3.11/stringslist.c  2026-07-01 18:51:05.000000000 +0200
@@ -38,9 +38,9 @@
        while (ptr) {
                int cmp = strcmp(string, ptr->string);
                if (cmp < 0)
-                       break;  /* Not on list break out to add */
+                       break; /* Not on list break out to add */
                if (cmp == 0)
-                       return; /* Already on list */
+                       return; /* Already on list */
                prev = ptr;
                ptr = ptr->next;
        }
@@ -62,8 +62,8 @@
        while (ptr) {
                *exact = strcmp(ptr->string, string) == 0;
                int cmp = fnmatch(ptr->string, string, 0);
-               if (cmp == 0) 
-                       return 0;       /* Match found */
+               if (cmp == 0)
+                       return 0; /* Match found */
                ptr = ptr->next;
        }
        return -1;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/restorecond-3.10/user.c new/restorecond-3.11/user.c
--- old/restorecond-3.10/user.c 2026-02-02 03:01:16.000000000 +0100
+++ new/restorecond-3.11/user.c 2026-07-01 18:51:05.000000000 +0200
@@ -64,8 +64,7 @@
 }
 
 static void on_name_lost(GDBusConnection *connection G_GNUC_UNUSED,
-                        const gchar *name,
-                        gpointer user_data)
+                        const gchar *name, gpointer user_data)
 {
        /* Exit when the D-Bus connection closes */
        GMainLoop *loop = user_data;
@@ -88,14 +87,10 @@
        if (!bus)
                return -1;
 
-       client_id = g_bus_own_name_on_connection(
-               bus,
-               DBUS_NAME,
-               G_BUS_NAME_OWNER_FLAGS_NONE,
-               on_name_acquired,
-               on_name_lost,
-               loop,
-               NULL);
+       client_id = g_bus_own_name_on_connection(bus, DBUS_NAME,
+                                                G_BUS_NAME_OWNER_FLAGS_NONE,
+                                                on_name_acquired, on_name_lost,
+                                                loop, NULL);
        g_object_unref(bus);
        if (client_id == 0)
                return -1;
@@ -106,70 +101,88 @@
 #endif
 
 /* size of the event structure, not counting name */
-#define EVENT_SIZE  (sizeof (struct inotify_event))
+#define EVENT_SIZE (sizeof(struct inotify_event))
 /* reasonable guess as to size of 1024 events */
-#define BUF_LEN        (1024 * (EVENT_SIZE + 16))
+#define BUF_LEN (1024 * (EVENT_SIZE + 16))
 
-static gboolean
-io_channel_callback
- (GIOChannel *source,
-  GIOCondition condition,
-  gpointer data __attribute__((__unused__)))
-{
-
-  char buffer[BUF_LEN+1];
-  gsize bytes_read;
-  unsigned int i = 0;
-
-  if (condition & G_IO_IN) {
-    /* Data is available. */
-    g_io_channel_read_chars
-      (source, buffer,
-       sizeof (buffer),
-       &bytes_read, NULL);
-
-    if (! bytes_read) {
-           /* Session/Terminal Ended */
-           exit(0);
-    }
-
-    while (i < bytes_read) {
-           struct inotify_event *event;
-           event = (struct inotify_event *)&buffer[i];
-           if (debug_mode)
-                   printf("wd=%d mask=%u cookie=%u len=%u\n",
-                          event->wd, event->mask,
-                          event->cookie, event->len);
-           if (event->len)
-                   watch_list_find(event->wd, event->name);
-
-           i += EVENT_SIZE + event->len;
-    }
-  }
+static gboolean io_channel_callback(GIOChannel *source, GIOCondition condition,
+                                   gpointer data __attribute__((__unused__)))
+{
+       char buffer[BUF_LEN + 1];
+       gsize bytes_read;
+       unsigned int i = 0;
+
+       if (condition & G_IO_IN) {
+               /* Data is available. */
+               g_io_channel_read_chars(source, buffer, sizeof(buffer),
+                                       &bytes_read, NULL);
+
+               if (!bytes_read) {
+                       /* Session/Terminal Ended */
+                       exit(0);
+               }
+
+               while (i < bytes_read) {
+                       struct inotify_event *event;
+                       event = (struct inotify_event *)&buffer[i];
+                       if (debug_mode)
+                               printf("wd=%d mask=%u cookie=%u len=%u\n",
+                                      event->wd, event->mask, event->cookie,
+                                      event->len);
+                       if (event->len)
+                               watch_list_find(event->wd, event->name);
+
+                       i += EVENT_SIZE + event->len;
+               }
+       }
 
-  /* An error happened while reading
+       /* An error happened while reading
      the file. */
 
-  if (condition & G_IO_NVAL)
-    return FALSE;
+       if (condition & G_IO_NVAL)
+               return FALSE;
 
-  /* We have reached the end of the
+       /* We have reached the end of the
      file. */
 
-  if (condition & G_IO_HUP) {
-    g_io_channel_shutdown (source, 0, NULL);
-    exit(0);
-    return FALSE;
-  }
+       if (condition & G_IO_HUP) {
+               g_io_channel_shutdown(source, 0, NULL);
+               exit(0);
+               return FALSE;
+       }
 
-  /* Returning TRUE will make sure
+       /* Returning TRUE will make sure
      the callback remains associated
      to the channel. */
 
-  return TRUE;
+       return TRUE;
 }
 
-int start(void) {
+static gboolean stdin_callback(GIOChannel *source, GIOCondition condition,
+                              gpointer data __attribute__((__unused__)))
+{
+       char buffer[256];
+       gsize bytes_read;
+
+       if (condition & G_IO_IN) {
+               /* Data is available. */
+               while (g_io_channel_read_chars(source, buffer, sizeof(buffer),
+                                              &bytes_read,
+                                              NULL) == G_IO_STATUS_NORMAL &&
+                      bytes_read > 0)
+                       ;
+               if (bytes_read == 0)
+                       exit(0);
+       }
+
+       if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL))
+               exit(0);
+
+       return TRUE;
+}
+
+int start(void)
+{
 #ifdef HAVE_DBUS
        GDBusConnection *bus;
        GError *err = NULL;
@@ -179,7 +192,8 @@
        bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &err);
        if (!bus) {
                if (debug_mode)
-                       g_warning("Failed to connect to the D-BUS daemon: %s", 
err->message);
+                       g_warning("Failed to connect to the D-BUS daemon: %s",
+                                 err->message);
                g_error_free(err);
                return 1;
        }
@@ -188,21 +202,20 @@
         *
         * 
https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-peer
         */
-       result = g_dbus_connection_call_sync(bus,
-                                            DBUS_NAME, /* bus name */
-                                            "/", /* object path */
-                                            "org.freedesktop.DBus.Peer", /* 
interface */
-                                            "Ping", /* method */
-                                            NULL, /* parameters */
-                                            NULL, /* reply_type */
-                                            G_DBUS_CALL_FLAGS_NONE,
-                                            -1, /* timeout_msec */
-                                            NULL,
-                                            &err);
+       result = g_dbus_connection_call_sync(
+               bus, DBUS_NAME, /* bus name */
+               "/", /* object path */
+               "org.freedesktop.DBus.Peer", /* interface */
+               "Ping", /* method */
+               NULL, /* parameters */
+               NULL, /* reply_type */
+               G_DBUS_CALL_FLAGS_NONE, -1, /* timeout_msec */
+               NULL, &err);
        if (!result) {
                g_object_unref(bus);
                if (debug_mode)
-                       g_warning("Failed to start %s: %s", DBUS_NAME, 
err->message);
+                       g_warning("Failed to start %s: %s", DBUS_NAME,
+                                 err->message);
                g_error_free(err);
                return 1;
        }
@@ -211,17 +224,19 @@
        return 0;
 }
 
-static int local_server(void) {
+static int local_server(void)
+{
        // ! dbus, run as local service
-       char *ptr=NULL;
+       char *ptr = NULL;
        if (asprintf(&ptr, "%s/.restorecond", homedir) < 0) {
                if (debug_mode)
                        perror("asprintf");
                return -1;
        }
-       local_lock_fd = open(ptr, O_CREAT | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, 
S_IRUSR | S_IWUSR);
+       local_lock_fd = open(ptr, O_CREAT | O_WRONLY | O_NOFOLLOW | O_CLOEXEC,
+                            S_IRUSR | S_IWUSR);
        if (debug_mode)
-               g_warning ("Lock file: %s", ptr);
+               g_warning("Lock file: %s", ptr);
 
        free(ptr);
        if (local_lock_fd < 0) {
@@ -239,16 +254,16 @@
        /* watch for stdin/terminal going away */
        GIOChannel *in = g_io_channel_unix_new(0);
        g_io_channel_set_encoding(in, NULL, NULL);
-       g_io_channel_set_flags(in, g_io_channel_get_flags(in) | 
G_IO_FLAG_NONBLOCK, NULL);
-       g_io_add_watch_full( in,
-                            G_PRIORITY_HIGH,
-                            G_IO_IN|G_IO_ERR|G_IO_HUP,
-                            io_channel_callback, NULL, NULL);
+       g_io_channel_set_flags(
+               in, g_io_channel_get_flags(in) | G_IO_FLAG_NONBLOCK, NULL);
+       g_io_add_watch_full(in, G_PRIORITY_HIGH, G_IO_IN | G_IO_ERR | G_IO_HUP,
+                           stdin_callback, NULL, NULL);
 
        return 0;
 }
 
-static void end_local_server(void) {
+static void end_local_server(void)
+{
        if (local_lock_fd >= 0)
                close(local_lock_fd);
        local_lock_fd = -1;
@@ -264,11 +279,11 @@
        return FALSE;
 }
 
-
-int server(int master_fd, const char *watch_file) {
+int server(int master_fd, const char *watch_file)
+{
        GMainLoop *loop;
 
-       loop = g_main_loop_new (NULL, FALSE);
+       loop = g_main_loop_new(NULL, FALSE);
 
 #ifdef HAVE_DBUS
        if (dbus_server(loop) != 0)
@@ -285,25 +300,20 @@
 
        GIOChannel *c = g_io_channel_unix_new(master_fd);
        g_io_channel_set_encoding(c, NULL, NULL);
-       g_io_channel_set_flags(c, g_io_channel_get_flags(c) | 
G_IO_FLAG_NONBLOCK, NULL);
+       g_io_channel_set_flags(
+               c, g_io_channel_get_flags(c) | G_IO_FLAG_NONBLOCK, NULL);
 
-       g_io_add_watch_full(c,
-                           G_PRIORITY_HIGH,
-                           G_IO_IN|G_IO_ERR|G_IO_HUP,
+       g_io_add_watch_full(c, G_PRIORITY_HIGH, G_IO_IN | G_IO_ERR | G_IO_HUP,
                            io_channel_callback, NULL, NULL);
 
        /* Handle SIGTERM */
-       g_unix_signal_add_full(G_PRIORITY_DEFAULT,
-                              SIGTERM,
-                              sigterm_handler,
-                              loop,
-                              NULL);
+       g_unix_signal_add_full(G_PRIORITY_DEFAULT, SIGTERM, sigterm_handler,
+                              loop, NULL);
 
-       g_main_loop_run (loop);
+       g_main_loop_run(loop);
 
 end:
        end_local_server();
-       g_main_loop_unref (loop);
+       g_main_loop_unref(loop);
        return 0;
 }
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/restorecond-3.10/utmpwatcher.c 
new/restorecond-3.11/utmpwatcher.c
--- old/restorecond-3.10/utmpwatcher.c  2026-02-02 03:01:16.000000000 +0100
+++ new/restorecond-3.11/utmpwatcher.c  2026-07-01 18:51:05.000000000 +0200
@@ -49,6 +49,7 @@
 {
        int changed = 0;
        struct utmp u;
+       char name[UT_NAMESIZE + 1];
        const char *utmp_path = "/run/utmp";
        struct stringsList *prev_utmp_ptr = utmp_ptr;
        if (wd != utmp_wd)
@@ -60,15 +61,18 @@
                exitApp("Error reading utmp file.");
 
        while (fread(&u, sizeof(struct utmp), 1, cfg) > 0) {
-               if (u.ut_type == USER_PROCESS)
-                       strings_list_add(&utmp_ptr, u.ut_user);
+               if (u.ut_type == USER_PROCESS) {
+                       strncpy(name, u.ut_user, UT_NAMESIZE);
+                       name[UT_NAMESIZE] = '\0';
+                       strings_list_add(&utmp_ptr, name);
+               }
        }
        fclose(cfg);
        if (utmp_wd >= 0)
                inotify_rm_watch(inotify_fd, utmp_wd);
 
-       utmp_wd =
-           inotify_add_watch(inotify_fd, utmp_path, IN_MOVED_FROM | IN_MODIFY);
+       utmp_wd = inotify_add_watch(inotify_fd, utmp_path,
+                                   IN_MOVED_FROM | IN_MODIFY | IN_DONT_FOLLOW);
        if (utmp_wd == -1)
                exitApp("Error watching utmp file.");
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/restorecond-3.10/watch.c new/restorecond-3.11/watch.c
--- old/restorecond-3.10/watch.c        2026-02-02 03:01:16.000000000 +0100
+++ new/restorecond-3.11/watch.c        2026-07-01 18:51:05.000000000 +0200
@@ -15,6 +15,7 @@
 #include <string.h>
 #include <stdio.h>
 #include <fcntl.h>
+#include <dirent.h>
 #include <selinux/selinux.h>
 #include "restorecond.h"
 #include "stringslist.h"
@@ -24,14 +25,10 @@
 #define GLOB_TILDE 0
 #endif
 
-#ifndef GLOB_BRACE
-#define GLOB_BRACE 0
-#endif
-
 /* size of the event structure, not counting name */
-#define EVENT_SIZE  (sizeof (struct inotify_event))
+#define EVENT_SIZE (sizeof(struct inotify_event))
 /* reasonable guess as to size of 1024 events */
-#define BUF_LEN        (1024 * (EVENT_SIZE + 16))
+#define BUF_LEN (1024 * (EVENT_SIZE + 16))
 
 struct watchList {
        struct watchList *next;
@@ -39,40 +36,181 @@
        char *dir;
        struct stringsList *files;
 };
-struct watchList *firstDir = NULL;
+static struct watchList *firstDir = NULL;
 
-int watch_list_isempty(void) {
+int watch_list_isempty(void)
+{
        return firstDir == NULL;
 }
 
+static int open_final(int dfd, const char *name, struct stat *sb)
+{
+       int fd;
+
+       if (name)
+               fd = openat(dfd, name, O_PATH | O_NOFOLLOW | O_CLOEXEC);
+       else
+               fd = fcntl(dfd, F_DUPFD_CLOEXEC, 0);
+       if (fd < 0)
+               return -1;
+
+       if (fstat(fd, sb) < 0) {
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
+static int safe_open(const char *path, struct stat *sb)
+{
+       char *copy, *cur, *slash;
+       int dfd, nfd;
+
+       if (!path || path[0] == '\0') {
+               errno = ENOENT;
+               return -1;
+       }
+
+       copy = strdup(path);
+       if (!copy)
+               return -1;
+
+       if (copy[0] == '/') {
+               dfd = open("/", O_PATH | O_DIRECTORY | O_CLOEXEC);
+               cur = copy + 1;
+       } else {
+               dfd = open(".", O_PATH | O_DIRECTORY | O_CLOEXEC);
+               cur = copy;
+       }
+       if (dfd < 0) {
+               free(copy);
+               return -1;
+       }
+
+       while (*cur == '/')
+               cur++;
+
+       while (*cur != '\0') {
+               slash = strchr(cur, '/');
+               if (slash) {
+                       *slash = '\0';
+                       char *next = slash + 1;
+                       while (*next == '/')
+                               next++;
+                       if (*next != '\0') {
+                               nfd = openat(dfd, cur,
+                                            O_PATH | O_NOFOLLOW | O_DIRECTORY |
+                                                    O_CLOEXEC);
+                               close(dfd);
+                               if (nfd < 0) {
+                                       free(copy);
+                                       return -1;
+                               }
+                               dfd = nfd;
+                               cur = next;
+                               continue;
+                       }
+               }
+
+               nfd = open_final(dfd, cur, sb);
+               close(dfd);
+               free(copy);
+               return nfd;
+       }
+
+       nfd = open_final(dfd, NULL, sb);
+       close(dfd);
+       free(copy);
+       return nfd;
+}
+
+static void *nofollow_opendir(const char *name)
+{
+       struct stat sb;
+       int fd, rdfd;
+
+       fd = safe_open(name, &sb);
+       if (fd < 0)
+               return NULL;
+
+       if (!S_ISDIR(sb.st_mode)) {
+               close(fd);
+               errno = ENOTDIR;
+               return NULL;
+       }
+
+       rdfd = openat(fd, ".", O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
+       close(fd);
+       if (rdfd < 0)
+               return NULL;
+       return fdopendir(rdfd);
+}
+
+static struct dirent *nofollow_readdir(void *d)
+{
+       return readdir((DIR *)d);
+}
+
+static void nofollow_closedir(void *d)
+{
+       closedir((DIR *)d);
+}
+
+static int nofollow_lstat(const char *path, struct stat *sb)
+{
+       return lstat(path, sb);
+}
+
 void watch_list_add(int fd, const char *path)
 {
+       char procfd[32];
+       struct stat sb;
+       int dirfd;
        struct watchList *ptr = NULL;
        size_t i = 0;
        struct watchList *prev = NULL;
        glob_t globbuf;
-       char *x = strdup(path);
-       if (!x) exitApp("Out of Memory");
-       char *file = basename(x);
-       char *dir = dirname(x);
+       char *xb = strdup(path);
+       if (!xb)
+               exitApp("Out of Memory");
+       char *xd = strdup(path);
+       if (!xd)
+               exitApp("Out of Memory");
+       char *file = basename(xb);
+       char *dir = dirname(xd);
        ptr = firstDir;
        int len;
 
-       globbuf.gl_offs = 1;
-       if (glob(path,
-                GLOB_TILDE | GLOB_PERIOD,
-                NULL,
-                &globbuf) >= 0) {
+       memset(&globbuf, 0, sizeof(globbuf));
+       globbuf.gl_opendir = nofollow_opendir;
+       globbuf.gl_readdir = nofollow_readdir;
+       globbuf.gl_closedir = nofollow_closedir;
+       globbuf.gl_lstat = nofollow_lstat;
+       globbuf.gl_stat = nofollow_lstat; /* never follow symlinks */
+       if (glob(path, GLOB_TILDE | GLOB_PERIOD | GLOB_ALTDIRFUNC, NULL,
+                &globbuf) == 0) {
                for (i = 0; i < globbuf.gl_pathc; i++) {
-                       len = strlen(globbuf.gl_pathv[i]) - 2;
-                       if (len > 0 &&
-                           strcmp(&globbuf.gl_pathv[i][len--], "/.") == 0)
+                       const char *p = globbuf.gl_pathv[i];
+
+                       len = strlen(p) - 2;
+                       if (len > 0 && strcmp(&p[len--], "/.") == 0)
                                continue;
-                       if (len > 0 &&
-                           strcmp(&globbuf.gl_pathv[i][len], "/..") == 0)
+                       if (len > 0 && strcmp(&p[len], "/..") == 0)
                                continue;
-                       selinux_restorecon(globbuf.gl_pathv[i],
-                                          r_opts.restorecon_flags);
+                       if (selinux_restorecon(p, r_opts.restorecon_flags) <
+                           0) {
+                               if (errno != ENOENT) {
+                                       if (!run_as_user)
+                                               syslog(LOG_ERR,
+                                                      "Unable to relabel (%s) 
%s\n",
+                                                      p, strerror(errno));
+                                       else
+                                               fprintf(stderr,
+                                                       "Unable to relabel (%s) 
%s\n",
+                                                       p, strerror(errno));
+                               }
+                       }
                }
                globfree(&globbuf);
        }
@@ -87,14 +225,31 @@
        }
        ptr = calloc(1, sizeof(struct watchList));
 
-       if (!ptr) exitApp("Out of Memory");
+       if (!ptr)
+               exitApp("Out of Memory");
+
+       dirfd = safe_open(dir, &sb);
+       if (dirfd < 0 || !S_ISDIR(sb.st_mode)) {
+               if (dirfd >= 0) {
+                       close(dirfd);
+                       errno = ENOTDIR;
+               }
+               ptr->wd = -1;
+       } else {
+               snprintf(procfd, sizeof(procfd), "/proc/self/fd/%d", dirfd);
+               ptr->wd =
+                       inotify_add_watch(fd, procfd, IN_CREATE | IN_MOVED_TO);
+               close(dirfd);
+       }
 
-       ptr->wd = inotify_add_watch(fd, dir, IN_CREATE | IN_MOVED_TO);
        if (ptr->wd == -1) {
                free(ptr);
-               if (! run_as_user)
-                       syslog(LOG_ERR, "Unable to watch (%s) %s\n",
-                              path, strerror(errno));
+               if (!run_as_user)
+                       syslog(LOG_ERR, "Unable to watch (%s) %s\n", path,
+                              strerror(errno));
+               else
+                       fprintf(stderr, "Unable to watch (%s) %s\n", path,
+                               strerror(errno));
                goto end;
        }
 
@@ -112,7 +267,8 @@
                printf("%d: Dir=%s, File=%s\n", ptr->wd, ptr->dir, file);
 
 end:
-       free(x);
+       free(xb);
+       free(xd);
        return;
 }
 
@@ -131,15 +287,31 @@
                printf("%d: File=%s\n", wd, file);
        while (ptr != NULL) {
                if (ptr->wd == wd) {
-                       int exact=0;
+                       int exact = 0;
                        if (strings_list_find(ptr->files, file, &exact) == 0) {
                                char *path = NULL;
                                if (asprintf(&path, "%s/%s", ptr->dir, file) <
                                    0)
                                        exitApp("Error allocating memory.");
 
-                               selinux_restorecon(path,
-                                                  r_opts.restorecon_flags);
+                               if (selinux_restorecon(
+                                           path, r_opts.restorecon_flags) <
+                                   0) {
+                                       if (errno != ENOENT) {
+                                               if (!run_as_user)
+                                                       syslog(LOG_ERR,
+                                                              "Unable to 
relabel (%s) %s\n",
+                                                              path,
+                                                              strerror(errno));
+                                               else
+                                                       fprintf(stderr,
+                                                               "Unable to 
relabel (%s) %s\n",
+                                                               path,
+                                                               strerror(
+                                                                       errno));
+                                       }
+                               }
+
                                free(path);
                                return 0;
                        }
@@ -179,7 +351,6 @@
 {
        char buf[BUF_LEN];
        int len, i = 0;
-       if (firstDir == NULL) return 0;
 
        len = read(fd, buf, BUF_LEN);
        if (len < 0) {
@@ -196,23 +367,23 @@
                struct inotify_event *event;
                event = (struct inotify_event *)&buf[i];
                if (debug_mode)
-                       printf("wd=%d mask=%u cookie=%u len=%u\n",
-                              event->wd, event->mask,
-                              event->cookie, event->len);
+                       printf("wd=%d mask=%u cookie=%u len=%u\n", event->wd,
+                              event->mask, event->cookie, event->len);
                if (event->mask & ~IN_IGNORED) {
                        if (event->wd == master_wd)
                                read_config(fd, watch_file);
                        else {
                                switch (utmpwatcher_handle(fd, event->wd)) {
-                               case -1:        /* Message was not for 
utmpwatcher */
+                               case -1: /* Message was not for utmpwatcher */
                                        if (event->len)
-                                               watch_list_find(event->wd, 
event->name);
+                                               watch_list_find(event->wd,
+                                                               event->name);
                                        break;
-                               case 1: /* utmp has changed need to reload */
+                               case 1: /* utmp has changed need to reload */
                                        read_config(fd, watch_file);
                                        break;
 
-                               default:        /* No users logged in or out */
+                               default: /* No users logged in or out */
                                        break;
                                }
                        }
@@ -223,7 +394,7 @@
        return 0;
 }
 
-static void process_config(int fd, FILE * cfg)
+static void process_config(int fd, FILE *cfg)
 {
        char *line_buf = NULL;
        size_t len = 0;
@@ -237,11 +408,13 @@
                int l = strlen(buffer) - 1;
                if (l <= 0)
                        continue;
-               buffer[l] = 0;
+               if (buffer[l] == '\n')
+                       buffer[l] = 0;
                if (buffer[0] == '~') {
                        if (run_as_user) {
-                               char *ptr=NULL;
-                               if (asprintf(&ptr, "%s%s", homedir, &buffer[1]) 
< 0)
+                               char *ptr = NULL;
+                               if (asprintf(&ptr, "%s%s", homedir,
+                                            &buffer[1]) < 0)
                                        exitApp("Error allocating memory.");
 
                                watch_list_add(fd, ptr);
@@ -264,7 +437,6 @@
 
 void read_config(int fd, const char *watch_file_path)
 {
-
        FILE *cfg = NULL;
        if (debug_mode)
                printf("Read Config\n");
@@ -272,7 +444,7 @@
        watch_list_free(fd);
 
        cfg = fopen(watch_file_path, "r");
-       if (!cfg){
+       if (!cfg) {
                perror(watch_file_path);
                exitApp("Error reading config file");
        }
@@ -281,7 +453,8 @@
 
        inotify_rm_watch(fd, master_wd);
        master_wd =
-           inotify_add_watch(fd, watch_file_path, IN_MOVED_FROM | IN_MODIFY);
+               inotify_add_watch(fd, watch_file_path,
+                                 IN_MOVED_FROM | IN_MODIFY | IN_DONT_FOLLOW);
        if (master_wd == -1)
                exitApp("Error watching config file.");
 }

Reply via email to