1 // Copyright (C) 2012 The SBCELT Developers. All rights reserved.
2 // Use of this source code is governed by a BSD-style license
3 // that can be found in the LICENSE-file.
4 
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <stdlib.h>
8 #include <pthread.h>
9 #include <unistd.h>
10 #include <errno.h>
11 #include <sys/mman.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <string.h>
15 #include <signal.h>
16 
17 #include <sys/time.h>
18 #include <sys/syscall.h>
19 
20 #include "celt.h"
21 #include "../sbcelt-internal.h"
22 
23 #include "pdeath.h"
24 #include "eintr.h"
25 #include "futex.h"
26 #include "sbcelt-sandbox.h"
27 
28 #define SAMPLE_RATE 48000
29 
30 #ifdef DEBUG
31 # define debugf(fmt, ...) \
32 	do { \
33 		fprintf(stderr, "sbcelt-helper:%s():%u: " fmt "\n", \
34 			__FUNCTION__, __LINE__, ## __VA_ARGS__); \
35 		fflush(stderr); \
36 	} while (0)
37 #else
38  #define debugf(s, ...) do{} while (0)
39 #endif
40 
41 static struct SBCELTWorkPage *workpage = NULL;
42 static struct SBCELTDecoderPage *decpage = NULL;
43 static CELTMode *modes[SBCELT_SLOTS];
44 static CELTDecoder *decoders[SBCELT_SLOTS];
45 
SBCELT_DecodeSingleFrame()46 static void SBCELT_DecodeSingleFrame() {
47 	unsigned char *src = &workpage->encbuf[0];
48 	float *dst = &workpage->decbuf[0];
49 
50 	int idx = workpage->slot;
51 	struct SBCELTDecoderSlot *slot = &decpage->slots[idx];
52 	CELTMode *m = modes[idx];
53 	CELTDecoder *d = decoders[idx];
54 
55 	if (slot->dispose && m != NULL && d != NULL) {
56 		debugf("disposed of mode & decoder for slot=%i", idx);
57 		celt_mode_destroy(m);
58 		celt_decoder_destroy(d);
59 		m = modes[idx] = celt_mode_create(SAMPLE_RATE, SAMPLE_RATE / 100, NULL);
60 		d = decoders[idx] = celt_decoder_create(m, 1, NULL);
61 		slot->dispose = 0;
62 	}
63 
64 	if (m == NULL && d == NULL) {
65 		debugf("created mode & decoder for slot=%i", idx);
66 		m = modes[idx] = celt_mode_create(SAMPLE_RATE, SAMPLE_RATE / 100, NULL);
67 		d = decoders[idx] = celt_decoder_create(m, 1, NULL);
68 	}
69 
70 	debugf("got work for slot=%i", idx);
71 	unsigned int len = workpage->len;
72 	debugf("to decode: %p, %p, %u, %p", d, src, len, dst);
73 	if (len == 0) {
74 		celt_decode_float(d, NULL, 0, dst);
75 	} else {
76 		celt_decode_float(d, src, len, dst);
77 	}
78 
79 	debugf("decoded len=%u", len);
80 }
81 
SBCELT_FutexHelper()82 static int SBCELT_FutexHelper() {
83 	while (1) {
84 		// Wait for the lib to signal us.
85 		while (workpage->ready == 1) {
86 			int err = futex_wait(&workpage->ready, 1, NULL);
87 			if (err == 0) {
88 				break;
89 			}
90 		}
91 
92 		SBCELT_DecodeSingleFrame();
93 
94 		workpage->ready = 1;
95 
96 		if (!workpage->busywait) {
97 			futex_wake(&workpage->ready);
98 		}
99 	}
100 
101 	return -2;
102  }
103 
SBCELT_RWHelper()104 static int SBCELT_RWHelper() {
105 	while (1) {
106 		// Wait for the lib to signal us.
107 		if (HANDLE_EINTR(read(0, &workpage->pingpong, 1)) == -1) {
108 			return -2;
109 		}
110 
111 		SBCELT_DecodeSingleFrame();
112 
113 		if (HANDLE_EINTR(write(1, &workpage->pingpong, 1)) == -1) {
114 			return -3;
115 		}
116 	}
117 }
118 
main(int argc,char * argv[])119 int main(int argc, char *argv[]) {
120 	if (argc >= 2 && !strcmp(argv[1], "detect")) {
121 		debugf("in seccomp-detect mode");
122 		if (SBCELT_EnterSandbox(SBCELT_SANDBOX_CAPSICUM) == 0) {
123 			_exit(SBCELT_SANDBOX_CAPSICUM);
124 		}
125 		if (SBCELT_EnterSandbox(SBCELT_SANDBOX_SEATBELT) == 0) {
126 			_exit(SBCELT_SANDBOX_SEATBELT);
127 		}
128 		if (SBCELT_EnterSandbox(SBCELT_SANDBOX_SECCOMP_BPF) == 0) {
129 			_exit(SBCELT_SANDBOX_SECCOMP_BPF);
130 		}
131 		if (SBCELT_EnterSandbox(SBCELT_SANDBOX_SECCOMP_STRICT) == 0) {
132 			_exit(SBCELT_SANDBOX_SECCOMP_STRICT);
133 		}
134 		_exit(SBCELT_SANDBOX_NONE);
135 	}
136 
137 	debugf("helper running");
138 
139 	if (pdeath() == -1) {
140 		return 1;
141 	}
142 
143 	char shmfn[50];
144 	if (snprintf(&shmfn[0], 50, "/sbcelt-%lu", (unsigned long) getppid()) < 0) {
145 		return 2;
146 	}
147 
148 	int fd = shm_open(&shmfn[0], O_RDWR, 0600);
149 	if (fd == -1) {
150 		debugf("unable to open shm: %s (%i)", strerror(errno), errno);
151 		return 3;
152 	}
153 
154 	void *addr = mmap(NULL, SBCELT_PAGES*SBCELT_PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0);
155 	if (addr == MAP_FAILED) {
156 		debugf("unable to mmap: %s (%i)", strerror(errno), errno);
157 		return 5;
158 	}
159 	workpage = addr;
160 	decpage = addr+SBCELT_PAGE_SIZE;
161 
162 	debugf("workpage=%p, decpage=%p", workpage, decpage);
163 
164 	if (SBCELT_EnterSandbox(workpage->sandbox) == -1) {
165 		return 6;
166 	}
167 
168 	switch (workpage->mode) {
169 		case SBCELT_MODE_FUTEX:
170 			return SBCELT_FutexHelper();
171 		case SBCELT_MODE_RW:
172 			return SBCELT_RWHelper();
173 	}
174 
175 	return 7;
176 }
177