Skip to content

Commit f950a5d

Browse files
committed
ipc: Use mkdtemp for more secure IPC files
Use mkdtemp makes sure that IPC files are only visible to the owning (client) process and do not use predictable names outside of that. This is not meant to be the last word on the subject, it's mainly a simple way of making the current libqb more secure. Importantly, it's backwards compatible with an old server. It calls rmdir on the directory created by mkdtemp way too often, but it seems to be the only way to be sure that things get cleaned up on the various types of server/client exit. I'm sure we can come up with something tidier for master but I hope this, or something similar, will be OK for 1.0.x.
1 parent 269a0ca commit f950a5d

File tree

7 files changed

+64
-11
lines changed

7 files changed

+64
-11
lines changed

lib/ipc_int.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ enum qb_ipcs_connection_state {
160160
QB_IPCS_CONNECTION_SHUTTING_DOWN,
161161
};
162162

163-
#define CONNECTION_DESCRIPTION (34) /* INT_MAX length + 3 */
163+
#define CONNECTION_DESCRIPTION NAME_MAX
164164

165165
struct qb_ipcs_connection_auth {
166166
uid_t uid;
@@ -207,4 +207,6 @@ int32_t qb_ipc_us_sock_error_is_disconnected(int err);
207207

208208
int use_filesystem_sockets(void);
209209

210+
void remove_tempdir(const char *name, size_t namelen);
211+
210212
#endif /* QB_IPC_INT_H_DEFINED */

lib/ipc_setup.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,8 +642,28 @@ handle_new_connection(struct qb_ipcs_service *s,
642642
c->auth.gid = c->egid = ugp->gid;
643643
c->auth.mode = 0600;
644644
c->stats.client_pid = ugp->pid;
645+
646+
#if defined(QB_LINUX) || defined(QB_CYGWIN)
647+
snprintf(c->description, CONNECTION_DESCRIPTION,
648+
"/dev/shm/qb-%d-%d-%d-XXXXXX", s->pid, ugp->pid, c->setup.u.us.sock);
649+
if (mkdtemp(c->description) == NULL) {
650+
res = errno;
651+
goto send_response;
652+
}
653+
res = chown(c->description, c->auth.uid, c->auth.gid);
654+
if (res != 0) {
655+
res = errno;
656+
goto send_response;
657+
}
658+
659+
/* We can't pass just a directory spec to the clients */
660+
strncat(c->description,"/qb", CONNECTION_DESCRIPTION);
661+
#else
645662
snprintf(c->description, CONNECTION_DESCRIPTION,
646663
"%d-%d-%d", s->pid, ugp->pid, c->setup.u.us.sock);
664+
#endif
665+
666+
647667

648668
if (auth_result == 0 && c->service->serv_fns.connection_accept) {
649669
res = c->service->serv_fns.connection_accept(c,
@@ -864,3 +884,22 @@ qb_ipcs_us_connection_acceptor(int fd, int revent, void *data)
864884
qb_ipcs_uc_recv_and_auth(new_fd, s);
865885
return 0;
866886
}
887+
888+
void remove_tempdir(const char *name, size_t namelen)
889+
{
890+
#if defined(QB_LINUX) || defined(QB_CYGWIN)
891+
char dirname[PATH_MAX];
892+
char *slash;
893+
memcpy(dirname, name, namelen);
894+
895+
slash = strrchr(dirname, '/');
896+
if (slash) {
897+
*slash = '\0';
898+
/* This gets called more than it needs to be really, so we don't check
899+
* the return code. It's more of a desperate attempt to clean up after ourself
900+
* in either the server or client.
901+
*/
902+
(void)rmdir(dirname);
903+
}
904+
#endif
905+
}

lib/ipc_shm.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,8 @@ qb_ipcs_shm_disconnect(struct qb_ipcs_connection *c)
239239
qb_rb_close(qb_rb_lastref_and_ret(&c->request.u.shm.rb));
240240
}
241241
}
242+
243+
remove_tempdir(c->description, CONNECTION_DESCRIPTION);
242244
}
243245

244246
static int32_t
@@ -285,11 +287,11 @@ qb_ipcs_shm_connect(struct qb_ipcs_service *s,
285287
qb_util_log(LOG_DEBUG, "connecting to client [%d]", c->pid);
286288

287289
snprintf(r->request, NAME_MAX, "%s-request-%s",
288-
s->name, c->description);
290+
c->description, s->name);
289291
snprintf(r->response, NAME_MAX, "%s-response-%s",
290-
s->name, c->description);
292+
c->description, s->name);
291293
snprintf(r->event, NAME_MAX, "%s-event-%s",
292-
s->name, c->description);
294+
c->description, s->name);
293295

294296
res = qb_ipcs_shm_rb_open(c, &c->request,
295297
r->request);

lib/ipc_socket.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,10 @@ qb_ipcc_us_disconnect(struct qb_ipcc_connection *c)
374374
free(base_name);
375375
}
376376
}
377+
378+
/* Last-ditch attempt to tidy up after ourself */
379+
remove_tempdir(c->request.u.us.shared_file_name, PATH_MAX);
380+
377381
qb_ipcc_us_sock_close(c->event.u.us.sock);
378382
qb_ipcc_us_sock_close(c->request.u.us.sock);
379383
qb_ipcc_us_sock_close(c->setup.u.us.sock);
@@ -765,7 +769,10 @@ qb_ipcs_us_disconnect(struct qb_ipcs_connection *c)
765769
c->state == QB_IPCS_CONNECTION_ACTIVE) {
766770
munmap(c->request.u.us.shared_data, SHM_CONTROL_SIZE);
767771
unlink(c->request.u.us.shared_file_name);
772+
773+
768774
}
775+
remove_tempdir(c->description, CONNECTION_DESCRIPTION);
769776
}
770777

771778
static int32_t
@@ -784,9 +791,9 @@ qb_ipcs_us_connect(struct qb_ipcs_service *s,
784791
c->request.u.us.sock = c->setup.u.us.sock;
785792
c->response.u.us.sock = c->setup.u.us.sock;
786793

787-
snprintf(r->request, NAME_MAX, "qb-%s-control-%s",
788-
s->name, c->description);
789-
snprintf(r->response, NAME_MAX, "qb-%s-%s", s->name, c->description);
794+
snprintf(r->request, NAME_MAX, "%s-control-%s",
795+
c->description, s->name);
796+
snprintf(r->response, NAME_MAX, "%s-%s", c->description, s->name);
790797

791798
fd_hdr = qb_sys_mmap_file_open(path, r->request,
792799
SHM_CONTROL_SIZE,

lib/ipcs.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,12 +642,13 @@ qb_ipcs_disconnect(struct qb_ipcs_connection *c)
642642
scheduled_retry = 1;
643643
}
644644
}
645-
645+
remove_tempdir(c->description, CONNECTION_DESCRIPTION);
646646
if (scheduled_retry == 0) {
647647
/* This removes the initial alloc ref */
648648
qb_ipcs_connection_unref(c);
649649
}
650650
}
651+
651652
}
652653

653654
static void

lib/ringbuffer.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ qb_rb_open_2(const char *name, size_t size, uint32_t flags,
166166
/*
167167
* Create a shared_hdr memory segment for the header.
168168
*/
169-
snprintf(filename, PATH_MAX, "qb-%s-header", name);
169+
snprintf(filename, PATH_MAX, "%s-header", name);
170170
fd_hdr = qb_sys_mmap_file_open(path, filename,
171171
shared_size, file_flags);
172172
if (fd_hdr < 0) {
@@ -217,7 +217,7 @@ qb_rb_open_2(const char *name, size_t size, uint32_t flags,
217217
* They have to be separate.
218218
*/
219219
if (flags & QB_RB_FLAG_CREATE) {
220-
snprintf(filename, PATH_MAX, "qb-%s-data", name);
220+
snprintf(filename, PATH_MAX, "%s-data", name);
221221
fd_data = qb_sys_mmap_file_open(path,
222222
filename,
223223
real_size, file_flags);

lib/unix.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ qb_sys_mmap_file_open(char *path, const char *file, size_t bytes,
8181
(void)strlcpy(path, file, PATH_MAX);
8282
} else {
8383
#if defined(QB_LINUX) || defined(QB_CYGWIN)
84-
snprintf(path, PATH_MAX, "/dev/shm/%s", file);
84+
/* This is only now called when talking to an old libqb
85+
where we need to add qb- to the name */
86+
snprintf(path, PATH_MAX, "/dev/shm/qb-%s", file);
8587
#else
8688
snprintf(path, PATH_MAX, "%s/%s", SOCKETDIR, file);
8789
is_absolute = path;

0 commit comments

Comments
 (0)