source: filterproc.c @ 1f39ded

release-1.10release-1.9
Last change on this file since 1f39ded was 1f39ded, 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.1 KB
Line 
1#include "owl.h"
2#include <sys/wait.h>
3#include <poll.h>
4
5int send_receive(int rfd, int wfd, const char *out, char **in)
6{
7  GString *str = g_string_new("");
8  char buf[1024];
9  nfds_t nfds;
10  int err = 0;
11  struct pollfd fds[2];
12
13  fcntl(rfd, F_SETFL, O_NONBLOCK | fcntl(rfd, F_GETFL));
14  fcntl(wfd, F_SETFL, O_NONBLOCK | fcntl(wfd, F_GETFL));
15
16  fds[0].fd = rfd;
17  fds[0].events = POLLIN;
18  fds[1].fd = wfd;
19  fds[1].events = POLLOUT;
20
21  if(!out || !*out) {
22    /* Nothing to write. Close our end so the child doesn't hang waiting. */
23    close(wfd);
24    out = NULL;
25  }
26
27  while(1) {
28    if(out && *out) {
29      nfds = 2;
30    } else {
31      nfds = 1;
32    }
33    err = poll(fds, nfds, -1);
34    if(err < 0) {
35      break;
36    }
37    if(out && *out) {
38      if(fds[1].revents & POLLOUT) {
39        err = write(wfd, out, strlen(out));
40        if(err > 0) {
41          out += err;
42        }
43        if(err < 0) {
44          out = NULL;
45        }
46      }
47      if(!out || !*out || fds[1].revents & (POLLERR | POLLHUP)) {
48        close(wfd);
49        out = NULL;
50      }
51    }
52    if(fds[0].revents & POLLIN) {
53      err = read(rfd, buf, sizeof(buf));
54      if(err <= 0) {
55        break;
56      }
57      g_string_append_len(str, buf, err);
58    } else if(fds[0].revents & (POLLHUP | POLLERR)) {
59      err = 0;
60      break;
61    }
62  }
63
64  *in = g_string_free(str, err < 0);
65  return err;
66}
67
68int call_filter(const char *prog, const char *const *argv, const char *in, char **out, int *status)
69{
70  int err = 0;
71  pid_t pid;
72  int rfd[2];
73  int wfd[2];
74
75  if((err = pipe(rfd))) goto out;
76  if((err = pipe(wfd))) goto out_close_rfd;
77
78  pid = fork();
79  if(pid < 0) {
80    err = pid;
81    goto out_close_all;
82  }
83  if(pid) {
84    /* parent */
85    close(rfd[1]);
86    close(wfd[0]);
87    err = send_receive(rfd[0], wfd[1], in, out);
88    if(err == 0) {
89      waitpid(pid, status, 0);
90    }
91  } else {
92    /* child */
93    close(rfd[0]);
94    close(wfd[1]);
95    dup2(rfd[1], 1);
96    dup2(wfd[0], 0);
97    close(rfd[1]);
98    close(wfd[0]);
99
100    if(execvp(prog, (char *const *)argv)) {
101      _exit(-1);
102    }
103  }
104
105 out_close_all:
106  close(wfd[0]);
107  close(wfd[1]);
108 out_close_rfd:
109  close(rfd[0]);
110  close(rfd[1]);
111 out:
112  return err;
113}
Note: See TracBrowser for help on using the repository browser.