aboutsummaryrefslogtreecommitdiffhomepage
path: root/experimental/webtry/main.cpp
blob: a83a60842d5de26b151b7d69cef000a5d8cdc98f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#include <sys/time.h>
#include <sys/resource.h>

#include "GrContextFactory.h"

#include "SkCanvas.h"
#include "SkCommandLineFlags.h"
#include "SkData.h"
#include "SkForceLinking.h"
#include "SkGraphics.h"
#include "SkImageDecoder.h"
#include "SkImageEncoder.h"
#include "SkImageInfo.h"
#include "SkOSFile.h"
#include "SkStream.h"
#include "SkSurface.h"

#include "seccomp_bpf.h"

__SK_FORCE_IMAGE_DECODER_LINKING;

DEFINE_string(out, "", "Output basename; fiddle will append the config used and the appropriate extension");
DEFINE_string(source, "", "Filename of the source image.");
DEFINE_int32(width, 256, "Width of output image.");
DEFINE_int32(height, 256, "Height of output image.");
DEFINE_bool(gpu, false, "Use GPU (Mesa) rendering.");
DEFINE_bool(raster, true, "Use Raster rendering.");
DEFINE_bool(pdf, false, "Use PDF rendering.");

// Defined in template.cpp.
extern SkBitmap source;

static bool install_syscall_filter() {

#ifndef SK_UNSAFE_BUILD_DESKTOP_ONLY
    struct sock_filter filter[] = {
        /* Grab the system call number. */
        EXAMINE_SYSCALL,
        /* List allowed syscalls. */
        ALLOW_SYSCALL(exit_group),
        ALLOW_SYSCALL(exit),
        ALLOW_SYSCALL(fstat),
        ALLOW_SYSCALL(read),
        ALLOW_SYSCALL(write),
        ALLOW_SYSCALL(close),
        ALLOW_SYSCALL(mmap),
        ALLOW_SYSCALL(munmap),
        ALLOW_SYSCALL(brk),
        ALLOW_SYSCALL(futex),
        KILL_PROCESS,
    };
    struct sock_fprog prog = {
        SK_ARRAY_COUNT(filter),
        filter,
    };

    // Lock down the app so that it can't get new privs, such as setuid.
    // Calling this is a requirement for an unpriviledged process to use mode
    // 2 seccomp filters, ala SECCOMP_MODE_FILTER, otherwise we'd have to be
    // root.
    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
        perror("prctl(NO_NEW_PRIVS)");
        goto failed;
    }
    // Now call seccomp and restrict the system calls that can be made to only
    // the ones in the provided filter list.
    if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
        perror("prctl(SECCOMP)");
        goto failed;
    }
    return true;

failed:
    if (errno == EINVAL) {
        fprintf(stderr, "SECCOMP_FILTER is not available. :(\n");
    }
    return false;
#else
    return true;
#endif /* SK_UNSAFE_BUILD_DESKTOP_ONLY */
}

static void setLimits() {
    struct rlimit n;

    // Limit to 5 seconds of CPU.
    n.rlim_cur = 5;
    n.rlim_max = 5;
    if (setrlimit(RLIMIT_CPU, &n)) {
        perror("setrlimit(RLIMIT_CPU)");
    }

    // Limit to 150M of Address space.
    n.rlim_cur = 150000000;
    n.rlim_max = 150000000;
    if (setrlimit(RLIMIT_AS, &n)) {
        perror("setrlimit(RLIMIT_CPU)");
    }
}

extern void draw(SkCanvas* canvas);

static void drawAndDump(SkSurface* surface, SkWStream* stream) {
    SkCanvas *canvas = surface->getCanvas();
    draw(canvas);

    // Write out the image as a PNG.
    SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
    SkAutoTUnref<SkData> data(image->encode(SkImageEncoder::kPNG_Type, 100));
    if (NULL == data.get()) {
        printf("Failed to encode\n");
        exit(1);
    }
    stream->write(data->data(), data->size());
}

static void drawRaster(SkWStream* stream, SkImageInfo info) {
    SkAutoTUnref<SkSurface> surface;
    surface.reset(SkSurface::NewRaster(info)); 
    drawAndDump(surface, stream);
}

static void drawGPU(SkWStream* stream, GrContext* gr, SkImageInfo info) {
    SkAutoTUnref<SkSurface> surface;
    surface.reset(SkSurface::NewRenderTarget(gr,info));

    drawAndDump(surface, stream);
}

static void drawPDF(SkWStream* stream, SkImageInfo info) {
    printf( "Not implemented yet...\n");
}

int main(int argc, char** argv) {
    SkCommandLineFlags::Parse(argc, argv);
    SkAutoGraphics init;

    if (FLAGS_out.count() == 0) {
      perror("The --out flag must have an argument.");
      return 1;
    }

    if (FLAGS_source.count() == 1) {
        const char *sourceDir = getenv("WEBTRY_INOUT");
        if (NULL == sourceDir) {
            sourceDir = "/skia_build/inout";
        }

        SkString sourcePath = SkOSPath::Join(sourceDir, FLAGS_source[0]);
        if (!SkImageDecoder::DecodeFile(sourcePath.c_str(), &source)) {
            perror("Unable to read the source image.");
        }
    }

    // make sure to open any needed output files before we set up the security
    // jail

    SkWStream* streams[3] = {NULL, NULL, NULL};

    if (FLAGS_raster) {
        SkString outPath;
        outPath.printf("%s_raster.png", FLAGS_out[0]);
        streams[0] = SkNEW_ARGS(SkFILEWStream,(outPath.c_str()));
    }
    if (FLAGS_gpu) {
        SkString outPath;
        outPath.printf("%s_gpu.png", FLAGS_out[0]);
        streams[1] = SkNEW_ARGS(SkFILEWStream,(outPath.c_str()));
    }
    if (FLAGS_pdf) {
        SkString outPath;
        outPath.printf("%s.pdf", FLAGS_out[0]);
        streams[2] = SkNEW_ARGS(SkFILEWStream,(outPath.c_str()));
    }

    SkImageInfo info = SkImageInfo::MakeN32(FLAGS_width, FLAGS_height, kPremul_SkAlphaType);

    GrContext *gr = NULL;
    GrContextFactory* grFactory = NULL;

    // need to set up the GPU context before we install system call restrictions
    if (FLAGS_gpu) {
    
        GrContext::Options grContextOpts;
        grFactory = new GrContextFactory(grContextOpts);
        gr = grFactory->get(GrContextFactory::kMESA_GLContextType);
    }

    setLimits();

    if (!install_syscall_filter()) {
        return 1;
    }

    if (NULL != streams[0]) {
        drawRaster(streams[0], info);
    }
    if (NULL != streams[1]) {
        drawGPU(streams[1], gr, info);
    }
    if (NULL != streams[2]) {
        drawPDF(streams[2], info);
    }

    if (gr) {
        delete grFactory;
    }
}