Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7ac013de authored by Tom Cherry's avatar Tom Cherry
Browse files

init: support setting rlimits per service

Add a new service option, `rlimit` that allows a given rlimit to be
set for a specific service instead of globally.

Use the same parsing, now allowing text such as 'cpu' or 'rtprio'
instead of relying on the enum value for the `setrlimit` builtin
command as well.

Bug: 63882119
Bug: 64894637

Test: boot bullhead, run a test app that attempts to set its rtprio to
      95, see that the priority set fails normally but passes when
      `rlimit rtprio 99 99` is used as its service option.
      See that this fails when `rlimit rtprio 50 50` is used as well.
Test: new unit tests

Change-Id: I4a13ca20e8529937d8b4bc11718ffaaf77523a52
parent df3e89be
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ cc_library_static {
        "security.cpp",
        "selinux.cpp",
        "service.cpp",
        "rlimit_parser.cpp",
        "tokenizer.cpp",
        "uevent_listener.cpp",
        "ueventd_parser.cpp",
@@ -163,6 +164,7 @@ cc_test {
        "init_test.cpp",
        "property_service_test.cpp",
        "result_test.cpp",
        "rlimit_parser_test.cpp",
        "service_test.cpp",
        "ueventd_test.cpp",
        "util_test.cpp",
+11 −1
Original line number Diff line number Diff line
@@ -216,6 +216,12 @@ runs the service.
  http://man7.org/linux/man-pages/man7/capabilities.7.html for a list of Linux
  capabilities.

`setrlimit <resource> <cur> <max>`
> This applies the given rlimit to the service. rlimits are inherited by child
  processes, so this effectively applies the given rlimit to the process tree
  started by this service.
  It is parsed similarly to the setrlimit command specified below.

`seclabel <seclabel>`
> Change to 'seclabel' before exec'ing this service.
  Primarily for use by services run from the rootfs, e.g. ueventd, adbd.
@@ -455,7 +461,11 @@ Commands
  within _value_.

`setrlimit <resource> <cur> <max>`
> Set the rlimit for a resource.
> Set the rlimit for a resource. This applies to all processes launched after
  the limit is set. It is intended to be set early in init and applied globally.
  _resource_ is best specified using its text representation ('cpu', 'rtio', etc
  or 'RLIM_CPU', 'RLIM_RTIO', etc). It also may be specified as the int value
  that the resource enum corresponds to.

`start <service>`
> Start a service running if it is not already running.
+4 −13
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@
#include "parser.h"
#include "property_service.h"
#include "reboot.h"
#include "rlimit_parser.h"
#include "service.h"
#include "signal_handler.h"
#include "util.h"
@@ -563,20 +564,10 @@ static Result<Success> do_setprop(const std::vector<std::string>& args) {
}

static Result<Success> do_setrlimit(const std::vector<std::string>& args) {
    int resource;
    if (!android::base::ParseInt(args[1], &resource)) {
        return Error() << "unable to parse resource, " << args[1];
    }

    struct rlimit limit;
    if (!android::base::ParseUint(args[2], &limit.rlim_cur)) {
        return Error() << "unable to parse rlim_cur, " << args[2];
    }
    if (!android::base::ParseUint(args[3], &limit.rlim_max)) {
        return Error() << "unable to parse rlim_max, " << args[3];
    }
    auto rlimit = ParseRlimit(args);
    if (!rlimit) return rlimit.error();

    if (setrlimit(resource, &limit) == -1) {
    if (setrlimit(rlimit->first, &rlimit->second) == -1) {
        return ErrnoError() << "setrlimit failed";
    }
    return Success();

init/rlimit_parser.cpp

0 → 100644
+78 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "rlimit_parser.h"

#include <android-base/parseint.h>
#include <android-base/strings.h>

using android::base::EqualsIgnoreCase;
using android::base::ParseInt;
using android::base::ParseUint;
using android::base::StartsWith;

namespace android {
namespace init {

// Builtins and service definitions both have their arguments start at 1 and finish at 3.
Result<std::pair<int, rlimit>> ParseRlimit(const std::vector<std::string>& args) {
    static const std::vector<std::pair<const char*, int>> text_to_resources = {
        {"cpu", 0},       {"fsize", 1}, {"data", 2},    {"stack", 3},
        {"core", 4},      {"rss", 5},   {"nproc", 6},   {"nofile", 7},
        {"memlock", 8},   {"as", 9},    {"locks", 10},  {"sigpending", 11},
        {"msgqueue", 12}, {"nice", 13}, {"rtprio", 14}, {"rttime", 15},
    };

    int resource;

    if (ParseInt(args[1], &resource)) {
        if (resource >= RLIM_NLIMITS) {
            return Error() << "Resource '" << args[1] << "' over the maximum resource value '"
                           << RLIM_NLIMITS << "'";
        } else if (resource < 0) {
            return Error() << "Resource '" << args[1] << "' below the minimum resource value '0'";
        }
    } else {
        std::string resource_string;
        if (StartsWith(args[1], "RLIM_")) {
            resource_string = args[1].substr(5);
        } else {
            resource_string = args[1];
        }

        auto it = std::find_if(text_to_resources.begin(), text_to_resources.end(),
                               [&resource_string](const auto& entry) {
                                   return EqualsIgnoreCase(resource_string, entry.first);
                               });
        if (it == text_to_resources.end()) {
            return Error() << "Could not parse resource '" << args[1] << "'";
        }

        resource = it->second;
    }

    rlimit limit;
    if (!ParseUint(args[2], &limit.rlim_cur)) {
        return Error() << "Could not parse soft limit '" << args[2] << "'";
    }
    if (!ParseUint(args[3], &limit.rlim_max)) {
        return Error() << "Could not parse hard limit '" << args[3] << "'";
    }
    return {resource, limit};
}

}  // namespace init
}  // namespace android

init/rlimit_parser.h

0 → 100644
+35 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef _INIT_RLIMIT_PARSER_H
#define _INIT_RLIMIT_PARSER_H

#include <sys/resource.h>

#include <string>
#include <vector>

#include "result.h"

namespace android {
namespace init {

Result<std::pair<int, rlimit>> ParseRlimit(const std::vector<std::string>& args);

}  // namespace init
}  // namespace android

#endif
Loading