• 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 <sys/stat.h>
18 #include <sys/syscall.h>
19 
20 #include <android-base/file.h>
21 #include <android-base/logging.h>
22 #include <android-base/unique_fd.h>
23 
24 #include <modprobe/modprobe.h>
25 
GetKernelCmdline(void)26 std::string Modprobe::GetKernelCmdline(void) {
27     std::string cmdline;
28     if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
29         return "";
30     }
31     return cmdline;
32 }
33 
Insmod(const std::string & path_name,const std::string & parameters)34 bool Modprobe::Insmod(const std::string& path_name, const std::string& parameters) {
35     android::base::unique_fd fd(
36             TEMP_FAILURE_RETRY(open(path_name.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
37     if (fd == -1) {
38         PLOG(ERROR) << "Could not open module '" << path_name << "'";
39         return false;
40     }
41 
42     auto canonical_name = MakeCanonical(path_name);
43     std::string options = "";
44     auto options_iter = module_options_.find(canonical_name);
45     if (options_iter != module_options_.end()) {
46         options = options_iter->second;
47     }
48     if (!parameters.empty()) {
49         options = options + " " + parameters;
50     }
51 
52     LOG(INFO) << "Loading module " << path_name << " with args '" << options << "'";
53     int ret = syscall(__NR_finit_module, fd.get(), options.c_str(), 0);
54     if (ret != 0) {
55         if (errno == EEXIST) {
56             // Module already loaded
57             std::lock_guard guard(module_loaded_lock_);
58             module_loaded_paths_.emplace(path_name);
59             module_loaded_.emplace(canonical_name);
60             return true;
61         }
62         PLOG(ERROR) << "Failed to insmod '" << path_name << "' with args '" << options << "'";
63         return false;
64     }
65 
66     LOG(INFO) << "Loaded kernel module " << path_name;
67     std::lock_guard guard(module_loaded_lock_);
68     module_loaded_paths_.emplace(path_name);
69     module_loaded_.emplace(canonical_name);
70     module_count_++;
71     return true;
72 }
73 
Rmmod(const std::string & module_name)74 bool Modprobe::Rmmod(const std::string& module_name) {
75     auto canonical_name = MakeCanonical(module_name);
76     int ret = syscall(__NR_delete_module, canonical_name.c_str(), O_NONBLOCK);
77     if (ret != 0) {
78         PLOG(ERROR) << "Failed to remove module '" << module_name << "'";
79         return false;
80     }
81     std::lock_guard guard(module_loaded_lock_);
82     module_loaded_.erase(canonical_name);
83     return true;
84 }
85 
ModuleExists(const std::string & module_name)86 bool Modprobe::ModuleExists(const std::string& module_name) {
87     struct stat fileStat;
88     if (blocklist_enabled && module_blocklist_.count(module_name)) {
89         LOG(INFO) << "module " << module_name << " is blocklisted";
90         return false;
91     }
92     auto deps = GetDependencies(module_name);
93     if (deps.empty()) {
94         // missing deps can happen in the case of an alias
95         return false;
96     }
97     if (stat(deps.front().c_str(), &fileStat)) {
98         LOG(INFO) << "module " << module_name << " does not exist";
99         return false;
100     }
101     if (!S_ISREG(fileStat.st_mode)) {
102         LOG(INFO) << "module " << module_name << " is not a regular file";
103         return false;
104     }
105     return true;
106 }
107