File: | build-scan/../src/nspawn/nspawn-setuid.c |
Warning: | line 94, column 9 Value stored to 'fd' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
2 | |
3 | #include <grp.h> |
4 | #include <sys/types.h> |
5 | #include <unistd.h> |
6 | |
7 | #include "alloc-util.h" |
8 | #include "def.h" |
9 | #include "errno.h" |
10 | #include "fd-util.h" |
11 | #include "fileio.h" |
12 | #include "mkdir.h" |
13 | #include "nspawn-setuid.h" |
14 | #include "process-util.h" |
15 | #include "signal-util.h" |
16 | #include "string-util.h" |
17 | #include "strv.h" |
18 | #include "user-util.h" |
19 | #include "util.h" |
20 | |
21 | static int spawn_getent(const char *database, const char *key, pid_t *rpid) { |
22 | int pipe_fds[2], r; |
23 | pid_t pid; |
24 | |
25 | assert(database)do { if ((__builtin_expect(!!(!(database)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("database"), "../src/nspawn/nspawn-setuid.c" , 25, __PRETTY_FUNCTION__); } while (0); |
26 | assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("key"), "../src/nspawn/nspawn-setuid.c", 26, __PRETTY_FUNCTION__); } while (0); |
27 | assert(rpid)do { if ((__builtin_expect(!!(!(rpid)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rpid"), "../src/nspawn/nspawn-setuid.c" , 27, __PRETTY_FUNCTION__); } while (0); |
28 | |
29 | if (pipe2(pipe_fds, O_CLOEXEC02000000) < 0) |
30 | return log_error_errno(errno, "Failed to allocate pipe: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn-setuid.c", 30, __func__ , "Failed to allocate pipe: %m") : -abs(_e); }); |
31 | |
32 | r = safe_fork("(getent)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid); |
33 | if (r < 0) { |
34 | safe_close_pair(pipe_fds); |
35 | return r; |
36 | } |
37 | if (r == 0) { |
38 | char *empty_env = NULL((void*)0); |
39 | |
40 | safe_close(pipe_fds[0]); |
41 | |
42 | if (rearrange_stdio(-1, pipe_fds[1], -1) < 0) |
43 | _exit(EXIT_FAILURE1); |
44 | |
45 | close_all_fds(NULL((void*)0), 0); |
46 | |
47 | execle("/usr/bin/getent", "getent", database, key, NULL((void*)0), &empty_env); |
48 | execle("/bin/getent", "getent", database, key, NULL((void*)0), &empty_env); |
49 | _exit(EXIT_FAILURE1); |
50 | } |
51 | |
52 | pipe_fds[1] = safe_close(pipe_fds[1]); |
53 | |
54 | *rpid = pid; |
55 | |
56 | return pipe_fds[0]; |
57 | } |
58 | |
59 | int change_uid_gid(const char *user, char **_home) { |
60 | char *x, *u, *g, *h; |
61 | const char *word, *state; |
62 | _cleanup_free___attribute__((cleanup(freep))) uid_t *uids = NULL((void*)0); |
63 | _cleanup_free___attribute__((cleanup(freep))) char *home = NULL((void*)0), *line = NULL((void*)0); |
64 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0); |
65 | _cleanup_close___attribute__((cleanup(closep))) int fd = -1; |
66 | unsigned n_uids = 0; |
67 | size_t sz = 0, l; |
68 | uid_t uid; |
69 | gid_t gid; |
70 | pid_t pid; |
71 | int r; |
72 | |
73 | assert(_home)do { if ((__builtin_expect(!!(!(_home)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("_home"), "../src/nspawn/nspawn-setuid.c" , 73, __PRETTY_FUNCTION__); } while (0); |
74 | |
75 | if (!user || STR_IN_SET(user, "root", "0")(!!strv_find((((char**) ((const char*[]) { "root", "0", ((void *)0) }))), (user)))) { |
76 | /* Reset everything fully to 0, just in case */ |
77 | |
78 | r = reset_uid_gid(); |
79 | if (r < 0) |
80 | return log_error_errno(r, "Failed to become root: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn-setuid.c", 80, __func__, "Failed to become root: %m" ) : -abs(_e); }); |
81 | |
82 | *_home = NULL((void*)0); |
83 | return 0; |
84 | } |
85 | |
86 | /* First, get user credentials */ |
87 | fd = spawn_getent("passwd", user, &pid); |
88 | if (fd < 0) |
89 | return fd; |
90 | |
91 | f = fdopen(fd, "re"); |
92 | if (!f) |
93 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn-setuid.c" , 93, __func__); |
94 | fd = -1; |
Value stored to 'fd' is never read | |
95 | |
96 | r = read_line(f, LONG_LINE_MAX(1U*1024U*1024U), &line); |
97 | if (r == 0) { |
98 | log_error("Failed to resolve user %s.", user)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn-setuid.c", 98, __func__, "Failed to resolve user %s." , user) : -abs(_e); }); |
99 | return -ESRCH3; |
100 | } |
101 | if (r < 0) |
102 | return log_error_errno(r, "Failed to read from getent: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn-setuid.c", 102, __func__, "Failed to read from getent: %m" ) : -abs(_e); }); |
103 | |
104 | (void) wait_for_terminate_and_check("getent passwd", pid, WAIT_LOG); |
105 | |
106 | x = strchr(line, ':'); |
107 | if (!x) { |
108 | log_error("/etc/passwd entry has invalid user field.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn-setuid.c", 108, __func__, "/etc/passwd entry has invalid user field." ) : -abs(_e); }); |
109 | return -EIO5; |
110 | } |
111 | |
112 | u = strchr(x+1, ':'); |
113 | if (!u) { |
114 | log_error("/etc/passwd entry has invalid password field.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn-setuid.c", 114, __func__, "/etc/passwd entry has invalid password field." ) : -abs(_e); }); |
115 | return -EIO5; |
116 | } |
117 | |
118 | u++; |
119 | g = strchr(u, ':'); |
120 | if (!g) { |
121 | log_error("/etc/passwd entry has invalid UID field.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn-setuid.c", 121, __func__, "/etc/passwd entry has invalid UID field." ) : -abs(_e); }); |
122 | return -EIO5; |
123 | } |
124 | |
125 | *g = 0; |
126 | g++; |
127 | x = strchr(g, ':'); |
128 | if (!x) { |
129 | log_error("/etc/passwd entry has invalid GID field.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn-setuid.c", 129, __func__, "/etc/passwd entry has invalid GID field." ) : -abs(_e); }); |
130 | return -EIO5; |
131 | } |
132 | |
133 | *x = 0; |
134 | h = strchr(x+1, ':'); |
135 | if (!h) { |
136 | log_error("/etc/passwd entry has invalid GECOS field.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn-setuid.c", 136, __func__, "/etc/passwd entry has invalid GECOS field." ) : -abs(_e); }); |
137 | return -EIO5; |
138 | } |
139 | |
140 | h++; |
141 | x = strchr(h, ':'); |
142 | if (!x) { |
143 | log_error("/etc/passwd entry has invalid home directory field.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn-setuid.c", 143, __func__, "/etc/passwd entry has invalid home directory field." ) : -abs(_e); }); |
144 | return -EIO5; |
145 | } |
146 | |
147 | *x = 0; |
148 | |
149 | r = parse_uid(u, &uid); |
150 | if (r < 0) { |
151 | log_error("Failed to parse UID of user.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn-setuid.c", 151, __func__, "Failed to parse UID of user." ) : -abs(_e); }); |
152 | return -EIO5; |
153 | } |
154 | |
155 | r = parse_gid(g, &gid); |
156 | if (r < 0) { |
157 | log_error("Failed to parse GID of user.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn-setuid.c", 157, __func__, "Failed to parse GID of user." ) : -abs(_e); }); |
158 | return -EIO5; |
159 | } |
160 | |
161 | home = strdup(h); |
162 | if (!home) |
163 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn-setuid.c" , 163, __func__); |
164 | |
165 | f = safe_fclose(f); |
166 | line = mfree(line); |
167 | |
168 | /* Second, get group memberships */ |
169 | fd = spawn_getent("initgroups", user, &pid); |
170 | if (fd < 0) |
171 | return fd; |
172 | |
173 | f = fdopen(fd, "re"); |
174 | if (!f) |
175 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn-setuid.c" , 175, __func__); |
176 | fd = -1; |
177 | |
178 | r = read_line(f, LONG_LINE_MAX(1U*1024U*1024U), &line); |
179 | if (r == 0) { |
180 | log_error("Failed to resolve user %s.", user)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn-setuid.c", 180, __func__, "Failed to resolve user %s." , user) : -abs(_e); }); |
181 | return -ESRCH3; |
182 | } |
183 | if (r < 0) |
184 | return log_error_errno(r, "Failed to read from getent: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn-setuid.c", 184, __func__, "Failed to read from getent: %m" ) : -abs(_e); }); |
185 | |
186 | (void) wait_for_terminate_and_check("getent initgroups", pid, WAIT_LOG); |
187 | |
188 | /* Skip over the username and subsequent separator whitespace */ |
189 | x = line; |
190 | x += strcspn(x, WHITESPACE" \t\n\r"); |
191 | x += strspn(x, WHITESPACE" \t\n\r"); |
192 | |
193 | FOREACH_WORD(word, l, x, state)for ((state) = (x), (word) = split(&(state), &(l), (" \t\n\r" ), (0)); (word); (word) = split(&(state), &(l), (" \t\n\r" ), (0))) { |
194 | char c[l+1]; |
195 | |
196 | memcpy(c, word, l); |
197 | c[l] = 0; |
198 | |
199 | if (!GREEDY_REALLOC(uids, sz, n_uids+1)greedy_realloc((void**) &(uids), &(sz), (n_uids+1), sizeof ((uids)[0]))) |
200 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn-setuid.c" , 200, __func__); |
201 | |
202 | r = parse_uid(c, &uids[n_uids++]); |
203 | if (r < 0) |
204 | return log_error_errno(r, "Failed to parse group data from getent: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn-setuid.c", 204, __func__, "Failed to parse group data from getent: %m" ) : -abs(_e); }); |
205 | } |
206 | |
207 | r = mkdir_parents(home, 0775); |
208 | if (r < 0) |
209 | return log_error_errno(r, "Failed to make home root directory: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn-setuid.c", 209, __func__, "Failed to make home root directory: %m" ) : -abs(_e); }); |
210 | |
211 | r = mkdir_safe(home, 0755, uid, gid, 0); |
212 | if (r < 0 && !IN_SET(r, -EEXIST, -ENOTDIR)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-17, -20})/sizeof(int)]; switch(r) { case -17: case -20: _found = 1; break; default: break; } _found; } )) |
213 | return log_error_errno(r, "Failed to make home directory: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn-setuid.c", 213, __func__, "Failed to make home directory: %m" ) : -abs(_e); }); |
214 | |
215 | (void) fchown(STDIN_FILENO0, uid, gid); |
216 | (void) fchown(STDOUT_FILENO1, uid, gid); |
217 | (void) fchown(STDERR_FILENO2, uid, gid); |
218 | |
219 | if (setgroups(n_uids, uids) < 0) |
220 | return log_error_errno(errno, "Failed to set auxiliary groups: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn-setuid.c", 220, __func__ , "Failed to set auxiliary groups: %m") : -abs(_e); }); |
221 | |
222 | if (setresgid(gid, gid, gid) < 0) |
223 | return log_error_errno(errno, "setresgid() failed: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn-setuid.c", 223, __func__ , "setresgid() failed: %m") : -abs(_e); }); |
224 | |
225 | if (setresuid(uid, uid, uid) < 0) |
226 | return log_error_errno(errno, "setresuid() failed: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn-setuid.c", 226, __func__ , "setresuid() failed: %m") : -abs(_e); }); |
227 | |
228 | if (_home) |
229 | *_home = TAKE_PTR(home)({ typeof(home) _ptr_ = (home); (home) = ((void*)0); _ptr_; } ); |
230 | |
231 | return 0; |
232 | } |