varnish-cache/bin/varnishd/mgt/mgt_vcc.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2015 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 *
30
 * VCL compiler stuff
31
 */
32
33
#include "config.h"
34
35
#include <limits.h>
36
#include <fcntl.h>
37
#include <stdio.h>
38
#include <stdlib.h>
39
#include <string.h>
40
#include <unistd.h>
41
#include <sys/stat.h>
42
43
#include "mgt/mgt.h"
44
#include "mgt/mgt_vcl.h"
45
#include "common/heritage.h"
46
#include "storage/storage.h"
47
48
#include "libvcc.h"
49
#include "vcli_serve.h"
50
#include "vfil.h"
51
#include "vsub.h"
52
#include "vtim.h"
53
54
struct vcc_priv {
55
        unsigned        magic;
56
#define VCC_PRIV_MAGIC  0x70080cb8
57
        const char      *vclsrc;
58
        const char      *vclsrcfile;
59
        struct vsb      *dir;
60
        struct vsb      *csrcfile;
61
        struct vsb      *libfile;
62
        struct vsb      *symfile;
63
};
64
65
enum vcc_fini_e {
66
        VCC_SUCCESS,
67
        VCC_FAILED,
68
};
69
70
char *mgt_cc_cmd;
71
char *mgt_cc_cmd_def;
72
char *mgt_cc_warn;
73
const char *mgt_vcl_path;
74
const char *mgt_vmod_path;
75
76
#define VGC_SRC         "vgc.c"
77
#define VGC_LIB         "vgc.so"
78
#define VGC_SYM         "vgc.sym"
79
80
/*--------------------------------------------------------------------*/
81
82
void
83 40
mgt_DumpBuiltin(void)
84
{
85 40
        printf("%s\n", builtin_vcl);
86 40
}
87
88
/*--------------------------------------------------------------------
89
 * Invoke system VCC compiler in a sub-process
90
 */
91
92
static void
93 40
vcc_vext_iter_func(const char *filename, void *priv)
94
{
95
        struct vsb *sb;
96
97
        /* VCC runs in the per-VCL subdir */
98 40
        sb = VSB_new_auto();
99 40
        AN(sb);
100 40
        VSB_cat(sb, "../");
101 40
        VSB_cat(sb, filename);
102 40
        AZ(VSB_finish(sb));
103 40
        VCC_VEXT(priv, VSB_data(sb));
104 40
        VSB_destroy(&sb);
105 40
}
106
107
static void v_noreturn_ v_matchproto_(vsub_func_f)
108 59920
run_vcc(void *priv)
109
{
110 59920
        struct vsb *sb = NULL;
111
        struct vclprog *vpg;
112
        struct vcc_priv *vp;
113
        struct vcc *vcc;
114
        struct stevedore *stv;
115
        int i;
116
117 59920
        VJ_subproc(JAIL_SUBPROC_VCC);
118 59920
        CAST_OBJ_NOTNULL(vp, priv, VCC_PRIV_MAGIC);
119
120 59920
        AZ(chdir(VSB_data(vp->dir)));
121
122 59920
        vcc = VCC_New();
123 59920
        AN(vcc);
124 59920
        VCC_Builtin_VCL(vcc, builtin_vcl);
125 59920
        VCC_VCL_path(vcc, mgt_vcl_path);
126 59920
        VCC_VMOD_path(vcc, mgt_vmod_path);
127
128
#define VCC_FEATURE_BIT(U, l, d)                        \
129
        VCC_Opt_ ## l(vcc, MGT_VCC_FEATURE(VCC_FEATURE_ ## U));
130
#include "tbl/vcc_feature_bits.h"
131
132
        vext_iter(vcc_vext_iter_func, vcc);
133
134 179960
        STV_Foreach(stv)
135 120040
                VCC_Predef(vcc, "VCL_STEVEDORE", stv->ident);
136 163120
        VTAILQ_FOREACH(vpg, &vclhead, list)
137 104880
                if (mcf_is_label(vpg))
138 1680
                        VCC_Predef(vcc, "VCL_VCL", vpg->name);
139
        i = VCC_Compile(vcc, &sb, vp->vclsrc, vp->vclsrcfile,
140
            VGC_SRC, VGC_SYM);
141 59920
        if (VSB_len(sb))
142 12280
                printf("%s", VSB_data(sb));
143
        VSB_destroy(&sb);
144
        exit(i == 0 ? 0 : 2);
145
}
146
147
/*--------------------------------------------------------------------
148
 * Expand the cc_command argument
149
 */
150
151
static const char *
152 48400
cc_expand(struct vsb *sb, const char *cc_cmd, char exp)
153
{
154
        char buf[PATH_MAX];
155
        const char *p;
156
        int pct;
157
158 48400
        AN(sb);
159 48400
        AN(cc_cmd);
160
161 3485240
        for (p = cc_cmd, pct = 0; *p; ++p) {
162 3436840
                if (pct) {
163 145400
                        switch (*p) {
164
                        case 's':
165 48360
                                VSB_cat(sb, VGC_SRC);
166 48360
                                break;
167
                        case 'o':
168 48360
                                VSB_cat(sb, VGC_LIB);
169 48360
                                break;
170
                        case 'w':
171 48400
                                VSB_cat(sb, mgt_cc_warn);
172 48400
                                break;
173
                        case 'd':
174 40
                                VSB_cat(sb, mgt_cc_cmd_def);
175 40
                                break;
176
                        case 'D':
177 40
                                if (exp == pct)
178 0
                                        return ("recursive expansion");
179 40
                                AZ(cc_expand(sb, mgt_cc_cmd_def, pct));
180 40
                                break;
181
                        case 'n':
182 40
                                AN(getcwd(buf, sizeof buf));
183 40
                                VSB_cat(sb, buf);
184 40
                                break;
185
                        case '%':
186 160
                                VSB_putc(sb, '%');
187 160
                                break;
188
                        default:
189 0
                                VSB_putc(sb, '%');
190 0
                                VSB_putc(sb, *p);
191 0
                                break;
192
                        }
193 145400
                        pct = 0;
194 3436840
                } else if (*p == '%') {
195 145400
                        pct = 1;
196 145400
                } else {
197 3146040
                        VSB_putc(sb, *p);
198
                }
199 3436840
        }
200 48400
        if (pct)
201 0
                VSB_putc(sb, '%');
202 48400
        return (NULL);
203 48400
}
204
205
/*--------------------------------------------------------------------
206
 * Invoke system C compiler in a sub-process
207
 */
208
209
static void v_matchproto_(vsub_func_f)
210 48360
run_cc(void *priv)
211
{
212
        struct vcc_priv *vp;
213
        struct vsb *sb;
214
        const char *err;
215
216 48360
        VJ_subproc(JAIL_SUBPROC_CC);
217 48360
        CAST_OBJ_NOTNULL(vp, priv, VCC_PRIV_MAGIC);
218
219 48360
        sb = VSB_new_auto();
220 48360
        AN(sb);
221 48360
        err = cc_expand(sb, mgt_cc_cmd, '\0');
222 48360
        if (err != NULL) {
223 0
                VSB_destroy(&sb);
224 0
                fprintf(stderr, "cc_command: %s\n", err);
225 0
                exit(1);
226
        }
227 48360
        AZ(VSB_finish(sb));
228
229 48360
        AZ(chdir(VSB_data(vp->dir)));
230
231 48360
        (void)umask(027);
232 48360
        (void)execl("/bin/sh", "/bin/sh", "-c", VSB_data(sb), (char*)0);
233 0
        VSB_destroy(&sb);                               // For flexelint
234 0
}
235
236
/*--------------------------------------------------------------------
237
 * Attempt to open compiled VCL in a sub-process
238
 */
239
240
static void v_noreturn_ v_matchproto_(vsub_func_f)
241 47800
run_dlopen(void *priv)
242
{
243
        struct vcc_priv *vp;
244
245 47800
        VJ_subproc(JAIL_SUBPROC_VCLLOAD);
246 47800
        CAST_OBJ_NOTNULL(vp, priv, VCC_PRIV_MAGIC);
247 47800
        if (VCL_TestLoad(VSB_data(vp->libfile)))
248 80
                exit(1);
249 47720
        exit(0);
250
}
251
252
/*--------------------------------------------------------------------
253
 * Touch a filename and make it available to privsep-privs
254
 */
255
256
static int
257 119840
mgt_vcc_touchfile(const char *fn, struct vsb *sb)
258
{
259
        int i;
260
261 119840
        i = open(fn, O_WRONLY|O_CREAT|O_TRUNC, 0640);
262 119840
        if (i < 0) {
263 0
                VSB_printf(sb, "Failed to create %s: %s\n",
264 0
                    fn, VAS_errtxt(errno));
265 0
                return (2);
266
        }
267 119840
        closefd(&i);
268 119840
        return (0);
269 119840
}
270
271
/*--------------------------------------------------------------------
272
 * Compile a VCL program, return shared object, errors in sb.
273
 */
274
275
static unsigned
276 59920
mgt_vcc_compile(struct vcc_priv *vp, struct vsb *sb, int C_flag)
277
{
278
        char *csrc;
279
        unsigned subs;
280
281 59920
        AN(sb);
282 59920
        VSB_clear(sb);
283 59920
        if (mgt_vcc_touchfile(VSB_data(vp->csrcfile), sb))
284 0
                return (2);
285 59920
        if (mgt_vcc_touchfile(VSB_data(vp->libfile), sb))
286 0
                return (2);
287
288 59920
        VJ_master(JAIL_MASTER_SYSTEM);
289 59920
        subs = VSUB_run(sb, run_vcc, vp, "VCC-compiler", -1);
290 59920
        VJ_master(JAIL_MASTER_LOW);
291 59920
        if (subs)
292 11560
                return (subs);
293
294 48360
        if (C_flag) {
295 160
                csrc = VFIL_readfile(NULL, VSB_data(vp->csrcfile), NULL);
296 160
                AN(csrc);
297 160
                VSB_cat(sb, csrc);
298 160
                free(csrc);
299
300 160
                VSB_cat(sb, "/* EXTERNAL SYMBOL TABLE\n");
301 160
                csrc = VFIL_readfile(NULL, VSB_data(vp->symfile), NULL);
302 160
                AN(csrc);
303 160
                VSB_cat(sb, csrc);
304 160
                VSB_cat(sb, "*/\n");
305 160
                free(csrc);
306 160
        }
307
308 48360
        VJ_master(JAIL_MASTER_SYSTEM);
309 48360
        subs = VSUB_run(sb, run_cc, vp, "C-compiler", 10);
310 48360
        VJ_master(JAIL_MASTER_LOW);
311 48360
        if (subs)
312 0
                return (subs);
313
314 48360
        VJ_master(JAIL_MASTER_SYSTEM);
315 48360
        subs = VSUB_run(sb, run_dlopen, vp, "dlopen", 10);
316 48360
        VJ_master(JAIL_MASTER_LOW);
317 48360
        return (subs);
318 59920
}
319
320
/*--------------------------------------------------------------------*/
321
322
static void
323 59920
mgt_vcc_init_vp(struct vcc_priv *vp)
324
{
325 59920
        INIT_OBJ(vp, VCC_PRIV_MAGIC);
326 59920
        vp->csrcfile = VSB_new_auto();
327 59920
        AN(vp->csrcfile);
328 59920
        vp->libfile = VSB_new_auto();
329 59920
        AN(vp->libfile);
330 59920
        vp->symfile = VSB_new_auto();
331 59920
        AN(vp->symfile);
332 59920
        vp->dir = VSB_new_auto();
333 59920
        AN(vp->dir);
334 59920
}
335
336
static void
337 59920
mgt_vcc_fini_vp(struct vcc_priv *vp, enum vcc_fini_e vcc_status)
338
{
339 59920
        int ignore_enoent = (vcc_status == VCC_FAILED);
340
341 59920
        if (!MGT_DO_DEBUG(DBG_VCL_KEEP)) {
342 59720
                VJ_unlink(VSB_data(vp->csrcfile), ignore_enoent);
343 59720
                VJ_unlink(VSB_data(vp->symfile), ignore_enoent);
344 59720
                if (vcc_status != VCC_SUCCESS) {
345 11680
                        VJ_unlink(VSB_data(vp->libfile), ignore_enoent);
346 11680
                        VJ_rmdir(VSB_data(vp->dir));
347 11680
                }
348 59720
        }
349 59920
        VSB_destroy(&vp->csrcfile);
350 59920
        VSB_destroy(&vp->libfile);
351 59920
        VSB_destroy(&vp->symfile);
352 59920
        VSB_destroy(&vp->dir);
353 59920
}
354
355
char *
356 59920
mgt_VccCompile(struct cli *cli, struct vclprog *vcl, const char *vclname,
357
    const char *vclsrc, const char *vclsrcfile, int C_flag)
358
{
359
        struct vcc_priv vp[1];
360
        struct vsb *sb;
361
        unsigned status;
362
        char *p;
363
364 59920
        AN(cli);
365
366 59920
        sb = VSB_new_auto();
367 59920
        AN(sb);
368
369 59920
        mgt_vcc_init_vp(vp);
370 59920
        vp->vclsrc = vclsrc;
371 59920
        vp->vclsrcfile = vclsrcfile;
372
373
        /*
374
         * The subdirectory must have a unique name to 100% certain evade
375
         * the refcounting semantics of dlopen(3).
376
         *
377
         * Bad implementations of dlopen(3) think the shlib you are opening
378
         * is the same, if the filename is the same as one already opened.
379
         *
380
         * Sensible implementations do a stat(2) and requires st_ino and
381
         * st_dev to also match.
382
         *
383
         * A correct implementation would run on filesystems which tickle
384
         * st_gen, and also insist that be the identical, before declaring
385
         * a match.
386
         *
387
         * Since no correct implementations are known to exist, we are subject
388
         * to really interesting races if you do something like:
389
         *
390
         *      (running on 'boot' vcl)
391
         *      vcl.load foo /foo.vcl
392
         *      vcl.use foo
393
         *      few/slow requests
394
         *      vcl.use boot
395
         *      vcl.discard foo
396
         *      vcl.load foo /foo.vcl   // dlopen(3) says "same-same"
397
         *      vcl.use foo
398
         *
399
         * Because discard of the first 'foo' lingers on non-zero reference
400
         * count, and when it finally runs, it trashes the second 'foo' because
401
         * dlopen(3) decided they were really the same thing.
402
         *
403
         * The Best way to reproduce this is to have regexps in the VCL.
404
         */
405
406 59920
        VSB_printf(vp->dir, "vcl_%s.%.6f", vclname, VTIM_real());
407 59920
        AZ(VSB_finish(vp->dir));
408
409 59920
        VSB_printf(vp->csrcfile, "%s/%s", VSB_data(vp->dir), VGC_SRC);
410 59920
        AZ(VSB_finish(vp->csrcfile));
411
412 59920
        VSB_printf(vp->libfile, "%s/%s", VSB_data(vp->dir), VGC_LIB);
413 59920
        AZ(VSB_finish(vp->libfile));
414
415 59920
        VSB_printf(vp->symfile, "%s/%s", VSB_data(vp->dir), VGC_SYM);
416 59920
        AZ(VSB_finish(vp->symfile));
417
418 59920
        if (VJ_make_subdir(VSB_data(vp->dir), "VCL", cli->sb)) {
419 0
                mgt_vcc_fini_vp(vp, VCC_FAILED);
420 0
                VSB_destroy(&sb);
421 0
                VCLI_Out(cli, "VCL compilation failed");
422 0
                VCLI_SetResult(cli, CLIS_PARAM);
423 0
                return (NULL);
424
        }
425
426 59920
        status = mgt_vcc_compile(vp, sb, C_flag);
427 59920
        AZ(VSB_finish(sb));
428 59920
        if (VSB_len(sb) > 0)
429 13120
                VCLI_Out(cli, "%s", VSB_data(sb));
430 48280
        VSB_destroy(&sb);
431
432 48280
        if (status || C_flag) {
433 11640
                mgt_vcc_fini_vp(vp, VCC_FAILED);
434 11640
                if (status) {
435 11640
                        VCLI_Out(cli, "VCL compilation failed");
436 11640
                        VCLI_SetResult(cli, CLIS_PARAM);
437 11640
                }
438 11800
                return (NULL);
439
        }
440
441 48120
        p = VFIL_readfile(NULL, VSB_data(vp->symfile), NULL);
442 48120
        AN(p);
443 48120
        mgt_vcl_symtab(vcl, p);
444
445 48120
        REPLACE(p, VSB_data(vp->libfile));
446 48120
        mgt_vcc_fini_vp(vp, VCC_SUCCESS);
447 48120
        return (p);
448 59920
}