Skip to content

Commit 3d2baff

Browse files
Arvinder Dhanoaawsomearvinder
authored andcommitted
fix(agent.c): wait for agent to successfully spawn before exiting.
We open a pipe with the agent when we spawn it, and wait for them to say they're ready before exiting. This *should* fix #650. The underlying issue was that when doing: ``` lpass login foo@example.com lpass show bar ``` in a script would cause a race condition where `lpass login` exited before the agent was successfully brought up. `lpass show bar` then tried to reach out to the agent, sees the socket isn't created yet, and says the user isn't logged in. Signed-Off-by: Arvinder Dhanoa <ArvinderDhan@gmail.com>
1 parent 4a6e1da commit 3d2baff

File tree

1 file changed

+38
-2
lines changed

1 file changed

+38
-2
lines changed

agent.c

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "password.h"
4141
#include "terminal.h"
4242
#include "process.h"
43+
#include <stdio.h>
4344
#include <unistd.h>
4445
#include <string.h>
4546
#include <fcntl.h>
@@ -156,14 +157,15 @@ int _setup_agent_socket(struct sockaddr_un *sa, char *path)
156157
return fd;
157158
}
158159

159-
static void agent_run(unsigned const char key[KDF_HASH_LEN])
160+
static void agent_run(unsigned const char key[KDF_HASH_LEN], int status_event_fd)
160161
{
161162
char *agent_timeout_str;
162163
unsigned int agent_timeout;
163164
struct sockaddr_un sa, listensa;
164165
struct ucred cred;
165166
int fd, listenfd;
166167
socklen_t len;
168+
char status_event[64];
167169

168170
signal(SIGHUP, agent_cleanup);
169171
signal(SIGINT, agent_cleanup);
@@ -188,9 +190,22 @@ static void agent_run(unsigned const char key[KDF_HASH_LEN])
188190
close(fd);
189191
unlink(path);
190192
errno = listenfd;
193+
194+
strcpy(status_event, "FAILED"); // send that we failed to successfully spawn to the process
195+
if (write(status_event_fd, status_event, 64) < 0) {
196+
fprintf(stderr, "Failed to send the error status to parent process.\n");
197+
}
198+
191199
die_errno("bind|listen");
192200
}
193201

202+
strcpy(status_event, "READY"); // notify to the calling process that we're in a ready state - they're free to exit.
203+
if (write(status_event_fd, status_event, 64) < 0) {
204+
fprintf(stderr, "Failed to notify the parent process that we are listening. Continuing anyways.\n");
205+
}
206+
207+
close(status_event_fd);
208+
194209
for (len = sizeof(listensa); (listenfd = accept(fd, (struct sockaddr *)&listensa, &len)) > 0; len = sizeof(listensa)) {
195210
if (agent_socket_get_cred(listenfd, &cred) < 0) {
196211
close(listenfd);
@@ -288,6 +303,11 @@ static void agent_start(unsigned const char key[KDF_HASH_LEN])
288303
return;
289304
}
290305

306+
int agent_status_pipe[2];
307+
if(pipe(agent_status_pipe) < 0) {
308+
die("Failed to make pipe for agent process.");
309+
}
310+
291311
child = fork();
292312
if (child < 0)
293313
die_errno("fork(agent)");
@@ -306,9 +326,25 @@ static void agent_start(unsigned const char key[KDF_HASH_LEN])
306326
process_disable_ptrace();
307327
process_set_name("lpass [agent]");
308328

309-
agent_run(key);
329+
close(agent_status_pipe[0]);
330+
agent_run(key, agent_status_pipe[1]);
310331
_exit(EXIT_FAILURE);
311332
}
333+
334+
if (child > 0) {
335+
close(agent_status_pipe[1]);
336+
337+
char status[64];
338+
if (read(agent_status_pipe[0], status, 64) < 0) { // wait for agent to spawn successfully before exiting.
339+
die("Failed to read bringup status from agent");
340+
}
341+
342+
if(strcmp(status, "FAILED") == 0) {
343+
die("Failed to bringup agent.");
344+
}
345+
return;
346+
close(agent_status_pipe[0]);
347+
}
312348
}
313349

314350
bool agent_get_decryption_key(unsigned char key[KDF_HASH_LEN])

0 commit comments

Comments
 (0)