diff mbox series

[pseudo] pseudo_client: Fail when the local state directory isn't writable

Message ID 20261112164734.488457-1-mark.hatle@amd.com
State New
Headers show
Series [pseudo] pseudo_client: Fail when the local state directory isn't writable | expand

Commit Message

Mark Hatle Nov. 12, 2026, 4:47 p.m. UTC
A read-only PSEUDO_LOCALSTATEDIR was only opened for reading, so clients
kept spawning a server that couldn't create its lock file, up to
PSEUDO_RETRIES times with an error each time, before aborting.

Check the directory is writable when the client starts, and fail as for
a missing directory.  The server makes the same check before creating
its lock file.  The client also aborts at once if the server exits with
a status retrying can't fix; lock_failed is still retried, as running
out of file descriptors can cause it.

Tested with a chmod 555 directory, a read-only bind mount, and by
starting the server directly.

[YOCTO #15497]

Reported-by: milahu <milahu@gmail.com>
AI-Generated: Uses GitHub Copilot
Signed-off-by: Mark Hatle <mark.hatle@amd.com>
---
 pseudo.1        |  3 +++
 pseudo_client.c | 26 ++++++++++++++++++++++++++
 pseudo_server.c |  5 +++++
 3 files changed, 34 insertions(+)
diff mbox series

Patch

diff --git a/pseudo.1 b/pseudo.1
index 2475631..be0827f 100644
--- a/pseudo.1
+++ b/pseudo.1
@@ -703,6 +703,9 @@  database files and log files; by default, it is the
 .I var/pseudo
 directory under
 .BR PSEUDO_PREFIX .
+It must be writable; if it is not,
+.I pseudo
+fails at startup rather than trying to start the server.
 .TP 8
 .B PSEUDO_NOSYMLINKEXP
 By default, when chrooted,
diff --git a/pseudo_client.c b/pseudo_client.c
index efb5662..44a6b88 100644
--- a/pseudo_client.c
+++ b/pseudo_client.c
@@ -608,6 +608,16 @@  pseudo_init_client(void) {
 					strerror(errno));
 				exit(1);
 			}
+			/* the server can't run without creating its lock,
+			 * socket, pid and database files here, so fail now
+			 * instead of repeatedly trying to start it
+			 */
+			if (faccessat(pseudo_localstate_dir_fd, ".", W_OK | X_OK, 0) == -1) {
+				pseudo_error("Local state path '%s' is not writable: %s\n",
+					pseudo_path,
+					strerror(errno));
+				exit(1);
+			}
 		}
 		free(pseudo_path);
 
@@ -1028,6 +1038,22 @@  client_spawn_server(void) {
 		} else {
 			pseudo_evlog(PDBGF_CLIENT, "server startup apparently unsuccessful.  setting server pid to -1.\n");
 			server_pid = -1;
+			/* Retrying can't fix these, so stop instead of
+			 * respawning the server PSEUDO_RETRIES times.
+			 */
+			if (WIFEXITED(status)) {
+				switch (WEXITSTATUS(status)) {
+				case PSEUDO_EXIT_LOCK_PATH:
+				case PSEUDO_EXIT_PSEUDO_LOADED:
+				case PSEUDO_EXIT_PSEUDO_PREFIX:
+				case PSEUDO_EXIT_PSEUDO_INVOCATION:
+					pseudo_critical("server failed to start: %s\n",
+						pseudo_exit_status_name(WEXITSTATUS(status)));
+					break;
+				default:
+					break;
+				}
+			}
 			return 1;
 		}
 	} else {
diff --git a/pseudo_server.c b/pseudo_server.c
index 7016adc..79365e6 100644
--- a/pseudo_server.c
+++ b/pseudo_server.c
@@ -266,6 +266,11 @@  pseudo_server_start(int daemonize) {
 		exit(PSEUDO_EXIT_LOCK_PATH);
 	}
 	mkdir_p(lockpath);
+	if (access(lockpath, W_OK | X_OK) == -1) {
+		pseudo_error("Local state directory '%s' is not writable, unable to create lockfile: %s\n",
+			lockpath, strerror(errno));
+		exit(PSEUDO_EXIT_LOCK_FAILED);
+	}
 	lockname = pseudo_localstatedir_path(PSEUDO_LOCKFILE);
 	if (!lockname) {
 		pseudo_error("Couldn't allocate a file path.\n");