Skip to content

Commit

Permalink
fix(agent.c): wait for agent to successfully spawn before exiting.
Browse files Browse the repository at this point in the history
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 [email protected]
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 <[email protected]>
  • Loading branch information
awsomearvinder committed Jul 17, 2024
1 parent 4a6e1da commit 0c7fd48
Showing 1 changed file with 38 additions and 2 deletions.
40 changes: 38 additions & 2 deletions agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "password.h"
#include "terminal.h"
#include "process.h"
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
Expand Down Expand Up @@ -156,14 +157,15 @@ int _setup_agent_socket(struct sockaddr_un *sa, char *path)
return fd;
}

static void agent_run(unsigned const char key[KDF_HASH_LEN])
static void agent_run(unsigned const char key[KDF_HASH_LEN], int status_event_fd)
{
char *agent_timeout_str;
unsigned int agent_timeout;
struct sockaddr_un sa, listensa;
struct ucred cred;
int fd, listenfd;
socklen_t len;
char status_event[64];

signal(SIGHUP, agent_cleanup);
signal(SIGINT, agent_cleanup);
Expand All @@ -188,9 +190,22 @@ static void agent_run(unsigned const char key[KDF_HASH_LEN])
close(fd);
unlink(path);
errno = listenfd;

strcpy("FAILED", status_event); // send that we failed to successfully spawn to the process
if (write(status_event_fd, status_event, 64) < 0) {
fprintf(stderr, "Failed to send the error status to parent process.\n");
}

die_errno("bind|listen");
}

strcpy("READY", status_event); // notify to the calling process that we're in a ready state - they're free to exit.
if (write(status_event_fd, status_event, 64) < 0) {
fprintf(stderr, "Failed to notify the parent process that we are listening. Continuing anyways.\n");
}

close(status_event_fd);

for (len = sizeof(listensa); (listenfd = accept(fd, (struct sockaddr *)&listensa, &len)) > 0; len = sizeof(listensa)) {
if (agent_socket_get_cred(listenfd, &cred) < 0) {
close(listenfd);
Expand Down Expand Up @@ -288,6 +303,11 @@ static void agent_start(unsigned const char key[KDF_HASH_LEN])
return;
}

int agent_status_pipe[2];
if(pipe(agent_status_pipe) < 0) {
die("Failed to make pipe for agent process.");
}

child = fork();
if (child < 0)
die_errno("fork(agent)");
Expand All @@ -306,9 +326,25 @@ static void agent_start(unsigned const char key[KDF_HASH_LEN])
process_disable_ptrace();
process_set_name("lpass [agent]");

agent_run(key);
close(agent_status_pipe[0]);
agent_run(key, agent_status_pipe[1]);
_exit(EXIT_FAILURE);
}

if (child > 0) {
close(agent_status_pipe[1]);

char status[64];
if (read(agent_status_pipe[0], status, 64) < 0) { // wait for agent to spawn successfully before exiting.
die("Failed to read bringup status from agent");
}

if(strcmp(status, "FAILED") == 0) {
die("Failed to bringup agent.");
}
return;
close(agent_status_pipe[0]);
}
}

bool agent_get_decryption_key(unsigned char key[KDF_HASH_LEN])
Expand Down

0 comments on commit 0c7fd48

Please sign in to comment.