source: filterproc.c @ 4a80a16

release-1.8
Last change on this file since 4a80a16 was 4a80a16, checked in by David Benjamin <davidben@mit.edu>, 12 years ago
Fix hang on empty zcrypt messages send_receive will never close wfd if out is an empty string. Consequently, the zcrypt end will keep waiting for something to encrypt (or decrypt), thereby deadlocking the barnowl. This closes wfd if we aren't going to write anything to it. Consequently, zcrypt will terminate quickly, and we'll also return. This fixes a deadlock when sending (at least it's the user's fault) or receiving (this one is a DoS possibility) empty zcrypted messages.
  • Property mode set to 100644
File size: 2.3 KB
Line 
1#include <signal.h>
2#include <unistd.h>
3#include <sys/select.h>
4#include <sys/types.h>
5#include <sys/wait.h>
6#include <poll.h>
7#include <fcntl.h>
8#include <string.h>
9
10#include <glib.h>
11
12int send_receive(int rfd, int wfd, const char *out, char **in)
13{
14  GString *str = g_string_new("");
15  char buf[1024];
16  nfds_t nfds;
17  int err = 0;
18  struct pollfd fds[2];
19
20  fcntl(rfd, F_SETFL, O_NONBLOCK | fcntl(rfd, F_GETFL));
21  fcntl(wfd, F_SETFL, O_NONBLOCK | fcntl(wfd, F_GETFL));
22
23  fds[0].fd = rfd;
24  fds[0].events = POLLIN;
25  fds[1].fd = wfd;
26  fds[1].events = POLLOUT;
27
28  if(!out || !*out) {
29    /* Nothing to write. Close our end so the child doesn't hang waiting. */
30    close(wfd);
31    out = NULL;
32  }
33
34  while(1) {
35    if(out && *out) {
36      nfds = 2;
37    } else {
38      nfds = 1;
39    }
40    err = poll(fds, nfds, -1);
41    if(err < 0) {
42      break;
43    }
44    if(out && *out) {
45      if(fds[1].revents & POLLOUT) {
46        err = write(wfd, out, strlen(out));
47        if(err > 0) {
48          out += err;
49        }
50        if(err < 0) {
51          out = NULL;
52        }
53      }
54      if(!out || !*out || fds[1].revents & (POLLERR | POLLHUP)) {
55        close(wfd);
56        out = NULL;
57      }
58    }
59    if(fds[0].revents & POLLIN) {
60      err = read(rfd, buf, sizeof(buf));
61      if(err <= 0) {
62        break;
63      }
64      g_string_append_len(str, buf, err);
65    } else if(fds[0].revents & (POLLHUP | POLLERR)) {
66      err = 0;
67      break;
68    }
69  }
70
71  *in = g_string_free(str, err < 0);
72  return err;
73}
74
75int call_filter(const char *prog, const char *const *argv, const char *in, char **out, int *status)
76{
77  int err = 0;
78  pid_t pid;
79  int rfd[2];
80  int wfd[2];
81
82  if((err = pipe(rfd))) goto out;
83  if((err = pipe(wfd))) goto out_close_rfd;
84
85  pid = fork();
86  if(pid < 0) {
87    err = pid;
88    goto out_close_all;
89  }
90  if(pid) {
91    /* parent */
92    close(rfd[1]);
93    close(wfd[0]);
94    err = send_receive(rfd[0], wfd[1], in, out);
95    if(err == 0) {
96      waitpid(pid, status, 0);
97    }
98  } else {
99    /* child */
100    close(rfd[0]);
101    close(wfd[1]);
102    dup2(rfd[1], 1);
103    dup2(wfd[0], 0);
104    close(rfd[1]);
105    close(wfd[0]);
106
107    if(execvp(prog, (char *const *)argv)) {
108      _exit(-1);
109    }
110  }
111
112 out_close_all:
113  close(wfd[0]);
114  close(wfd[1]);
115 out_close_rfd:
116  close(rfd[0]);
117  close(rfd[1]);
118 out:
119  return err;
120}
Note: See TracBrowser for help on using the repository browser.