varnish-cache/bin/varnishd/mgt/mgt_vcc.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2015 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 *
29
 * VCL compiler stuff
30
 */
31
32
#include "config.h"
33
34
#include <errno.h>
35
#include <fcntl.h>
36
#include <stdio.h>
37
#include <stdlib.h>
38
#include <string.h>
39
#include <unistd.h>
40
#include <sys/stat.h>
41
42
#include "mgt/mgt.h"
43
#include "common/heritage.h"
44
#include "storage/storage.h"
45
46
#include "libvcc.h"
47
#include "vcli_serve.h"
48
#include "vfil.h"
49
#include "vsub.h"
50
#include "vav.h"
51
#include "vtim.h"
52
53
struct vcc_priv {
54
        unsigned        magic;
55
#define VCC_PRIV_MAGIC  0x70080cb8
56
        char            *dir;
57
        const char      *vclsrc;
58
        const char      *vclsrcfile;
59
        char            *csrcfile;
60
        char            *libfile;
61
};
62
63
char *mgt_cc_cmd;
64
const char *mgt_vcl_path;
65
const char *mgt_vmod_path;
66
unsigned mgt_vcc_err_unref;
67
unsigned mgt_vcc_allow_inline_c;
68
unsigned mgt_vcc_unsafe_path;
69
70
71
#define VGC_SRC         "vgc.c"
72
#define VGC_LIB         "vgc.so"
73
74
/*--------------------------------------------------------------------*/
75
76
void
77 4
mgt_DumpBuiltin(void)
78
{
79 4
        printf("%s\n", builtin_vcl);
80 4
}
81
82
/*--------------------------------------------------------------------
83
 * Invoke system VCC compiler in a sub-process
84
 */
85
86
static void v_matchproto_(vsub_func_f)
87 2118
run_vcc(void *priv)
88
{
89
        struct vsb *csrc;
90 2118
        struct vsb *sb = NULL;
91
        struct vcc_priv *vp;
92
        int fd, i, l;
93
        struct vcc *vcc;
94
        struct stevedore *stv;
95
96 2118
        VJ_subproc(JAIL_SUBPROC_VCC);
97 2118
        CAST_OBJ_NOTNULL(vp, priv, VCC_PRIV_MAGIC);
98
99 2118
        AZ(chdir(vp->dir));
100
101 2118
        vcc = VCC_New();
102 2118
        AN(vcc);
103 2118
        VCC_Builtin_VCL(vcc, builtin_vcl);
104 2118
        VCC_VCL_path(vcc, mgt_vcl_path);
105 2118
        VCC_VMOD_path(vcc, mgt_vmod_path);
106 2118
        VCC_Err_Unref(vcc, mgt_vcc_err_unref);
107 2118
        VCC_Allow_InlineC(vcc, mgt_vcc_allow_inline_c);
108 2118
        VCC_Unsafe_Path(vcc, mgt_vcc_unsafe_path);
109 8492
        STV_Foreach(stv)
110 4256
                VCC_Predef(vcc, "VCL_STEVEDORE", stv->ident);
111 2118
        mgt_vcl_export_labels(vcc);
112 2118
        csrc = VCC_Compile(vcc, &sb, vp->vclsrc, vp->vclsrcfile);
113 2118
        AZ(VSB_finish(sb));
114 2118
        if (VSB_len(sb))
115 380
                printf("%s", VSB_data(sb));
116 2118
        VSB_destroy(&sb);
117 2118
        if (csrc == NULL)
118 370
                exit(2);
119
120 1748
        fd = open(VGC_SRC, O_WRONLY|O_TRUNC|O_CREAT, 0600);
121 1748
        if (fd < 0) {
122 0
                fprintf(stderr, "VCC cannot open %s", vp->csrcfile);
123 0
                exit(2);
124
        }
125 1748
        l = VSB_len(csrc);
126 1748
        i = write(fd, VSB_data(csrc), l);
127 1748
        if (i != l) {
128 0
                fprintf(stderr, "VCC cannot write %s", vp->csrcfile);
129 0
                exit(2);
130
        }
131 1748
        closefd(&fd);
132 1748
        VSB_destroy(&csrc);
133 1748
        exit(0);
134
}
135
136
/*--------------------------------------------------------------------
137
 * Invoke system C compiler in a sub-process
138
 */
139
140
static void v_matchproto_(vsub_func_f)
141 1748
run_cc(void *priv)
142
{
143
        struct vcc_priv *vp;
144
        struct vsb *sb;
145
        int pct;
146
        char *p;
147
148 1748
        VJ_subproc(JAIL_SUBPROC_CC);
149 1748
        CAST_OBJ_NOTNULL(vp, priv, VCC_PRIV_MAGIC);
150
151 1748
        AZ(chdir(vp->dir));
152
153 1748
        sb = VSB_new_auto();
154 1748
        AN(sb);
155 823308
        for (p = mgt_cc_cmd, pct = 0; *p; ++p) {
156 821560
                if (pct) {
157 3496
                        switch (*p) {
158
                        case 's':
159 1748
                                VSB_cat(sb, VGC_SRC);
160 1748
                                break;
161
                        case 'o':
162 1748
                                VSB_cat(sb, VGC_LIB);
163 1748
                                break;
164
                        case '%':
165 0
                                VSB_putc(sb, '%');
166 0
                                break;
167
                        default:
168 0
                                VSB_putc(sb, '%');
169 0
                                VSB_putc(sb, *p);
170 0
                                break;
171
                        }
172 3496
                        pct = 0;
173 818064
                } else if (*p == '%') {
174 3496
                        pct = 1;
175
                } else {
176 814568
                        VSB_putc(sb, *p);
177
                }
178
        }
179 1748
        if (pct)
180 0
                VSB_putc(sb, '%');
181 1748
        AZ(VSB_finish(sb));
182
183 1748
        (void)umask(027);
184 1748
        (void)execl("/bin/sh", "/bin/sh", "-c", VSB_data(sb), (char*)0);
185 1748
        VSB_destroy(&sb);                               // For flexelint
186 0
}
187
188
/*--------------------------------------------------------------------
189
 * Attempt to open compiled VCL in a sub-process
190
 */
191
192
static void v_matchproto_(vsub_func_f)
193 1718
run_dlopen(void *priv)
194
{
195
        struct vcc_priv *vp;
196
197 1718
        VJ_subproc(JAIL_SUBPROC_VCLLOAD);
198 1718
        CAST_OBJ_NOTNULL(vp, priv, VCC_PRIV_MAGIC);
199 1718
        if (VCL_TestLoad(vp->libfile))
200 2
                exit(1);
201 1716
        exit(0);
202
}
203
204
/*--------------------------------------------------------------------
205
 * Touch a filename and make it available to privsep-privs
206
 */
207
208
static int
209 4236
mgt_vcc_touchfile(const char *fn, struct vsb *sb)
210
{
211
        int i;
212
213 4236
        i = open(fn, O_WRONLY|O_CREAT|O_TRUNC, 0640);
214 4236
        if (i < 0) {
215 0
                VSB_printf(sb, "Failed to create %s: %s", fn, strerror(errno));
216 0
                return (2);
217
        }
218 4236
        if (fchown(i, mgt_param.uid, mgt_param.gid) != 0)
219 4236
                if (geteuid() == 0)
220 0
                        VSB_printf(sb, "Failed to change owner on %s: %s\n",
221 0
                            fn, strerror(errno));
222 4236
        closefd(&i);
223 4236
        return (0);
224
}
225
226
/*--------------------------------------------------------------------
227
 * Compile a VCL program, return shared object, errors in sb.
228
 */
229
230
static unsigned
231 2118
mgt_vcc_compile(struct vcc_priv *vp, struct vsb *sb, int C_flag)
232
{
233
        char *csrc;
234
        unsigned subs;
235
236 2118
        if (mgt_vcc_touchfile(vp->csrcfile, sb))
237 0
                return (2);
238 2118
        if (mgt_vcc_touchfile(vp->libfile, sb))
239 0
                return (2);
240
241 2118
        subs = VSUB_run(sb, run_vcc, vp, "VCC-compiler", -1);
242 2118
        if (subs)
243 370
                return (subs);
244
245 1748
        if (C_flag) {
246 4
                csrc = VFIL_readfile(NULL, vp->csrcfile, NULL);
247 4
                AN(csrc);
248 4
                VSB_cat(sb, csrc);
249 4
                free(csrc);
250
        }
251
252 1748
        subs = VSUB_run(sb, run_cc, vp, "C-compiler", 10);
253 1748
        if (subs)
254 0
                return (subs);
255
256 1748
        subs = VSUB_run(sb, run_dlopen, vp, "dlopen", 10);
257 1748
        return (subs);
258
}
259
260
/*--------------------------------------------------------------------*/
261
262
char *
263 2118
mgt_VccCompile(struct cli *cli, struct vclprog *vcl, const char *vclname,
264
    const char *vclsrc, const char *vclsrcfile, int C_flag)
265
{
266
        struct vcc_priv vp;
267
        struct vsb *sb;
268
        unsigned status;
269
        char buf[1024];
270
        FILE *fcs;
271
        char **av;
272
        int ac;
273
274 2118
        AN(cli);
275
276 2118
        sb = VSB_new_auto();
277 2118
        XXXAN(sb);
278
279 2118
        INIT_OBJ(&vp, VCC_PRIV_MAGIC);
280 2118
        vp.vclsrc = vclsrc;
281 2118
        vp.vclsrcfile = vclsrcfile;
282
283
        /*
284
         * The subdirectory must have a unique name to 100% certain evade
285
         * the refcounting semantics of dlopen(3).
286
         *
287
         * Bad implementations of dlopen(3) think the shlib you are opening
288
         * is the same, if the filename is the same as one already opened.
289
         *
290
         * Sensible implementations do a stat(2) and requires st_ino and
291
         * st_dev to also match.
292
         *
293
         * A correct implementation would run on filesystems which tickle
294
         * st_gen, and also insist that be the identical, before declaring
295
         * a match.
296
         *
297
         * Since no correct implementations are known to exist, we are subject
298
         * to really interesting races if you do something like:
299
         *
300
         *      (running on 'boot' vcl)
301
         *      vcl.load foo /foo.vcl
302
         *      vcl.use foo
303
         *      few/slow requests
304
         *      vcl.use boot
305
         *      vcl.discard foo
306
         *      vcl.load foo /foo.vcl   // dlopen(3) says "same-same"
307
         *      vcl.use foo
308
         *
309
         * Because discard of the first 'foo' lingers on non-zero reference
310
         * count, and when it finally runs, it trashes the second 'foo' because
311
         * dlopen(3) decided they were really the same thing.
312
         *
313
         * The Best way to reproduce this is to have regexps in the VCL.
314
         */
315 2118
        VSB_printf(sb, "vcl_%s.%.9f", vclname, VTIM_real());
316 2118
        AZ(VSB_finish(sb));
317 2118
        vp.dir = strdup(VSB_data(sb));
318 2118
        AN(vp.dir);
319
320 2118
        if (VJ_make_subdir(vp.dir, "VCL", cli->sb)) {
321 0
                free(vp.dir);
322 0
                VSB_destroy(&sb);
323 0
                VCLI_Out(cli, "VCL compilation failed");
324 0
                VCLI_SetResult(cli, CLIS_PARAM);
325 0
                return (NULL);
326
        }
327
328 2118
        VSB_clear(sb);
329 2118
        VSB_printf(sb, "%s/%s", vp.dir, VGC_SRC);
330 2118
        AZ(VSB_finish(sb));
331 2118
        vp.csrcfile = strdup(VSB_data(sb));
332 2118
        AN(vp.csrcfile);
333 2118
        VSB_clear(sb);
334
335 2118
        VSB_printf(sb, "%s/%s", vp.dir, VGC_LIB);
336 2118
        AZ(VSB_finish(sb));
337 2118
        vp.libfile = strdup(VSB_data(sb));
338 2118
        AN(vp.csrcfile);
339 2118
        VSB_clear(sb);
340
341 2118
        status = mgt_vcc_compile(&vp, sb, C_flag);
342
343 2118
        AZ(VSB_finish(sb));
344 2118
        if (VSB_len(sb) > 0)
345 414
                VCLI_Out(cli, "%s", VSB_data(sb));
346 2118
        VSB_destroy(&sb);
347
348 2118
        if (status || C_flag) {
349 376
                (void)unlink(vp.csrcfile);
350 376
                free(vp.csrcfile);
351 376
                (void)unlink(vp.libfile);
352 376
                free(vp.libfile);
353 376
                (void)rmdir(vp.dir);
354 376
                free(vp.dir);
355 376
                if (status) {
356 372
                        VCLI_Out(cli, "VCL compilation failed");
357 372
                        VCLI_SetResult(cli, CLIS_PARAM);
358
                }
359 376
                return (NULL);
360
        }
361
362 1742
        fcs = fopen(vp.csrcfile, "r");
363 1742
        AN(fcs);
364
        while (1) {
365 646
                AN(fgets(buf, sizeof buf, fcs));
366 2388
                if (memcmp(buf, VCC_INFO_PREFIX, strlen(VCC_INFO_PREFIX)))
367 1742
                        break;
368 646
                av = VAV_Parse(buf, &ac, 0);
369 646
                AN(av);
370 646
                AZ(av[0]);
371 646
                AZ(strcmp(av[1], "/*"));
372 646
                AZ(strcmp(av[ac-1], "*/"));
373 646
                if (!strcmp(av[3], "VCL"))
374 32
                        mgt_vcl_depends(vcl, av[4]);
375 614
                else if (!strcmp(av[3], "VMOD"))
376 614
                        mgt_vcl_vmod(vcl, av[4], av[5]);
377
                else
378 0
                        WRONG("Wrong VCCINFO");
379 646
                VAV_Free(av);
380
        }
381 1742
        AZ(fclose(fcs));
382
383 1742
        (void)unlink(vp.csrcfile);
384 1742
        free(vp.csrcfile);
385
386 1742
        free(vp.dir);
387
388 1742
        VCLI_Out(cli, "VCL compiled.\n");
389
390 1742
        return (vp.libfile);
391
}