1 /* 2 * Copyright (C) Igor Sysoev 3 * Copyright (C) NGINX, Inc. 4 */ 5 6 #include <nxt_main.h> 7 #include <sys/types.h> 8 #include <nxt_conf.h> 9 #include <nxt_clone.h> 10 11 #if (NXT_HAVE_CLONE) 12 13 pid_t 14 nxt_clone(nxt_int_t flags) 15 { 16 #if defined(__s390x__) || defined(__s390__) || defined(__CRIS__) 17 return syscall(__NR_clone, NULL, flags); 18 #else 19 return syscall(__NR_clone, flags, NULL); 20 #endif 21 } 22 23 #endif 24 25 26 #if (NXT_HAVE_CLONE_NEWUSER) 27 28 /* map uid 65534 to unit pid */ 29 #define NXT_DEFAULT_UNPRIV_MAP "65534 %d 1" 30 31 nxt_int_t nxt_clone_proc_setgroups(nxt_task_t *task, pid_t child_pid, 32 const char *str); 33 nxt_int_t nxt_clone_proc_map_set(nxt_task_t *task, const char* mapfile, 34 pid_t pid, nxt_int_t defval, nxt_conf_value_t *mapobj); 35 nxt_int_t nxt_clone_proc_map_write(nxt_task_t *task, const char *mapfile, 36 pid_t pid, u_char *mapinfo); 37 38 39 typedef struct { 40 nxt_int_t container; 41 nxt_int_t host; 42 nxt_int_t size; 43 } nxt_clone_procmap_t; 44 45 46 nxt_int_t 47 nxt_clone_proc_setgroups(nxt_task_t *task, pid_t child_pid, const char *str) 48 { 49 int fd, n; 50 u_char *p, *end; 51 u_char path[PATH_MAX]; 52 53 end = path + PATH_MAX; 54 p = nxt_sprintf(path, end, "/proc/%d/setgroups", child_pid); 55 *p = '\0'; 56 57 if (nxt_slow_path(p == end)) { 58 nxt_alert(task, "error write past the buffer: %s", path); 59 return NXT_ERROR; 60 } 61 62 fd = open((char *)path, O_RDWR); 63 64 if (fd == -1) { 65 /* 66 * If the /proc/pid/setgroups doesn't exists, we are 67 * safe to set uid/gid maps. But if the error is anything 68 * other than ENOENT, then we should abort and let user know. 69 */ 70 71 if (errno != ENOENT) { 72 nxt_alert(task, "open(%s): %E", path, nxt_errno); 73 return NXT_ERROR; 74 } 75 76 return NXT_OK; 77 } 78 79 n = write(fd, str, strlen(str)); 80 close(fd); 81 82 if (nxt_slow_path(n == -1)) { 83 nxt_alert(task, "write(%s): %E", path, nxt_errno); 84 return NXT_ERROR; 85 } 86 87 return NXT_OK; 88 } 89 90 91 nxt_int_t 92 nxt_clone_proc_map_write(nxt_task_t *task, const char *mapfile, pid_t pid, 93 u_char *mapinfo) 94 { 95 int len, mapfd; 96 u_char *p, *end; 97 ssize_t n; 98 u_char buf[256]; 99 100 end = buf + sizeof(buf); 101 102 p = nxt_sprintf(buf, end, "/proc/%d/%s", pid, mapfile); 103 if (nxt_slow_path(p == end)) { 104 nxt_alert(task, "writing past the buffer"); 105 return NXT_ERROR; 106 } 107 108 *p = '\0'; 109 110 mapfd = open((char*)buf, O_RDWR); 111 if (nxt_slow_path(mapfd == -1)) { 112 nxt_alert(task, "failed to open proc map (%s) %E", buf, nxt_errno); 113 return NXT_ERROR; 114 } 115 116 len = nxt_strlen(mapinfo); 117 118 n = write(mapfd, (char *)mapinfo, len); 119 if (nxt_slow_path(n != len)) { 120 121 if (n == -1 && nxt_errno == EINVAL) { 122 nxt_alert(task, "failed to write %s: Check kernel maximum " \ 123 "allowed lines %E", buf, nxt_errno); 124 125 } else { 126 nxt_alert(task, "failed to write proc map (%s) %E", buf, 127 nxt_errno); 128 } 129 130 close(mapfd); 131 132 return NXT_ERROR; 133 } 134 135 close(mapfd); 136 137 return NXT_OK; 138 } 139 140 141 nxt_int_t 142 nxt_clone_proc_map_set(nxt_task_t *task, const char* mapfile, pid_t pid, 143 nxt_int_t defval, nxt_conf_value_t *mapobj) 144 { 145 u_char *p, *end, *mapinfo; 146 nxt_int_t container, host, size; 147 nxt_int_t ret, len, count, i; 148 nxt_conf_value_t *obj, *value; 149 150 static nxt_str_t str_cont = nxt_string("container"); 151 static nxt_str_t str_host = nxt_string("host"); 152 static nxt_str_t str_size = nxt_string("size"); 153 154 /* 155 * uid_map one-entry size: 156 * alloc space for 3 numbers (32bit) plus 2 spaces and \n. 157 */ 158 len = sizeof(u_char) * (10 + 10 + 10 + 2 + 1); 159 160 if (mapobj != NULL) { 161 count = nxt_conf_array_elements_count(mapobj); 162 163 if (count == 0) { 164 goto default_map; 165 } 166 167 len = len * count + 1; 168 169 mapinfo = nxt_malloc(len); 170 if (nxt_slow_path(mapinfo == NULL)) { 171 nxt_alert(task, "failed to allocate uid_map buffer"); 172 return NXT_ERROR; 173 } 174 175 p = mapinfo; 176 end = mapinfo + len; 177 178 for (i = 0; i < count; i++) { 179 obj = nxt_conf_get_array_element(mapobj, i); 180 181 value = nxt_conf_get_object_member(obj, &str_cont, NULL); 182 container = nxt_conf_get_integer(value); 183 184 value = nxt_conf_get_object_member(obj, &str_host, NULL); 185 host = nxt_conf_get_integer(value); 186 187 value = nxt_conf_get_object_member(obj, &str_size, NULL); 188 size = nxt_conf_get_integer(value); 189 190 p = nxt_sprintf(p, end, "%d %d %d", container, host, size); 191 if (nxt_slow_path(p == end)) { 192 nxt_alert(task, "write past the uid_map buffer"); 193 nxt_free(mapinfo); 194 return NXT_ERROR; 195 } 196 197 if (i+1 < count) { 198 *p++ = '\n'; 199 200 } else { 201 *p = '\0'; 202 } 203 } 204 205 } else { 206 207 default_map: 208 209 mapinfo = nxt_malloc(len); 210 if (nxt_slow_path(mapinfo == NULL)) { 211 nxt_alert(task, "failed to allocate uid_map buffer"); 212 return NXT_ERROR; 213 } 214 215 end = mapinfo + len; 216 p = nxt_sprintf(mapinfo, end, NXT_DEFAULT_UNPRIV_MAP, defval); 217 *p = '\0'; 218 219 if (nxt_slow_path(p == end)) { 220 nxt_alert(task, "write past the %s buffer", mapfile); 221 nxt_free(mapinfo); 222 return NXT_ERROR; 223 } 224 } 225 226 ret = nxt_clone_proc_map_write(task, mapfile, pid, mapinfo); 227 228 nxt_free(mapinfo); 229 230 return ret; 231 } 232 233 234 nxt_int_t 235 nxt_clone_proc_map(nxt_task_t *task, pid_t pid, nxt_process_clone_t *clone) 236 { 237 nxt_int_t ret; 238 nxt_int_t uid, gid; 239 const char *rule; 240 nxt_runtime_t *rt; 241 242 rt = task->thread->runtime; 243 uid = geteuid(); 244 gid = getegid(); 245 246 rule = rt->capabilities.setid ? "allow" : "deny"; 247 248 ret = nxt_clone_proc_map_set(task, "uid_map", pid, uid, clone->uidmap); 249 if (nxt_slow_path(ret != NXT_OK)) { 250 return NXT_ERROR; 251 } 252 253 ret = nxt_clone_proc_setgroups(task, pid, rule); 254 if (nxt_slow_path(ret != NXT_OK)) { 255 nxt_alert(task, "failed to write /proc/%d/setgroups", pid); 256 return NXT_ERROR; 257 } 258 259 ret = nxt_clone_proc_map_set(task, "gid_map", pid, gid, clone->gidmap); 260 if (nxt_slow_path(ret != NXT_OK)) { 261 return NXT_ERROR; 262 } 263 264 return NXT_OK; 265 } 266 267 #endif 268