Fix some security issues
[platform/core/connectivity/stc-manager.git] / src / helper / helper-cgroup.c
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
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 "helper-cgroup.h"
18
19 #define RELEASE_AGENT   "release_agent"
20 #define NOTIFY_ON_RELEASE  "notify_on_release"
21
22 #define CGROUP_FILE_NAME "cgroup.procs"
23 #define CLASSID_FILE_NAME "net_cls.classid"
24
25 #define MAX_PATH_LENGTH 512
26
27 static bool cgroup_is_exists(const char *cgroup_full_path)
28 {
29         struct stat stat_buf;
30         return stat(cgroup_full_path, &stat_buf) == 0;
31 }
32
33 static int cgroup_create(const char *cgroup_full_path)
34 {
35         if (mkdir(cgroup_full_path,
36                   S_IRUSR | S_IWUSR | S_IRGRP) < 0)
37                 return -errno; //LCOV_EXCL_LINE
38
39         return 0;
40 }
41
42 /*
43  * @desc place pid to cgroup.procs file
44  * @return 0 in case of success, errno value in case of failure
45  */
46 stc_error_e cgroup_write_pid_fullpath(const char *cgroup_full_path,
47                                       const int pid)
48 {
49         int ret;
50
51         if (pid <= 0) {
52                 STC_LOGE("try to write empty pid to %s", cgroup_full_path); //LCOV_EXCL_LINE
53                 return STC_ERROR_NO_DATA; //LCOV_EXCL_LINE
54         }
55
56         ret = cgroup_write_node_uint32(cgroup_full_path, CGROUP_FILE_NAME,
57                                        (uint32_t)pid);
58
59         ret_value_msg_if(ret < 0, STC_ERROR_FAIL,
60                          "Failed place all pid to cgroup %s", cgroup_full_path);
61         return STC_ERROR_NONE;
62 }
63
64 stc_error_e cgroup_write_pid(const char *cgroup_subsystem,
65                              const char *cgroup_name, const int pid)
66 {
67         char buf[MAX_PATH_LENGTH];
68         snprintf(buf, sizeof(buf), "%s/%s", cgroup_subsystem, cgroup_name);
69         return cgroup_write_pid_fullpath(buf, pid);
70 }
71
72 //LCOV_EXCL_START
73 stc_error_e cgroup_write_pidtree(const char *cgroup_subsystem,
74                                  const char *cgroup_name, const int pid)
75 {
76         char buf[MAX_PATH_LENGTH];
77
78         /*/proc/%d/task/%d/children */
79         char child_buf[21 + MAX_DEC_SIZE(int) + MAX_DEC_SIZE(int) + 1];
80         char pidbuf[MAX_DEC_SIZE(int)];
81         stc_error_e ret;
82
83         FILE *f;
84
85         snprintf(buf, sizeof(buf), "%s/%s", cgroup_subsystem, cgroup_name);
86         /* place parent */
87         ret = cgroup_write_pid_fullpath(buf, pid);
88         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
89                          "Failed to put parent process %d into %s cgroup",
90                          pid, cgroup_name);
91
92         snprintf(child_buf, sizeof(child_buf), PROC_TASK_CHILDREN,
93                  pid, pid);
94         f = fopen(child_buf, "r");
95         ret_value_msg_if(!f, STC_ERROR_FAIL, "Failed to get child pids!");
96         while (fgets(pidbuf, sizeof(pidbuf), f) != NULL) {
97                 int child_pid = atoi(pidbuf);
98                 if (child_pid < 0) {
99                         STC_LOGE("Invalid child pid!");
100                         fclose(f);
101                         return STC_ERROR_FAIL;
102                 }
103                 stc_error_e ret = cgroup_write_pid_fullpath(buf, child_pid);
104                 if (ret != STC_ERROR_NONE) {
105                         STC_LOGE("Failed to put parent process %d into %s cgroup",
106                            pid, cgroup_name);
107                         fclose(f);
108                         return ret;
109                 }
110         }
111         fclose(f);
112         return STC_ERROR_NONE;
113 }
114 //LCOV_EXCL_STOP
115
116 int cgroup_write_node_uint32(const char *cgroup_name,
117                              const char *file_name, uint32_t value)
118 {
119         char buf[MAX_PATH_LENGTH];
120         snprintf(buf, sizeof(buf), "%s/%s", cgroup_name, file_name);
121
122         if (STC_DEBUG_LOG)
123                 STC_LOGD("cgroup_buf %s, value %d\n", buf, value); //LCOV_EXCL_LINE
124
125         return fwrite_uint(buf, value);
126 }
127
128 int cgroup_write_node_str(const char *cgroup_name,
129                           const char *file_name, const char *string)
130 {
131         char buf[MAX_PATH_LENGTH];
132         snprintf(buf, sizeof(buf), "%s/%s", cgroup_name, file_name);
133
134         if (STC_DEBUG_LOG)
135                 STC_LOGD("cgroup_buf %s, string %s\n", buf, string); //LCOV_EXCL_LINE
136
137         return fwrite_str(buf, string);
138 }
139
140 int cgroup_read_node_uint32(const char *cgroup_name,
141                             const char *file_name, uint32_t *value)
142 {
143         char buf[MAX_PATH_LENGTH];
144         int ret;
145         snprintf(buf, sizeof(buf), "%s/%s", cgroup_name, file_name);
146         ret = fread_uint(buf, value);
147
148         if (STC_DEBUG_LOG)
149                 STC_LOGD("cgroup_buf %s, value %d\n", buf, *value); //LCOV_EXCL_LINE
150
151         return ret;
152 }
153
154 int cgroup_make_subdir(const char *parentdir, const char *cgroup_name,
155                        bool *already)
156 {
157         char buf[MAX_PATH_LENGTH];
158         bool cgroup_exists;
159         int ret = 0;
160
161         if (parentdir)
162                 ret = snprintf(buf, sizeof(buf), "%s/%s",
163                                parentdir, cgroup_name);
164         else
165                 ret = snprintf(buf, sizeof(buf), "%s",
166                                cgroup_name);
167
168         ret_value_msg_if(ret > sizeof(buf), STC_ERROR_FAIL,
169                          "Not enought buffer size for %s%s",
170                          parentdir, cgroup_name);
171
172         cgroup_exists = cgroup_is_exists(buf);
173         if (!cgroup_exists) {
174                 bool cgroup_remount = false;
175
176                 if (parentdir && !strncmp(parentdir, DEFAULT_CGROUP,
177                                           sizeof(DEFAULT_CGROUP))) {
178                         ret = mount("tmpfs", DEFAULT_CGROUP, "tmpfs", //LCOV_EXCL_LINE
179                                     MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
180                                     "mode=755");
181                         if (ret < 0) {
182                                 STC_LOGE("Fail to RW mount cgroup directory. Can't make %s cgroup", cgroup_name); //LCOV_EXCL_LINE
183                                 return STC_ERROR_FAIL; //LCOV_EXCL_LINE
184                         }
185                         cgroup_remount = true;
186                 }
187
188                 ret = cgroup_create(buf);
189                 ret_value_msg_if(ret < 0, STC_ERROR_FAIL,
190                                  "Fail to create cgroup %s : err %d",
191                                  cgroup_name, errno);
192
193                 if (cgroup_remount) {
194                         ret = mount("tmpfs", DEFAULT_CGROUP, "tmpfs",  //LCOV_EXCL_LINE
195                                     MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY,
196                                     "mode=755");
197                         if (ret < 0)
198                                 STC_LOGD("Fail to RO mount"); //LCOV_EXCL_LINE
199                 }
200         }
201
202         if (already)
203                 *already = cgroup_exists;
204
205         return STC_ERROR_NONE;
206 }
207
208 int cgroup_set_release_agent(const char *cgroup_subsys,
209                              const char *release_agent)
210 {
211         _cleanup_free_ char *buf = NULL;
212         int r;
213
214         r = asprintf(&buf, "%s/%s", DEFAULT_CGROUP, cgroup_subsys);
215         if (r < 0)
216                 return -ENOMEM;
217
218         r = cgroup_write_node_str(buf, RELEASE_AGENT, release_agent);
219         if (r < 0)
220                 return r;
221
222         return cgroup_write_node_str(buf, NOTIFY_ON_RELEASE, "1");
223 }
224
225 void cgroup_init(void)
226 {
227         /* create stc cgroup directory */
228         cgroup_make_subdir(CGROUP_NETWORK, STC_CGROUP_NAME, NULL);
229
230         /* create background cgroup directory */
231         cgroup_make_subdir(STC_CGROUP_NETWORK, STC_BACKGROUND_CGROUP_NAME,
232                            NULL);
233
234         cgroup_write_node_uint32(BACKGROUND_CGROUP_NETWORK,
235                 CLASSID_FILE_NAME, STC_BACKGROUND_APP_CLASSID);
236
237         /* create foreground cgroup directory */
238         cgroup_make_subdir(STC_CGROUP_NETWORK, STC_FOREGROUND_CGROUP_NAME,
239                            NULL);
240 }