Skip to content

Commit 3b187a7

Browse files
committed
privsep: Fix reading results from root process
Should be the final fallout from the new eloop.
1 parent 760a3d2 commit 3b187a7

File tree

3 files changed

+81
-66
lines changed

3 files changed

+81
-66
lines changed

src/privsep-root.c

Lines changed: 75 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ struct psr_ctx {
7171
struct psr_error psr_error;
7272
size_t psr_datalen;
7373
void *psr_data;
74+
size_t psr_mdatalen;
75+
void *psr_mdata;
76+
bool psr_usemdata;
7477
};
7578

7679
static void
@@ -81,14 +84,15 @@ ps_root_readerrorcb(void *arg, unsigned short events)
8184
struct psr_error *psr_error = &psr_ctx->psr_error;
8285
struct iovec iov[] = {
8386
{ .iov_base = psr_error, .iov_len = sizeof(*psr_error) },
84-
{ .iov_base = psr_ctx->psr_data,
85-
.iov_len = psr_ctx->psr_datalen },
87+
{ .iov_base = NULL, .iov_len = 0 },
8688
};
8789
ssize_t len;
8890
int exit_code = EXIT_FAILURE;
8991

90-
if (events & ELE_HANGUP)
92+
if (events & ELE_HANGUP) {
93+
logerrx("%s: hangup", __func__);
9194
goto out;
95+
}
9296

9397
if (events != ELE_READ)
9498
logerrx("%s: unexpected event 0x%04x", __func__, events);
@@ -100,11 +104,39 @@ ps_root_readerrorcb(void *arg, unsigned short events)
100104
goto out; \
101105
} while (0 /* CONSTCOND */)
102106

103-
len = readv(PS_ROOT_FD(ctx), iov, __arraycount(iov));
107+
len = recv(PS_ROOT_FD(ctx), psr_error, sizeof(*psr_error), MSG_PEEK);
104108
if (len == -1)
105109
PSR_ERROR(errno);
106110
else if ((size_t)len < sizeof(*psr_error))
107111
PSR_ERROR(EINVAL);
112+
113+
if (psr_error->psr_datalen > SSIZE_MAX)
114+
PSR_ERROR(ENOBUFS);
115+
if (psr_ctx->psr_usemdata &&
116+
psr_error->psr_datalen > psr_ctx->psr_mdatalen)
117+
{
118+
void *d = realloc(psr_ctx->psr_mdata, psr_error->psr_datalen);
119+
if (d == NULL)
120+
PSR_ERROR(errno);
121+
psr_ctx->psr_mdata = d;
122+
psr_ctx->psr_mdatalen = psr_error->psr_datalen;
123+
}
124+
if (psr_error->psr_datalen != 0) {
125+
if (psr_ctx->psr_usemdata)
126+
iov[1].iov_base = psr_ctx->psr_mdata;
127+
else {
128+
if (psr_error->psr_datalen > psr_ctx->psr_datalen)
129+
PSR_ERROR(ENOBUFS);
130+
iov[1].iov_base = psr_ctx->psr_data;
131+
}
132+
iov[1].iov_len = psr_error->psr_datalen;
133+
}
134+
135+
len = readv(PS_ROOT_FD(ctx), iov, __arraycount(iov));
136+
if (len == -1)
137+
PSR_ERROR(errno);
138+
else if ((size_t)len != sizeof(*psr_error) + psr_error->psr_datalen)
139+
PSR_ERROR(EINVAL);
108140
exit_code = EXIT_SUCCESS;
109141

110142
out:
@@ -119,6 +151,7 @@ ps_root_readerror(struct dhcpcd_ctx *ctx, void *data, size_t len)
119151

120152
pc->psr_data = data;
121153
pc->psr_datalen = len;
154+
pc->psr_usemdata = false;
122155
err = eloop_start(ctx->ps_eloop);
123156
if (err < 0)
124157
return err;
@@ -127,73 +160,35 @@ ps_root_readerror(struct dhcpcd_ctx *ctx, void *data, size_t len)
127160
return pc->psr_error.psr_result;
128161
}
129162

130-
#ifdef PRIVSEP_GETIFADDRS
131-
static void
132-
ps_root_mreaderrorcb(void *arg, unsigned short events)
133-
{
134-
struct psr_ctx *psr_ctx = arg;
135-
struct dhcpcd_ctx *ctx = psr_ctx->psr_ctx;
136-
struct psr_error *psr_error = &psr_ctx->psr_error;
137-
struct iovec iov[] = {
138-
{ .iov_base = psr_error, .iov_len = sizeof(*psr_error) },
139-
{ .iov_base = NULL, .iov_len = 0 },
140-
};
141-
ssize_t len;
142-
int exit_code = EXIT_FAILURE;
143-
144-
if (events != ELE_READ)
145-
logerrx("%s: unexpected event 0x%04x", __func__, events);
146-
147-
len = recv(PS_ROOT_FD(ctx), psr_error, sizeof(*psr_error), MSG_PEEK);
148-
if (len == -1)
149-
PSR_ERROR(errno);
150-
else if ((size_t)len < sizeof(*psr_error))
151-
PSR_ERROR(EINVAL);
152-
153-
if (psr_error->psr_datalen > SSIZE_MAX)
154-
PSR_ERROR(ENOBUFS);
155-
else if (psr_error->psr_datalen != 0) {
156-
psr_ctx->psr_data = malloc(psr_error->psr_datalen);
157-
if (psr_ctx->psr_data == NULL)
158-
PSR_ERROR(errno);
159-
psr_ctx->psr_datalen = psr_error->psr_datalen;
160-
iov[1].iov_base = psr_ctx->psr_data;
161-
iov[1].iov_len = psr_ctx->psr_datalen;
162-
}
163-
164-
len = readv(PS_ROOT_FD(ctx), iov, __arraycount(iov));
165-
if (len == -1)
166-
PSR_ERROR(errno);
167-
else if ((size_t)len != sizeof(*psr_error) + psr_ctx->psr_datalen)
168-
PSR_ERROR(EINVAL);
169-
exit_code = EXIT_SUCCESS;
170-
171-
out:
172-
eloop_exit(ctx->ps_eloop, exit_code);
173-
}
174-
175163
ssize_t
176164
ps_root_mreaderror(struct dhcpcd_ctx *ctx, void **data, size_t *len)
177165
{
178-
struct psr_ctx psr_ctx = {
179-
.psr_ctx = ctx,
180-
};
181-
int fd = PS_ROOT_FD(ctx), err;
182-
183-
if (eloop_event_add(ctx->ps_eloop, fd, ELE_READ,
184-
ps_root_mreaderrorcb, &psr_ctx) == -1)
185-
return -1;
166+
struct psr_ctx *pc = ctx->ps_root->psp_data;
167+
int err;
168+
void *d;
186169

187-
err = eloop_start(ctx->ps_eloop, &ctx->sigset);
170+
pc->psr_usemdata = true;
171+
err = eloop_start(ctx->ps_eloop);
188172
if (err < 0)
189173
return err;
190174

191-
errno = psr_ctx.psr_error.psr_errno;
192-
*data = psr_ctx.psr_data;
193-
*len = psr_ctx.psr_datalen;
194-
return psr_ctx.psr_error.psr_result;
175+
if (pc->psr_error.psr_datalen != 0) {
176+
if (pc->psr_error.psr_datalen > pc->psr_mdatalen) {
177+
errno = EINVAL;
178+
return -1;
179+
}
180+
d = malloc(pc->psr_error.psr_datalen);
181+
if (d == NULL)
182+
return -1;
183+
memcpy(d, pc->psr_mdata, pc->psr_error.psr_datalen);
184+
} else
185+
d = NULL;
186+
187+
errno = pc->psr_error.psr_errno;
188+
*data = d;
189+
*len = pc->psr_error.psr_datalen;
190+
return pc->psr_error.psr_result;
195191
}
196-
#endif
197192

198193
static ssize_t
199194
ps_root_writeerror(struct dhcpcd_ctx *ctx, ssize_t result,
@@ -863,6 +858,17 @@ ps_root_log(void *arg, unsigned short events)
863858
logerr(__func__);
864859
}
865860

861+
static void
862+
ps_root_freepsdata(void *arg)
863+
{
864+
struct psr_ctx *pc = arg;
865+
866+
if (pc == NULL)
867+
return;
868+
free(pc->psr_mdata);
869+
free(pc);
870+
}
871+
866872
pid_t
867873
ps_root_start(struct dhcpcd_ctx *ctx)
868874
{
@@ -891,8 +897,7 @@ ps_root_start(struct dhcpcd_ctx *ctx)
891897
return -1;
892898
#endif
893899

894-
895-
pc = malloc(sizeof(*pc));
900+
pc = calloc(1, sizeof(*pc));
896901
if (pc == NULL)
897902
return -1;
898903
pc->psr_ctx = ctx;
@@ -903,6 +908,7 @@ ps_root_start(struct dhcpcd_ctx *ctx)
903908
free(pc);
904909
return -1;
905910
}
911+
psp->psp_freedata = ps_root_freepsdata;
906912
strlcpy(psp->psp_name, "privileged proxy", sizeof(psp->psp_name));
907913
pid = ps_startprocess(psp, ps_root_recvmsg, NULL,
908914
ps_root_startcb, PSF_ELOOP);
@@ -970,6 +976,7 @@ int
970976
ps_root_stop(struct dhcpcd_ctx *ctx)
971977
{
972978
struct ps_process *psp = ctx->ps_root;
979+
int err;
973980

974981
if (!(ctx->options & DHCPCD_PRIVSEP) ||
975982
ctx->eloop == NULL)
@@ -1001,7 +1008,9 @@ ps_root_stop(struct dhcpcd_ctx *ctx)
10011008
return -1;
10021009
} /* else the root process has already exited :( */
10031010

1004-
return ps_stopwait(ctx);
1011+
err = ps_stopwait(ctx);
1012+
ps_freeprocess(ctx->ps_root);
1013+
return err;
10051014
}
10061015

10071016
ssize_t

src/privsep.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,11 @@ ps_freeprocess(struct ps_process *psp)
775775

776776
TAILQ_REMOVE(&ctx->ps_processes, psp, next);
777777

778+
if (psp->psp_freedata != NULL)
779+
psp->psp_freedata(psp->psp_data);
780+
else
781+
free(psp->psp_data);
782+
778783
if (psp->psp_fd != -1) {
779784
eloop_event_delete(ctx->eloop, psp->psp_fd);
780785
close(psp->psp_fd);

src/privsep.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ struct ps_process {
185185
uint16_t psp_proto;
186186
const char *psp_protostr;
187187
void *psp_data;
188+
void (*psp_freedata)(void *);
188189
bool psp_started;
189190

190191
#ifdef INET

0 commit comments

Comments
 (0)