• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "modalias_handler.h"
18 
19 #include <fnmatch.h>
20 #include <sys/syscall.h>
21 
22 #include <algorithm>
23 #include <functional>
24 #include <string>
25 #include <vector>
26 
27 #include <android-base/chrono_utils.h>
28 #include <android-base/logging.h>
29 #include <android-base/unique_fd.h>
30 
31 #include "parser.h"
32 
33 namespace android {
34 namespace init {
35 
ParseDepCallback(std::vector<std::string> && args)36 Result<Success> ModaliasHandler::ParseDepCallback(std::vector<std::string>&& args) {
37     std::vector<std::string> deps;
38 
39     // Set first item as our modules path
40     std::string::size_type pos = args[0].find(':');
41     if (pos != std::string::npos) {
42         deps.emplace_back(args[0].substr(0, pos));
43     } else {
44         return Error() << "dependency lines must start with name followed by ':'";
45     }
46 
47     // Remaining items are dependencies of our module
48     for (auto arg = args.begin() + 1; arg != args.end(); ++arg) {
49         deps.push_back(*arg);
50     }
51 
52     // Key is striped module name to match names in alias file
53     std::size_t start = args[0].find_last_of('/');
54     std::size_t end = args[0].find(".ko:");
55     if ((end - start) <= 1) return Error() << "malformed dependency line";
56     auto mod_name = args[0].substr(start + 1, (end - start) - 1);
57     // module names can have '-', but their file names will have '_'
58     std::replace(mod_name.begin(), mod_name.end(), '-', '_');
59     this->module_deps_[mod_name] = deps;
60 
61     return Success();
62 }
63 
ParseAliasCallback(std::vector<std::string> && args)64 Result<Success> ModaliasHandler::ParseAliasCallback(std::vector<std::string>&& args) {
65     auto it = args.begin();
66     const std::string& type = *it++;
67 
68     if (type != "alias") {
69         return Error() << "we only handle alias lines, got: " << type;
70     }
71 
72     if (args.size() != 3) {
73         return Error() << "alias lines must have 3 entries";
74     }
75 
76     std::string& alias = *it++;
77     std::string& module_name = *it++;
78     this->module_aliases_.emplace_back(alias, module_name);
79 
80     return Success();
81 }
82 
ModaliasHandler()83 ModaliasHandler::ModaliasHandler() {
84     using namespace std::placeholders;
85 
86     static const std::string base_paths[] = {
87             "/vendor/lib/modules/",
88             "/lib/modules/",
89             "/odm/lib/modules/",
90     };
91 
92     Parser alias_parser;
93     auto alias_callback = std::bind(&ModaliasHandler::ParseAliasCallback, this, _1);
94     alias_parser.AddSingleLineParser("alias", alias_callback);
95     for (const auto& base_path : base_paths) alias_parser.ParseConfig(base_path + "modules.alias");
96 
97     Parser dep_parser;
98     auto dep_callback = std::bind(&ModaliasHandler::ParseDepCallback, this, _1);
99     dep_parser.AddSingleLineParser("", dep_callback);
100     for (const auto& base_path : base_paths) dep_parser.ParseConfig(base_path + "modules.dep");
101 }
102 
Insmod(const std::string & path_name,const std::string & args)103 Result<Success> ModaliasHandler::Insmod(const std::string& path_name, const std::string& args) {
104     base::unique_fd fd(
105             TEMP_FAILURE_RETRY(open(path_name.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
106     if (fd == -1) return ErrnoError() << "Could not open module '" << path_name << "'";
107 
108     int ret = syscall(__NR_finit_module, fd.get(), args.c_str(), 0);
109     if (ret != 0) {
110         if (errno == EEXIST) {
111             // Module already loaded
112             return Success();
113         }
114         return ErrnoError() << "Failed to insmod '" << path_name << "' with args '" << args << "'";
115     }
116 
117     LOG(INFO) << "Loaded kernel module " << path_name;
118     return Success();
119 }
120 
InsmodWithDeps(const std::string & module_name,const std::string & args)121 Result<Success> ModaliasHandler::InsmodWithDeps(const std::string& module_name,
122                                                 const std::string& args) {
123     if (module_name.empty()) {
124         return Error() << "Need valid module name";
125     }
126 
127     auto it = module_deps_.find(module_name);
128     if (it == module_deps_.end()) {
129         return Error() << "Module '" << module_name << "' not in dependency file";
130     }
131     auto& dependencies = it->second;
132 
133     // load module dependencies in reverse order
134     for (auto dep = dependencies.rbegin(); dep != dependencies.rend() - 1; ++dep) {
135         if (auto result = Insmod(*dep, ""); !result) return result;
136     }
137 
138     // load target module itself with args
139     return Insmod(dependencies[0], args);
140 }
141 
HandleUevent(const Uevent & uevent)142 void ModaliasHandler::HandleUevent(const Uevent& uevent) {
143     if (uevent.modalias.empty()) return;
144 
145     for (const auto& [alias, module] : module_aliases_) {
146         if (fnmatch(alias.c_str(), uevent.modalias.c_str(), 0) != 0) continue;  // Keep looking
147 
148         LOG(DEBUG) << "Loading kernel module '" << module << "' for alias '" << uevent.modalias
149                    << "'";
150 
151         if (auto result = InsmodWithDeps(module, ""); !result) {
152             LOG(ERROR) << "Cannot load module: " << result.error();
153             // try another one since there may be another match
154             continue;
155         }
156 
157         // loading was successful
158         return;
159     }
160 }
161 
162 }  // namespace init
163 }  // namespace android
164