C++程序  |  132行  |  3.33 KB

#include <sys/time.h>
#include <sys/resource.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 "SkStream.h"
#include "SkSurface.h"

#include "seccomp_bpf.h"

__SK_FORCE_IMAGE_DECODER_LINKING;

DEFINE_string(out, "", "Filename of the PNG to write to.");
DEFINE_string(source, "", "Filename of the source image.");

// 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),
        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 50M of Address space.
    n.rlim_cur = 50000000;
    n.rlim_max = 50000000;
    if (setrlimit(RLIMIT_AS, &n)) {
        perror("setrlimit(RLIMIT_CPU)");
    }
}

extern void draw(SkCanvas* canvas);

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) {
       if (!SkImageDecoder::DecodeFile(FLAGS_source[0], &source)) {
           perror("Unable to read the source image.");
       }
    }

    SkFILEWStream stream(FLAGS_out[0]);

    SkImageInfo info = SkImageInfo::MakeN32(256, 256, kPremul_SkAlphaType);
    SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info));
    SkCanvas* canvas = surface->getCanvas();

    setLimits();

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

    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());
}