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 36500
#include <limits.h>
36
#include <fcntl.h>
37
#include <stdio.h>
38
#include <stdlib.h>
39 36500
#include <string.h>
40
#include <unistd.h>
41
#include <sys/stat.h>
42
43 36500
#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 25
mgt_DumpBuiltin(void)
84
{
85 25
        printf("%s\n", builtin_vcl);
86 25
}
87
88
/*--------------------------------------------------------------------
89
 * Invoke system VCC compiler in a sub-process
90
 */
91
92
static void
93 25
vcc_vext_iter_func(const char *filename, void *priv)
94
{
95
        struct vsb *sb;
96
97
        /* VCC runs in the per-VCL subdir */
98 25
        sb = VSB_new_auto();
99 25
        AN(sb);
100 25
        VSB_cat(sb, "../");
101 25
        VSB_cat(sb, filename);
102 25
        AZ(VSB_finish(sb));
103 25
        VCC_VEXT(priv, VSB_data(sb));
104 25
        VSB_destroy(&sb);
105 25
}
106
107
static void v_noreturn_ v_matchproto_(vsub_func_f)
108 36500
run_vcc(void *priv)
109
{
110 36500
        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 36500
        VJ_subproc(JAIL_SUBPROC_VCC);
118 36500
        CAST_OBJ_NOTNULL(vp, priv, VCC_PRIV_MAGIC);
119
120 36500
        AZ(chdir(VSB_data(vp->dir)));
121
122 36500
        vcc = VCC_New();
123 36500
        AN(vcc);
124 36500
        VCC_Builtin_VCL(vcc, builtin_vcl);
125 36500
        VCC_VCL_path(vcc, mgt_vcl_path);
126 36500
        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 36500
        vext_iter(vcc_vext_iter_func, vcc);
133
134 109625
        STV_Foreach(stv)
135 73125
                VCC_Predef(vcc, "VCL_STEVEDORE", stv->ident);
136 99250
        VTAILQ_FOREACH(vpg, &vclhead, list)
137 63800
                if (mcf_is_label(vpg))
138 1050
                        VCC_Predef(vcc, "VCL_VCL", vpg->name);
139 36500
        i = VCC_Compile(vcc, &sb, vp->vclsrc, vp->vclsrcfile,
140
            VGC_SRC, VGC_SYM);
141 36500
        if (VSB_len(sb))
142 7675
                printf("%s", VSB_data(sb));
143 36500
        VSB_destroy(&sb);
144 36500
        exit(i == 0 ? 0 : 2);
145
}
146
147
/*--------------------------------------------------------------------
148
 * Expand the cc_command argument
149
 */
150
151
static const char *
152 29300
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 29300
        AN(sb);
159 29300
        AN(cc_cmd);
160
161 2109875
        for (p = cc_cmd, pct = 0; *p; ++p) {
162 2080575
                if (pct) {
163 88025
                        switch (*p) {
164
                        case 's':
165 29275
                                VSB_cat(sb, VGC_SRC);
166 29275
                                break;
167
                        case 'o':
168 29275
                                VSB_cat(sb, VGC_LIB);
169 29275
                                break;
170
                        case 'w':
171 29300
                                VSB_cat(sb, mgt_cc_warn);
172 29300
                                break;
173
                        case 'd':
174 25
                                VSB_cat(sb, mgt_cc_cmd_def);
175 25
                                break;
176
                        case 'D':
177 25
                                if (exp == pct)
178 0
                                        return ("recursive expansion");
179 25
                                AZ(cc_expand(sb, mgt_cc_cmd_def, pct));
180 25
                                break;
181
                        case 'n':
182 25
                                AN(getcwd(buf, sizeof buf));
183 25
                                VSB_cat(sb, buf);
184 25
                                break;
185
                        case '%':
186 100
                                VSB_putc(sb, '%');
187 100
                                break;
188
                        default:
189 0
                                VSB_putc(sb, '%');
190 0
                                VSB_putc(sb, *p);
191 0
                                break;
192
                        }
193 88025
                        pct = 0;
194 2080575
                } else if (*p == '%') {
195 88025
                        pct = 1;
196 88025
                } else {
197 1904525
                        VSB_putc(sb, *p);
198
                }
199 2080575
        }
200 29300
        if (pct)
201 0
                VSB_putc(sb, '%');
202 29300
        return (NULL);
203 29300
}
204
205
/*--------------------------------------------------------------------
206
 * Invoke system C compiler in a sub-process
207
 */
208
209
static void v_matchproto_(vsub_func_f)
210 29275
run_cc(void *priv)
211
{
212
        struct vcc_priv *vp;
213
        struct vsb *sb;
214
        const char *err;
215
216 29275
        VJ_subproc(JAIL_SUBPROC_CC);
217 29275
        CAST_OBJ_NOTNULL(vp, priv, VCC_PRIV_MAGIC);
218
219 29275
        sb = VSB_new_auto();
220 29275
        AN(sb);
221 29275
        err = cc_expand(sb, mgt_cc_cmd, '\0');
222 29275
        if (err != NULL) {
223 0
                VSB_destroy(&sb);
224 0
                fprintf(stderr, "cc_command: %s\n", err);
225 0
                exit(1);
226
        }
227 29275
        AZ(VSB_finish(sb));
228
229 29275
        AZ(chdir(VSB_data(vp->dir)));
230
231 29275
        (void)umask(027);
232 29275
        (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 28925
run_dlopen(void *priv)
242
{
243
        struct vcc_priv *vp;
244
245 28925
        VJ_subproc(JAIL_SUBPROC_VCLLOAD);
246 28925
        CAST_OBJ_NOTNULL(vp, priv, VCC_PRIV_MAGIC);
247 28925
        if (VCL_TestLoad(VSB_data(vp->libfile)))
248 50
                exit(1);
249 28875
        exit(0);
250
}
251
252
/*--------------------------------------------------------------------
253
 * Touch a filename and make it available to privsep-privs
254
 */
255
256
static int
257 73000
mgt_vcc_touchfile(const char *fn, struct vsb *sb)
258
{
259
        int i;
260
261 73000
        i = open(fn, O_WRONLY|O_CREAT|O_TRUNC, 0640);
262 73000
        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 73000
        closefd(&i);
268 73000
        return (0);
269 73000
}
270
271
/*--------------------------------------------------------------------
272
 * Compile a VCL program, return shared object, errors in sb.
273
 */
274
275
static unsigned
276 36500
mgt_vcc_compile(struct vcc_priv *vp, struct vsb *sb, int C_flag)
277
{
278
        char *csrc;
279
        unsigned subs;
280
281 36500
        AN(sb);
282 36500
        VSB_clear(sb);
283 36500
        if (mgt_vcc_touchfile(VSB_data(vp->csrcfile), sb))
284 0
                return (2);
285 36500
        if (mgt_vcc_touchfile(VSB_data(vp->libfile), sb))
286 0
                return (2);
287
288 36500
        VJ_master(JAIL_MASTER_SYSTEM);
289 36500
        subs = VSUB_run(sb, run_vcc, vp, "VCC-compiler", -1);
290 36500
        VJ_master(JAIL_MASTER_LOW);
291 36500
        if (subs)
292 7225
                return (subs);
293
294 29275
        if (C_flag) {
295 100
                csrc = VFIL_readfile(NULL, VSB_data(vp->csrcfile), NULL);
296 100
                AN(csrc);
297 100
                VSB_cat(sb, csrc);
298 100
                free(csrc);
299
300 100
                VSB_cat(sb, "/* EXTERNAL SYMBOL TABLE\n");
301 100
                csrc = VFIL_readfile(NULL, VSB_data(vp->symfile), NULL);
302 100
                AN(csrc);
303 100
                VSB_cat(sb, csrc);
304 100
                VSB_cat(sb, "*/\n");
305 100
                free(csrc);
306 100
        }
307
308 29275
        VJ_master(JAIL_MASTER_SYSTEM);
309 29275
        subs = VSUB_run(sb, run_cc, vp, "C-compiler", 10);
310 29275
        VJ_master(JAIL_MASTER_LOW);
311 29275
        if (subs)
312 0
                return (subs);
313
314 29275
        VJ_master(JAIL_MASTER_SYSTEM);
315 29275
        subs = VSUB_run(sb, run_dlopen, vp, "dlopen", 10);
316 29275
        VJ_master(JAIL_MASTER_LOW);
317 29275
        return (subs);
318 36500
}
319
320
/*--------------------------------------------------------------------*/
321
322
static void
323 36500
mgt_vcc_init_vp(struct vcc_priv *vp)
324
{
325 36500
        INIT_OBJ(vp, VCC_PRIV_MAGIC);
326 36500
        vp->csrcfile = VSB_new_auto();
327 36500
        AN(vp->csrcfile);
328 36500
        vp->libfile = VSB_new_auto();
329 36500
        AN(vp->libfile);
330 36500
        vp->symfile = VSB_new_auto();
331 36500
        AN(vp->symfile);
332 36500
        vp->dir = VSB_new_auto();
333 36500
        AN(vp->dir);
334 36500
}
335
336
static void
337 36500
mgt_vcc_fini_vp(struct vcc_priv *vp, enum vcc_fini_e vcc_status)
338
{
339 36500
        int ignore_enoent = (vcc_status == VCC_FAILED);
340
341 36500
        if (!MGT_DO_DEBUG(DBG_VCL_KEEP)) {
342 36375
                VJ_unlink(VSB_data(vp->csrcfile), ignore_enoent);
343 36375
                VJ_unlink(VSB_data(vp->symfile), ignore_enoent);
344 36375
                if (vcc_status != VCC_SUCCESS) {
345 7300
                        VJ_unlink(VSB_data(vp->libfile), ignore_enoent);
346 7300
                        VJ_rmdir(VSB_data(vp->dir));
347 7300
                }
348 36375
        }
349 36500
        VSB_destroy(&vp->csrcfile);
350 36500
        VSB_destroy(&vp->libfile);
351 36500
        VSB_destroy(&vp->symfile);
352 36500
        VSB_destroy(&vp->dir);
353 36500
}
354
355
char *
356 36500
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 36500
        AN(cli);
365
366 36500
        sb = VSB_new_auto();
367 36500
        AN(sb);
368
369 36500
        mgt_vcc_init_vp(vp);
370 36500
        vp->vclsrc = vclsrc;
371 36500
        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 36500
        VSB_printf(vp->dir, "vcl_%s.%.6f", vclname, VTIM_real());
407 36500
        AZ(VSB_finish(vp->dir));
408
409 36500
        VSB_printf(vp->csrcfile, "%s/%s", VSB_data(vp->dir), VGC_SRC);
410 36500
        AZ(VSB_finish(vp->csrcfile));
411
412 36500
        VSB_printf(vp->libfile, "%s/%s", VSB_data(vp->dir), VGC_LIB);
413 36500
        AZ(VSB_finish(vp->libfile));
414
415 36500
        VSB_printf(vp->symfile, "%s/%s", VSB_data(vp->dir), VGC_SYM);
416 36500
        AZ(VSB_finish(vp->symfile));
417
418 36500
        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 36500
        status = mgt_vcc_compile(vp, sb, C_flag);
427 36500
        AZ(VSB_finish(sb));
428 36500
        if (VSB_len(sb) > 0)
429 8200
                VCLI_Out(cli, "%s", VSB_data(sb));
430 29225
        VSB_destroy(&sb);
431
432 29225
        if (status || C_flag) {
433 7275
                mgt_vcc_fini_vp(vp, VCC_FAILED);
434 7275
                if (status) {
435 7275
                        VCLI_Out(cli, "VCL compilation failed");
436 7275
                        VCLI_SetResult(cli, CLIS_PARAM);
437 7275
                }
438 7375
                return (NULL);
439
        }
440
441 29125
        p = VFIL_readfile(NULL, VSB_data(vp->symfile), NULL);
442 29125
        AN(p);
443 29125
        mgt_vcl_symtab(vcl, p);
444
445 29125
        REPLACE(p, VSB_data(vp->libfile));
446 29125
        mgt_vcc_fini_vp(vp, VCC_SUCCESS);
447 29125
        return (p);
448 36500
}