Bug Summary

File:build-scan/../src/vconsole/vconsole-setup.c
Warning:line 461, column 21
Potential leak of memory pointed to by 'vc'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name vconsole-setup.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I systemd-vconsole-setup.p -I . -I .. -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/vconsole/vconsole-setup.c

../src/vconsole/vconsole-setup.c

1/* SPDX-License-Identifier: LGPL-2.1+ */
2/***
3 Copyright © 2016 Michal Soltys <soltys@ziu.info>
4***/
5
6#include <errno(*__errno_location ()).h>
7#include <fcntl.h>
8#include <limits.h>
9#include <linux1/kd.h>
10#include <linux1/tiocl.h>
11#include <linux1/vt.h>
12#include <stdbool.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <sys/ioctl.h>
16#include <sysexits.h>
17#include <termios.h>
18#include <unistd.h>
19
20#include "alloc-util.h"
21#include "fd-util.h"
22#include "fileio.h"
23#include "io-util.h"
24#include "locale-util.h"
25#include "log.h"
26#include "process-util.h"
27#include "signal-util.h"
28#include "stdio-util.h"
29#include "string-util.h"
30#include "strv.h"
31#include "terminal-util.h"
32#include "util.h"
33#include "virt.h"
34
35static int verify_vc_device(int fd) {
36 unsigned char data[] = {
37 TIOCL_GETFGCONSOLE12,
38 };
39
40 int r;
41
42 r = ioctl(fd, TIOCLINUX0x541C, data);
43 if (r < 0)
44 return -errno(*__errno_location ());
45
46 return r;
47}
48
49static int verify_vc_allocation(unsigned idx) {
50 char vcname[sizeof("/dev/vcs") + DECIMAL_STR_MAX(unsigned)(2+(sizeof(unsigned) <= 1 ? 3 : sizeof(unsigned) <= 2 ?
5 : sizeof(unsigned) <= 4 ? 10 : sizeof(unsigned) <= 8
? 20 : sizeof(int[-2*(sizeof(unsigned) > 8)])))
- 2];
51
52 xsprintf(vcname, "/dev/vcs%u", idx)do { if ((__builtin_expect(!!(!(((size_t) snprintf(vcname, __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(vcname), typeof(&*(vcname))), sizeof(vcname)/sizeof((vcname
)[0]), ((void)0))), "/dev/vcs%u", idx) < (__extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(vcname), typeof(&*
(vcname))), sizeof(vcname)/sizeof((vcname)[0]), ((void)0)))))
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("xsprintf: "
"vcname" "[] must be big enough"), "../src/vconsole/vconsole-setup.c"
, 52, __PRETTY_FUNCTION__); } while (0)
;
53
54 if (access(vcname, F_OK0) < 0)
55 return -errno(*__errno_location ());
56
57 return 0;
58}
59
60static int verify_vc_allocation_byfd(int fd) {
61 struct vt_stat vcs = {};
62
63 if (ioctl(fd, VT_GETSTATE0x5603, &vcs) < 0)
64 return -errno(*__errno_location ());
65
66 return verify_vc_allocation(vcs.v_active);
67}
68
69static int verify_vc_kbmode(int fd) {
70 int curr_mode;
71
72 /*
73 * Make sure we only adjust consoles in K_XLATE or K_UNICODE mode.
74 * Otherwise we would (likely) interfere with X11's processing of the
75 * key events.
76 *
77 * http://lists.freedesktop.org/archives/systemd-devel/2013-February/008573.html
78 */
79
80 if (ioctl(fd, KDGKBMODE0x4B44, &curr_mode) < 0)
81 return -errno(*__errno_location ());
82
83 return IN_SET(curr_mode, K_XLATE, K_UNICODE)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){0x01, 0x03})/sizeof(int)]; switch(curr_mode
) { case 0x01: case 0x03: _found = 1; break; default: break; }
_found; })
? 0 : -EBUSY16;
84}
85
86static int toggle_utf8(const char *name, int fd, bool_Bool utf8) {
87 int r;
88 struct termios tc = {};
89
90 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/vconsole/vconsole-setup.c"
, 90, __PRETTY_FUNCTION__); } while (0)
;
91
92 r = ioctl(fd, KDSKBMODE0x4B45, utf8 ? K_UNICODE0x03 : K_XLATE0x01);
93 if (r < 0)
94 return log_warning_errno(errno, "Failed to %s UTF-8 kbdmode on %s: %m", enable_disable(utf8), name)({ int _level = ((4)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/vconsole/vconsole-setup.c", 94, __func__
, "Failed to %s UTF-8 kbdmode on %s: %m", enable_disable(utf8
), name) : -abs(_e); })
;
95
96 r = loop_write(fd, utf8 ? "\033%G" : "\033%@", 3, false0);
97 if (r < 0)
98 return log_warning_errno(r, "Failed to %s UTF-8 term processing on %s: %m", enable_disable(utf8), name)({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/vconsole/vconsole-setup.c", 98, __func__, "Failed to %s UTF-8 term processing on %s: %m"
, enable_disable(utf8), name) : -abs(_e); })
;
99
100 r = tcgetattr(fd, &tc);
101 if (r >= 0) {
102 SET_FLAG(tc.c_iflag, IUTF8, utf8)(tc.c_iflag) = (utf8) ? ((tc.c_iflag) | (0040000)) : ((tc.c_iflag
) & ~(0040000))
;
103 r = tcsetattr(fd, TCSANOW0, &tc);
104 }
105 if (r < 0)
106 return log_warning_errno(errno, "Failed to %s iutf8 flag on %s: %m", enable_disable(utf8), name)({ int _level = ((4)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/vconsole/vconsole-setup.c", 106,
__func__, "Failed to %s iutf8 flag on %s: %m", enable_disable
(utf8), name) : -abs(_e); })
;
107
108 log_debug("UTF-8 kbdmode %sd on %s", enable_disable(utf8), name)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/vconsole/vconsole-setup.c", 108, __func__, "UTF-8 kbdmode %sd on %s"
, enable_disable(utf8), name) : -abs(_e); })
;
109 return 0;
110}
111
112static int toggle_utf8_sysfs(bool_Bool utf8) {
113 int r;
114
115 r = write_string_file("/sys/module/vt/parameters/default_utf8", one_zero(utf8), 0);
116 if (r < 0)
117 return log_warning_errno(r, "Failed to %s sysfs UTF-8 flag: %m", enable_disable(utf8))({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/vconsole/vconsole-setup.c", 117, __func__, "Failed to %s sysfs UTF-8 flag: %m"
, enable_disable(utf8)) : -abs(_e); })
;
118
119 log_debug("Sysfs UTF-8 flag %sd", enable_disable(utf8))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/vconsole/vconsole-setup.c", 119, __func__, "Sysfs UTF-8 flag %sd"
, enable_disable(utf8)) : -abs(_e); })
;
120 return 0;
121}
122
123static int keyboard_load_and_wait(const char *vc, const char *map, const char *map_toggle, bool_Bool utf8) {
124 const char *args[8];
125 unsigned i = 0;
126 pid_t pid;
127 int r;
128
129 /* An empty map means kernel map */
130 if (isempty(map))
131 return 0;
132
133 args[i++] = KBD_LOADKEYS"/bin/loadkeys";
134 args[i++] = "-q";
135 args[i++] = "-C";
136 args[i++] = vc;
137 if (utf8)
138 args[i++] = "-u";
139 args[i++] = map;
140 if (map_toggle)
141 args[i++] = map_toggle;
142 args[i++] = NULL((void*)0);
143
144 if (DEBUG_LOGGING(__builtin_expect(!!(log_get_max_level_realm(LOG_REALM_SYSTEMD
) >= 7),0))
) {
145 _cleanup_free___attribute__((cleanup(freep))) char *cmd;
146
147 cmd = strv_join((char**) args, " ");
148 log_debug("Executing \"%s\"...", strnull(cmd))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/vconsole/vconsole-setup.c", 148, __func__, "Executing \"%s\"..."
, strnull(cmd)) : -abs(_e); })
;
149 }
150
151 r = safe_fork("(loadkeys)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_LOG, &pid);
152 if (r < 0)
153 return r;
154 if (r == 0) {
155 execv(args[0], (char **) args);
156 _exit(EXIT_FAILURE1);
157 }
158
159 return wait_for_terminate_and_check(KBD_LOADKEYS"/bin/loadkeys", pid, WAIT_LOG);
160}
161
162static int font_load_and_wait(const char *vc, const char *font, const char *map, const char *unimap) {
163 const char *args[9];
164 unsigned i = 0;
165 pid_t pid;
166 int r;
167
168 /* Any part can be set independently */
169 if (isempty(font) && isempty(map) && isempty(unimap))
170 return 0;
171
172 args[i++] = KBD_SETFONT"/bin/setfont";
173 args[i++] = "-C";
174 args[i++] = vc;
175 if (!isempty(map)) {
176 args[i++] = "-m";
177 args[i++] = map;
178 }
179 if (!isempty(unimap)) {
180 args[i++] = "-u";
181 args[i++] = unimap;
182 }
183 if (!isempty(font))
184 args[i++] = font;
185 args[i++] = NULL((void*)0);
186
187 if (DEBUG_LOGGING(__builtin_expect(!!(log_get_max_level_realm(LOG_REALM_SYSTEMD
) >= 7),0))
) {
188 _cleanup_free___attribute__((cleanup(freep))) char *cmd;
189
190 cmd = strv_join((char**) args, " ");
191 log_debug("Executing \"%s\"...", strnull(cmd))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/vconsole/vconsole-setup.c", 191, __func__, "Executing \"%s\"..."
, strnull(cmd)) : -abs(_e); })
;
192 }
193
194 r = safe_fork("(setfont)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_LOG, &pid);
195 if (r < 0)
196 return r;
197 if (r == 0) {
198 execv(args[0], (char **) args);
199 _exit(EXIT_FAILURE1);
200 }
201
202 return wait_for_terminate_and_check(KBD_SETFONT"/bin/setfont", pid, WAIT_LOG);
203}
204
205/*
206 * A newly allocated VT uses the font from the source VT. Here
207 * we update all possibly already allocated VTs with the configured
208 * font. It also allows to restart systemd-vconsole-setup.service,
209 * to apply a new font to all VTs.
210 *
211 * We also setup per-console utf8 related stuff: kbdmode, term
212 * processing, stty iutf8.
213 */
214static void setup_remaining_vcs(int src_fd, unsigned src_idx, bool_Bool utf8) {
215 struct console_font_op cfo = {
216 .op = KD_FONT_OP_GET1,
217 .width = UINT_MAX(2147483647 *2U +1U), .height = UINT_MAX(2147483647 *2U +1U),
218 .charcount = UINT_MAX(2147483647 *2U +1U),
219 };
220 struct unimapinit adv = {};
221 struct unimapdesc unimapd;
222 _cleanup_free___attribute__((cleanup(freep))) struct unipair* unipairs = NULL((void*)0);
223 _cleanup_free___attribute__((cleanup(freep))) void *fontbuf = NULL((void*)0);
224 unsigned i;
225 int log_level;
226 int r;
227
228 unipairs = new(struct unipair, USHRT_MAX)((struct unipair*) malloc_multiply(sizeof(struct unipair), ((
32767 *2 +1))))
;
229 if (!unipairs) {
230 log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/vconsole/vconsole-setup.c"
, 230, __func__)
;
231 return;
232 }
233
234 log_level = LOG_WARNING4;
235
236 /* get metadata of the current font (width, height, count) */
237 r = ioctl(src_fd, KDFONTOP0x4B72, &cfo);
238 if (r < 0) {
239 /* We might be called to operate on the dummy console (to setup keymap
240 * mainly) when fbcon deferred takeover is used for example. In such case,
241 * setting font is not supported and is expected to fail. */
242 if (errno(*__errno_location ()) == ENOSYS38)
243 log_level = LOG_DEBUG7;
244
245 log_full_errno(log_level, errno,({ int _level = ((log_level)), _e = (((*__errno_location ()))
), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm
) >= ((_level) & 0x07)) ? log_internal_realm(((_realm)
<< 10 | (_level)), _e, "../src/vconsole/vconsole-setup.c"
, 246, __func__, "KD_FONT_OP_GET failed while trying to get the font metadata: %m"
) : -abs(_e); })
246 "KD_FONT_OP_GET failed while trying to get the font metadata: %m")({ int _level = ((log_level)), _e = (((*__errno_location ()))
), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm
) >= ((_level) & 0x07)) ? log_internal_realm(((_realm)
<< 10 | (_level)), _e, "../src/vconsole/vconsole-setup.c"
, 246, __func__, "KD_FONT_OP_GET failed while trying to get the font metadata: %m"
) : -abs(_e); })
;
247 } else {
248 /* verify parameter sanity first */
249 if (cfo.width > 32 || cfo.height > 32 || cfo.charcount > 512)
250 log_warning("Invalid font metadata - width: %u (max 32), height: %u (max 32), count: %u (max 512)",({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/vconsole/vconsole-setup.c", 251, __func__, "Invalid font metadata - width: %u (max 32), height: %u (max 32), count: %u (max 512)"
, cfo.width, cfo.height, cfo.charcount) : -abs(_e); })
251 cfo.width, cfo.height, cfo.charcount)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/vconsole/vconsole-setup.c", 251, __func__, "Invalid font metadata - width: %u (max 32), height: %u (max 32), count: %u (max 512)"
, cfo.width, cfo.height, cfo.charcount) : -abs(_e); })
;
252 else {
253 /*
254 * Console fonts supported by the kernel are limited in size to 32 x 32 and maximum 512
255 * characters. Thus with 1 bit per pixel it requires up to 65536 bytes. The height always
256 * requries 32 per glyph, regardless of the actual height - see the comment above #define
257 * max_font_size 65536 in drivers/tty/vt/vt.c for more details.
258 */
259 fontbuf = malloc_multiply((cfo.width + 7) / 8 * 32, cfo.charcount);
260 if (!fontbuf) {
261 log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/vconsole/vconsole-setup.c"
, 261, __func__)
;
262 return;
263 }
264 /* get fonts from the source console */
265 cfo.data = fontbuf;
266 r = ioctl(src_fd, KDFONTOP0x4B72, &cfo);
267 if (r < 0)
268 log_warning_errno(errno, "KD_FONT_OP_GET failed while trying to read the font data: %m")({ int _level = ((4)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/vconsole/vconsole-setup.c", 268,
__func__, "KD_FONT_OP_GET failed while trying to read the font data: %m"
) : -abs(_e); })
;
269 else {
270 unimapd.entries = unipairs;
271 unimapd.entry_ct = USHRT_MAX(32767 *2 +1);
272 r = ioctl(src_fd, GIO_UNIMAP0x4B66, &unimapd);
273 if (r < 0)
274 log_warning_errno(errno, "GIO_UNIMAP failed while trying to read unicode mappings: %m")({ int _level = ((4)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/vconsole/vconsole-setup.c", 274,
__func__, "GIO_UNIMAP failed while trying to read unicode mappings: %m"
) : -abs(_e); })
;
275 else
276 cfo.op = KD_FONT_OP_SET0;
277 }
278 }
279 }
280
281 if (cfo.op != KD_FONT_OP_SET0)
282 log_full(log_level, "Fonts will not be copied to remaining consoles")({ int _level = (((log_level))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/vconsole/vconsole-setup.c", 282, __func__, "Fonts will not be copied to remaining consoles"
) : -abs(_e); })
;
283
284 for (i = 1; i <= 63; i++) {
285 char ttyname[sizeof("/dev/tty63")];
286 _cleanup_close___attribute__((cleanup(closep))) int fd_d = -1;
287
288 if (i == src_idx || verify_vc_allocation(i) < 0)
289 continue;
290
291 /* try to open terminal */
292 xsprintf(ttyname, "/dev/tty%u", i)do { if ((__builtin_expect(!!(!(((size_t) snprintf(ttyname, __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(ttyname), typeof(&*(ttyname))), sizeof(ttyname)/sizeof((
ttyname)[0]), ((void)0))), "/dev/tty%u", i) < (__extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(ttyname), typeof(&*(ttyname))), sizeof(ttyname)/sizeof((
ttyname)[0]), ((void)0))))))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("xsprintf: " "ttyname" "[] must be big enough"), "../src/vconsole/vconsole-setup.c"
, 292, __PRETTY_FUNCTION__); } while (0)
;
293 fd_d = open_terminal(ttyname, O_RDWR02|O_CLOEXEC02000000|O_NOCTTY0400);
294 if (fd_d < 0) {
295 log_warning_errno(fd_d, "Unable to open tty%u, fonts will not be copied: %m", i)({ int _level = ((4)), _e = ((fd_d)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/vconsole/vconsole-setup.c", 295, __func__, "Unable to open tty%u, fonts will not be copied: %m"
, i) : -abs(_e); })
;
296 continue;
297 }
298
299 if (verify_vc_kbmode(fd_d) < 0)
300 continue;
301
302 toggle_utf8(ttyname, fd_d, utf8);
303
304 if (cfo.op != KD_FONT_OP_SET0)
305 continue;
306
307 r = ioctl(fd_d, KDFONTOP0x4B72, &cfo);
308 if (r < 0) {
309 log_warning_errno(errno, "KD_FONT_OP_SET failed, fonts will not be copied to tty%u: %m", i)({ int _level = ((4)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/vconsole/vconsole-setup.c", 309,
__func__, "KD_FONT_OP_SET failed, fonts will not be copied to tty%u: %m"
, i) : -abs(_e); })
;
310 continue;
311 }
312
313 /*
314 * copy unicode translation table
315 * unimapd is a ushort count and a pointer to an
316 * array of struct unipair { ushort, ushort }
317 */
318 r = ioctl(fd_d, PIO_UNIMAPCLR0x4B68, &adv);
319 if (r < 0) {
320 log_warning_errno(errno, "PIO_UNIMAPCLR failed, unimaps might be incorrect for tty%u: %m", i)({ int _level = ((4)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/vconsole/vconsole-setup.c", 320,
__func__, "PIO_UNIMAPCLR failed, unimaps might be incorrect for tty%u: %m"
, i) : -abs(_e); })
;
321 continue;
322 }
323
324 r = ioctl(fd_d, PIO_UNIMAP0x4B67, &unimapd);
325 if (r < 0) {
326 log_warning_errno(errno, "PIO_UNIMAP failed, unimaps might be incorrect for tty%u: %m", i)({ int _level = ((4)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/vconsole/vconsole-setup.c", 326,
__func__, "PIO_UNIMAP failed, unimaps might be incorrect for tty%u: %m"
, i) : -abs(_e); })
;
327 continue;
328 }
329
330 log_debug("Font and unimap successfully copied to %s", ttyname)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/vconsole/vconsole-setup.c", 330, __func__, "Font and unimap successfully copied to %s"
, ttyname) : -abs(_e); })
;
331 }
332}
333
334static int find_source_vc(char **ret_path, unsigned *ret_idx) {
335 _cleanup_free___attribute__((cleanup(freep))) char *path = NULL((void*)0);
336 int r, err = 0;
337 unsigned i;
338
339 path = new(char, sizeof("/dev/tty63"))((char*) malloc_multiply(sizeof(char), (sizeof("/dev/tty63"))
))
;
4
Calling 'malloc_multiply'
7
Returned allocated memory
340 if (!path)
8
Assuming 'path' is non-null
9
Taking false branch
341 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/vconsole/vconsole-setup.c"
, 341, __func__)
;
342
343 for (i = 1; i <= 63; i++) {
10
Loop condition is true. Entering loop body
344 _cleanup_close___attribute__((cleanup(closep))) int fd = -1;
345
346 r = verify_vc_allocation(i);
347 if (r
10.1
'r' is >= 0
10.1
'r' is >= 0
< 0) {
11
Taking false branch
348 if (!err)
349 err = -r;
350 continue;
351 }
352
353 sprintf(path, "/dev/tty%u", i);
354 fd = open_terminal(path, O_RDWR02|O_CLOEXEC02000000|O_NOCTTY0400);
355 if (fd < 0) {
12
Assuming 'fd' is >= 0
13
Taking false branch
356 if (!err)
357 err = -fd;
358 continue;
359 }
360 r = verify_vc_kbmode(fd);
361 if (r < 0) {
14
Assuming 'r' is >= 0
15
Taking false branch
362 if (!err)
363 err = -r;
364 continue;
365 }
366
367 /* all checks passed, return this one as a source console */
368 *ret_idx = i;
369 *ret_path = TAKE_PTR(path)({ typeof(path) _ptr_ = (path); (path) = ((void*)0); _ptr_; }
)
;
370 return TAKE_FD(fd)({ int _fd_ = (fd); (fd) = -1; _fd_; });
371 }
372
373 return log_error_errno(err, "No usable source console found: %m")({ int _level = ((3)), _e = ((err)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/vconsole/vconsole-setup.c", 373, __func__, "No usable source console found: %m"
) : -abs(_e); })
;
374}
375
376static int verify_source_vc(char **ret_path, const char *src_vc) {
377 _cleanup_close___attribute__((cleanup(closep))) int fd = -1;
378 char *path;
379 int r;
380
381 fd = open_terminal(src_vc, O_RDWR02|O_CLOEXEC02000000|O_NOCTTY0400);
382 if (fd < 0)
383 return log_error_errno(fd, "Failed to open %s: %m", src_vc)({ int _level = ((3)), _e = ((fd)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/vconsole/vconsole-setup.c", 383, __func__, "Failed to open %s: %m"
, src_vc) : -abs(_e); })
;
384
385 r = verify_vc_device(fd);
386 if (r < 0)
387 return log_error_errno(r, "Device %s is not a virtual console: %m", src_vc)({ 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/vconsole/vconsole-setup.c", 387, __func__, "Device %s is not a virtual console: %m"
, src_vc) : -abs(_e); })
;
388
389 r = verify_vc_allocation_byfd(fd);
390 if (r < 0)
391 return log_error_errno(r, "Virtual console %s is not allocated: %m", src_vc)({ 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/vconsole/vconsole-setup.c", 391, __func__, "Virtual console %s is not allocated: %m"
, src_vc) : -abs(_e); })
;
392
393 r = verify_vc_kbmode(fd);
394 if (r < 0)
395 return log_error_errno(r, "Virtual console %s is not in K_XLATE or K_UNICODE: %m", src_vc)({ 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/vconsole/vconsole-setup.c", 395, __func__, "Virtual console %s is not in K_XLATE or K_UNICODE: %m"
, src_vc) : -abs(_e); })
;
396
397 path = strdup(src_vc);
398 if (!path)
399 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/vconsole/vconsole-setup.c"
, 399, __func__)
;
400
401 *ret_path = path;
402 return TAKE_FD(fd)({ int _fd_ = (fd); (fd) = -1; _fd_; });
403}
404
405int main(int argc, char **argv) {
406 _cleanup_free___attribute__((cleanup(freep))) char
407 *vc = NULL((void*)0),
408 *vc_keymap = NULL((void*)0), *vc_keymap_toggle = NULL((void*)0),
409 *vc_font = NULL((void*)0), *vc_font_map = NULL((void*)0), *vc_font_unimap = NULL((void*)0);
410 _cleanup_close___attribute__((cleanup(closep))) int fd = -1;
411 bool_Bool utf8, keyboard_ok;
412 unsigned idx = 0;
413 int r;
414
415 log_set_target(LOG_TARGET_AUTO);
416 log_parse_environment()log_parse_environment_realm(LOG_REALM_SYSTEMD);
417 log_open();
418
419 umask(0022);
420
421 if (argv[1])
1
Assuming the condition is false
2
Taking false branch
422 fd = verify_source_vc(&vc, argv[1]);
423 else
424 fd = find_source_vc(&vc, &idx);
3
Calling 'find_source_vc'
16
Returned allocated memory via 1st parameter
425 if (fd
16.1
'fd' is >= 0
16.1
'fd' is >= 0
< 0)
17
Taking false branch
426 return EXIT_FAILURE1;
427
428 utf8 = is_locale_utf8();
429
430 r = parse_env_file(NULL((void*)0), "/etc/vconsole.conf", NEWLINE"\n\r",
431 "KEYMAP", &vc_keymap,
432 "KEYMAP_TOGGLE", &vc_keymap_toggle,
433 "FONT", &vc_font,
434 "FONT_MAP", &vc_font_map,
435 "FONT_UNIMAP", &vc_font_unimap,
436 NULL((void*)0));
437 if (r < 0 && r != -ENOENT2)
18
Assuming 'r' is < 0
19
Assuming the condition is false
20
Taking false branch
438 log_warning_errno(r, "Failed to read /etc/vconsole.conf: %m")({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/vconsole/vconsole-setup.c", 438, __func__, "Failed to read /etc/vconsole.conf: %m"
) : -abs(_e); })
;
439
440 /* Let the kernel command line override /etc/vconsole.conf */
441 if (detect_container() <= 0) {
21
Assuming the condition is false
22
Taking false branch
442 r = parse_env_file(NULL((void*)0), "/proc/cmdline", WHITESPACE" \t\n\r",
443 "vconsole.keymap", &vc_keymap,
444 "vconsole.keymap_toggle", &vc_keymap_toggle,
445 "vconsole.font", &vc_font,
446 "vconsole.font_map", &vc_font_map,
447 "vconsole.font_unimap", &vc_font_unimap,
448 /* compatibility with obsolete multiple-dot scheme */
449 "vconsole.keymap.toggle", &vc_keymap_toggle,
450 "vconsole.font.map", &vc_font_map,
451 "vconsole.font.unimap", &vc_font_unimap,
452 NULL((void*)0));
453 if (r < 0 && r != -ENOENT2)
454 log_warning_errno(r, "Failed to read /proc/cmdline: %m")({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/vconsole/vconsole-setup.c", 454, __func__, "Failed to read /proc/cmdline: %m"
) : -abs(_e); })
;
455 }
456
457 (void) toggle_utf8_sysfs(utf8);
458 (void) toggle_utf8(vc, fd, utf8);
459
460 r = font_load_and_wait(vc, vc_font, vc_font_map, vc_font_unimap);
461 keyboard_ok = keyboard_load_and_wait(vc, vc_keymap, vc_keymap_toggle, utf8) == 0;
23
Potential leak of memory pointed to by 'vc'
462
463 if (idx > 0) {
464 if (r == 0)
465 setup_remaining_vcs(fd, idx, utf8);
466 else if (r == EX_OSERR71)
467 /* setfont returns EX_OSERR when ioctl(KDFONTOP/PIO_FONTX/PIO_FONTX) fails.
468 * This might mean various things, but in particular lack of a graphical
469 * console. Let's be generous and not treat this as an error. */
470 log_notice("Setting fonts failed with a \"system error\", ignoring.")({ int _level = (((5))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/vconsole/vconsole-setup.c", 470, __func__, "Setting fonts failed with a \"system error\", ignoring."
) : -abs(_e); })
;
471 else
472 log_warning("Setting source virtual console failed, ignoring remaining ones")({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/vconsole/vconsole-setup.c", 472, __func__, "Setting source virtual console failed, ignoring remaining ones"
) : -abs(_e); })
;
473 }
474
475 return IN_SET(r, 0, EX_OSERR)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){0, 71})/sizeof(int)]; switch(r) { case 0
: case 71: _found = 1; break; default: break; } _found; })
&& keyboard_ok ? EXIT_SUCCESS0 : EXIT_FAILURE1;
476}

../src/basic/alloc-util.h

1/* SPDX-License-Identifier: LGPL-2.1+ */
2#pragma once
3
4#include <alloca.h>
5#include <stddef.h>
6#include <stdlib.h>
7#include <string.h>
8
9#include "macro.h"
10
11#define new(t, n)((t*) malloc_multiply(sizeof(t), (n))) ((t*) malloc_multiply(sizeof(t), (n)))
12
13#define new0(t, n)((t*) calloc((n), sizeof(t))) ((t*) calloc((n), sizeof(t)))
14
15#define newa(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)"
), "../src/basic/alloc-util.h", 15, __PRETTY_FUNCTION__); } while
(0); (t*) __builtin_alloca (sizeof(t)*(n)); })
\
16 ({ \
17 assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)"
), "../src/basic/alloc-util.h", 17, __PRETTY_FUNCTION__); } while
(0)
; \
18 (t*) alloca(sizeof(t)*(n))__builtin_alloca (sizeof(t)*(n)); \
19 })
20
21#define newa0(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)"
), "../src/basic/alloc-util.h", 21, __PRETTY_FUNCTION__); } while
(0); (t*) ({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_
= __builtin_alloca (_len_); (void *) memset(_new_, 0, _len_)
; }); })
\
22 ({ \
23 assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)"
), "../src/basic/alloc-util.h", 23, __PRETTY_FUNCTION__); } while
(0)
; \
24 (t*) alloca0(sizeof(t)*(n))({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_ = __builtin_alloca
(_len_); (void *) memset(_new_, 0, _len_); })
; \
25 })
26
27#define newdup(t, p, n)((t*) memdup_multiply(p, sizeof(t), (n))) ((t*) memdup_multiply(p, sizeof(t), (n)))
28
29#define newdup_suffix0(t, p, n)((t*) memdup_suffix0_multiply(p, sizeof(t), (n))) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n)))
30
31#define malloc0(n)(calloc(1, (n))) (calloc(1, (n)))
32
33static inline void *mfree(void *memory) {
34 free(memory);
35 return NULL((void*)0);
36}
37
38#define free_and_replace(a, b)({ free(a); (a) = (b); (b) = ((void*)0); 0; }) \
39 ({ \
40 free(a); \
41 (a) = (b); \
42 (b) = NULL((void*)0); \
43 0; \
44 })
45
46void* memdup(const void *p, size_t l) _alloc_(2);
47void* memdup_suffix0(const void *p, size_t l) _alloc_(2);
48
49static inline void freep(void *p) {
50 free(*(void**) p);
51}
52
53#define _cleanup_free___attribute__((cleanup(freep))) _cleanup_(freep)__attribute__((cleanup(freep)))
54
55static inline bool_Bool size_multiply_overflow(size_t size, size_t need) {
56 return _unlikely_(need != 0 && size > (SIZE_MAX / need))(__builtin_expect(!!(need != 0 && size > ((18446744073709551615UL
) / need)),0))
;
57}
58
59_malloc___attribute__ ((malloc)) _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) {
60 if (size_multiply_overflow(size, need))
5
Taking false branch
61 return NULL((void*)0);
62
63 return malloc(size * need);
6
Memory is allocated
64}
65
66#if !HAVE_REALLOCARRAY1
67_alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size) {
68 if (size_multiply_overflow(size, need))
69 return NULL((void*)0);
70
71 return realloc(p, size * need);
72}
73#endif
74
75_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) {
76 if (size_multiply_overflow(size, need))
77 return NULL((void*)0);
78
79 return memdup(p, size * need);
80}
81
82_alloc_(2, 3) static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) {
83 if (size_multiply_overflow(size, need))
84 return NULL((void*)0);
85
86 return memdup_suffix0(p, size * need);
87}
88
89void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size);
90void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
91
92#define GREEDY_REALLOC(array, allocated, need)greedy_realloc((void**) &(array), &(allocated), (need
), sizeof((array)[0]))
\
93 greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0]))
94
95#define GREEDY_REALLOC0(array, allocated, need)greedy_realloc0((void**) &(array), &(allocated), (need
), sizeof((array)[0]))
\
96 greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0]))
97
98#define alloca0(n)({ char *_new_; size_t _len_ = n; _new_ = __builtin_alloca (_len_
); (void *) memset(_new_, 0, _len_); })
\
99 ({ \
100 char *_new_; \
101 size_t _len_ = n; \
102 _new_ = alloca(_len_)__builtin_alloca (_len_); \
103 (void *) memset(_new_, 0, _len_); \
104 })
105
106/* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */
107#define alloca_align(size, align)({ void *_ptr_; size_t _mask_ = (align) - 1; _ptr_ = __builtin_alloca
((size) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) &
~_mask_); })
\
108 ({ \
109 void *_ptr_; \
110 size_t _mask_ = (align) - 1; \
111 _ptr_ = alloca((size) + _mask_)__builtin_alloca ((size) + _mask_); \
112 (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \
113 })
114
115#define alloca0_align(size, align)({ void *_new_; size_t _size_ = (size); _new_ = ({ void *_ptr_
; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca ((_size_
) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_
); }); (void*)memset(_new_, 0, _size_); })
\
116 ({ \
117 void *_new_; \
118 size_t _size_ = (size); \
119 _new_ = alloca_align(_size_, (align))({ void *_ptr_; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca
((_size_) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) &
~_mask_); })
; \
120 (void*)memset(_new_, 0, _size_); \
121 })
122
123/* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to
124 * NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */
125#define TAKE_PTR(ptr)({ typeof(ptr) _ptr_ = (ptr); (ptr) = ((void*)0); _ptr_; }) \
126 ({ \
127 typeof(ptr) _ptr_ = (ptr); \
128 (ptr) = NULL((void*)0); \
129 _ptr_; \
130 })