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

Commit 3657c80c authored by Tom Cherry's avatar Tom Cherry Committed by android-build-merger
Browse files

Merge "Introduce property types"

am: a0ffad60

Change-Id: Ideb5035d125c541eb763ab5ffde97f899778b25e
parents 422fafeb a0ffad60
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -75,6 +75,7 @@ cc_library_static {
        "persistent_properties.cpp",
        "persistent_properties.cpp",
        "persistent_properties.proto",
        "persistent_properties.proto",
        "property_service.cpp",
        "property_service.cpp",
        "property_type.cpp",
        "security.cpp",
        "security.cpp",
        "selinux.cpp",
        "selinux.cpp",
        "service.cpp",
        "service.cpp",
@@ -178,6 +179,7 @@ cc_test {
        "init_test.cpp",
        "init_test.cpp",
        "persistent_properties_test.cpp",
        "persistent_properties_test.cpp",
        "property_service_test.cpp",
        "property_service_test.cpp",
        "property_type_test.cpp",
        "result_test.cpp",
        "result_test.cpp",
        "rlimit_parser_test.cpp",
        "rlimit_parser_test.cpp",
        "service_test.cpp",
        "service_test.cpp",
+57 −59
Original line number Original line Diff line number Diff line
@@ -58,6 +58,7 @@


#include "init.h"
#include "init.h"
#include "persistent_properties.h"
#include "persistent_properties.h"
#include "property_type.h"
#include "util.h"
#include "util.h"


using android::base::ReadFileToString;
using android::base::ReadFileToString;
@@ -95,14 +96,9 @@ void property_init() {
        LOG(FATAL) << "Failed to load serialized property info file";
        LOG(FATAL) << "Failed to load serialized property info file";
    }
    }
}
}
static bool check_mac_perms(const std::string& name, char* sctx, struct ucred* cr) {
static bool CheckMacPerms(const std::string& name, const char* target_context,
    if (!sctx) {
                          const char* source_context, struct ucred* cr) {
      return false;
    if (!target_context || !source_context) {
    }

    const char* target_context = nullptr;
    property_info_area->GetPropertyInfo(name.c_str(), &target_context, nullptr);
    if (target_context == nullptr) {
        return false;
        return false;
    }
    }


@@ -111,29 +107,12 @@ static bool check_mac_perms(const std::string& name, char* sctx, struct ucred* c
    audit_data.name = name.c_str();
    audit_data.name = name.c_str();
    audit_data.cr = cr;
    audit_data.cr = cr;


    bool has_access =
    bool has_access = (selinux_check_access(source_context, target_context, "property_service",
        (selinux_check_access(sctx, target_context, "property_service", "set", &audit_data) == 0);
                                            "set", &audit_data) == 0);


    return has_access;
    return has_access;
}
}


static int check_control_mac_perms(const char *name, char *sctx, struct ucred *cr)
{
    /*
     *  Create a name prefix out of ctl.<service name>
     *  The new prefix allows the use of the existing
     *  property service backend labeling while avoiding
     *  mislabels based on true property prefixes.
     */
    char ctl_name[PROP_VALUE_MAX+4];
    int ret = snprintf(ctl_name, sizeof(ctl_name), "ctl.%s", name);

    if (ret < 0 || (size_t) ret >= sizeof(ctl_name))
        return 0;

    return check_mac_perms(ctl_name, sctx, cr);
}

bool is_legal_property_name(const std::string& name) {
bool is_legal_property_name(const std::string& name) {
    size_t namelen = name.size();
    size_t namelen = name.size();


@@ -422,25 +401,51 @@ static void handle_property_set(SocketConnection& socket,
  struct ucred cr = socket.cred();
  struct ucred cr = socket.cred();
  char* source_ctx = nullptr;
  char* source_ctx = nullptr;
  getpeercon(socket.socket(), &source_ctx);
  getpeercon(socket.socket(), &source_ctx);
  std::string source_context = source_ctx;
  freecon(source_ctx);


  if (StartsWith(name, "ctl.")) {
  if (StartsWith(name, "ctl.")) {
    if (check_control_mac_perms(value.c_str(), source_ctx, &cr)) {
      // ctl. properties have their name ctl.<action> and their value is the name of the service to
      // apply that action to.  Permissions for these actions are based on the service, so we must
      // create a fake name of ctl.<service> to check permissions.
      auto control_string = "ctl." + value;
      const char* target_context = nullptr;
      const char* type = nullptr;
      property_info_area->GetPropertyInfo(control_string.c_str(), &target_context, &type);
      if (!CheckMacPerms(control_string, target_context, source_context.c_str(), &cr)) {
          LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4)
                     << " service ctl [" << value << "]"
                     << " uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid;
          if (!legacy_protocol) {
              socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE);
          }
          return;
      }

      handle_control_message(name.c_str() + 4, value.c_str());
      handle_control_message(name.c_str() + 4, value.c_str());
      if (!legacy_protocol) {
      if (!legacy_protocol) {
          socket.SendUint32(PROP_SUCCESS);
          socket.SendUint32(PROP_SUCCESS);
      }
      }
  } else {
  } else {
      LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4)
      const char* target_context = nullptr;
                 << " service ctl [" << value << "]"
      const char* type = nullptr;
                 << " uid:" << cr.uid
      property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);
                 << " gid:" << cr.gid
      if (!CheckMacPerms(name, target_context, source_context.c_str(), &cr)) {
                 << " pid:" << cr.pid;
          LOG(ERROR) << "sys_prop(" << cmd_name << "): permission denied uid:" << cr.uid
                     << " name:" << name;
          if (!legacy_protocol) {
          if (!legacy_protocol) {
        socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE);
              socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
          }
          }
          return;
      }
      if (type == nullptr || !CheckType(type, value)) {
          LOG(ERROR) << "sys_prop(" << cmd_name << "): type check failed, type: '"
                     << (type ?: "(null)") << "' value: '" << value << "'";
          if (!legacy_protocol) {
              socket.SendUint32(PROP_ERROR_INVALID_VALUE);
          }
          return;
      }
      }
  } else {
    if (check_mac_perms(name, source_ctx, &cr)) {
      // sys.powerctl is a special property that is used to make the device reboot.  We want to log
      // sys.powerctl is a special property that is used to make the device reboot.  We want to log
      // any process that sets this property to be able to accurately blame the cause of a shutdown.
      // any process that sets this property to be able to accurately blame the cause of a shutdown.
      if (name == "sys.powerctl") {
      if (name == "sys.powerctl") {
@@ -459,17 +464,9 @@ static void handle_property_set(SocketConnection& socket,
      if (!legacy_protocol) {
      if (!legacy_protocol) {
          socket.SendUint32(result);
          socket.SendUint32(result);
      }
      }
    } else {
      LOG(ERROR) << "sys_prop(" << cmd_name << "): permission denied uid:" << cr.uid << " name:" << name;
      if (!legacy_protocol) {
        socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
      }
  }
  }
}
}


  freecon(source_ctx);
}

static void handle_property_set_fd() {
static void handle_property_set_fd() {
    static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */
    static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */


@@ -764,9 +761,10 @@ void CreateSerializedPropertyInfo() {
        }
        }
        LoadPropertyInfoFromFile("/nonplat_property_contexts", &property_infos);
        LoadPropertyInfoFromFile("/nonplat_property_contexts", &property_infos);
    }
    }

    auto serialized_contexts = std::string();
    auto serialized_contexts = std::string();
    auto error = std::string();
    auto error = std::string();
    if (!BuildTrie(property_infos, "u:object_r:default_prop:s0", "\\s*", &serialized_contexts,
    if (!BuildTrie(property_infos, "u:object_r:default_prop:s0", "string", &serialized_contexts,
                   &error)) {
                   &error)) {
        LOG(ERROR) << "Unable to serialize property contexts: " << error;
        LOG(ERROR) << "Unable to serialize property contexts: " << error;
        return;
        return;

init/property_type.cpp

0 → 100644
+81 −0
Original line number Original line 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 "property_type.h"

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

using android::base::ParseDouble;
using android::base::ParseInt;
using android::base::ParseUint;
using android::base::Split;

namespace android {
namespace init {

bool CheckType(const std::string& type_string, const std::string& value) {
    auto type_strings = Split(type_string, " ");
    if (type_strings.empty()) {
        return false;
    }
    auto type = type_strings[0];

    if (type == "string") {
        return true;
    }
    if (type == "bool") {
        return value == "true" || value == "false" || value == "1" || value == "0";
    }
    if (type == "int") {
        int64_t parsed;
        return ParseInt(value, &parsed);
    }
    if (type == "uint") {
        uint64_t parsed;
        if (value.empty() || value.front() == '-') {
            return false;
        }
        return ParseUint(value, &parsed);
    }
    if (type == "double") {
        double parsed;
        return ParseDouble(value.c_str(), &parsed);
    }
    if (type == "size") {
        auto it = value.begin();
        while (it != value.end() && isdigit(*it)) {
            it++;
        }
        if (it == value.begin() || it == value.end() || (*it != 'g' && *it != 'k' && *it != 'm')) {
            return false;
        }
        it++;
        return it == value.end();
    }
    if (type == "enum") {
        for (auto it = std::next(type_strings.begin()); it != type_strings.end(); ++it) {
            if (*it == value) {
                return true;
            }
        }
    }
    return false;
}

}  // namespace init
}  // namespace android

init/property_type.h

0 → 100644
+30 −0
Original line number Original line 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_PROPERTY_TYPE_H
#define _INIT_PROPERTY_TYPE_H

#include <string>

namespace android {
namespace init {

bool CheckType(const std::string& type_string, const std::string& value);

}  // namespace init
}  // namespace android

#endif
+95 −0
Original line number Original line 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 "property_type.h"

#include <gtest/gtest.h>

namespace android {
namespace init {

TEST(property_type, CheckType_string) {
    EXPECT_TRUE(CheckType("string", ""));
    EXPECT_TRUE(CheckType("string", "-234"));
    EXPECT_TRUE(CheckType("string", "234"));
    EXPECT_TRUE(CheckType("string", "true"));
    EXPECT_TRUE(CheckType("string", "false"));
    EXPECT_TRUE(CheckType("string", "45645634563456345634563456"));
    EXPECT_TRUE(CheckType("string", "some other string"));
}

TEST(property_type, CheckType_int) {
    EXPECT_FALSE(CheckType("int", ""));
    EXPECT_FALSE(CheckType("int", "abc"));
    EXPECT_FALSE(CheckType("int", "-abc"));
    EXPECT_TRUE(CheckType("int", "0"));
    EXPECT_TRUE(CheckType("int", std::to_string(std::numeric_limits<int64_t>::min())));
    EXPECT_TRUE(CheckType("int", std::to_string(std::numeric_limits<int64_t>::max())));
    EXPECT_TRUE(CheckType("int", "123"));
    EXPECT_TRUE(CheckType("int", "-123"));
}

TEST(property_type, CheckType_uint) {
    EXPECT_FALSE(CheckType("uint", ""));
    EXPECT_FALSE(CheckType("uint", "abc"));
    EXPECT_FALSE(CheckType("uint", "-abc"));
    EXPECT_TRUE(CheckType("uint", "0"));
    EXPECT_TRUE(CheckType("uint", std::to_string(std::numeric_limits<uint64_t>::max())));
    EXPECT_TRUE(CheckType("uint", "123"));
    EXPECT_FALSE(CheckType("uint", "-123"));
}

TEST(property_type, CheckType_double) {
    EXPECT_FALSE(CheckType("double", ""));
    EXPECT_FALSE(CheckType("double", "abc"));
    EXPECT_FALSE(CheckType("double", "-abc"));
    EXPECT_TRUE(CheckType("double", "0.0"));
    EXPECT_TRUE(CheckType("double", std::to_string(std::numeric_limits<double>::min())));
    EXPECT_TRUE(CheckType("double", std::to_string(std::numeric_limits<double>::max())));
    EXPECT_TRUE(CheckType("double", "123.1"));
    EXPECT_TRUE(CheckType("double", "-123.1"));
}

TEST(property_type, CheckType_size) {
    EXPECT_FALSE(CheckType("size", ""));
    EXPECT_FALSE(CheckType("size", "ab"));
    EXPECT_FALSE(CheckType("size", "abcd"));
    EXPECT_FALSE(CheckType("size", "0"));

    EXPECT_TRUE(CheckType("size", "512g"));
    EXPECT_TRUE(CheckType("size", "512k"));
    EXPECT_TRUE(CheckType("size", "512m"));

    EXPECT_FALSE(CheckType("size", "512gggg"));
    EXPECT_FALSE(CheckType("size", "512mgk"));
    EXPECT_FALSE(CheckType("size", "g"));
    EXPECT_FALSE(CheckType("size", "m"));
}

TEST(property_type, CheckType_enum) {
    EXPECT_FALSE(CheckType("enum abc", ""));
    EXPECT_FALSE(CheckType("enum abc", "ab"));
    EXPECT_FALSE(CheckType("enum abc", "abcd"));
    EXPECT_FALSE(CheckType("enum 123 456 789", "0"));

    EXPECT_TRUE(CheckType("enum abc", "abc"));
    EXPECT_TRUE(CheckType("enum 123 456 789", "123"));
    EXPECT_TRUE(CheckType("enum 123 456 789", "456"));
    EXPECT_TRUE(CheckType("enum 123 456 789", "789"));
}

}  // namespace init
}  // namespace android
Loading