]> sourceware.org Git - glibc.git/blame - misc/syslog.c
syslog: Fix heap buffer overflow in __vsyslog_internal (CVE-2023-6779)
[glibc.git] / misc / syslog.c
CommitLineData
790aa1f2
UD
1/*
2 * Copyright (c) 1983, 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#if defined(LIBC_SCCS) && !defined(lint)
31static char sccsid[] = "@(#)syslog.c 8.4 (Berkeley) 3/18/94";
32#endif /* LIBC_SCCS and not lint */
33
0cc15f45 34#include <libio/libioP.h>
790aa1f2 35#include <paths.h>
0cc15f45
AZ
36#include <stdarg.h>
37#include <stdlib.h>
790aa1f2
UD
38#include <stdio.h>
39#include <stdio_ext.h>
0cc15f45
AZ
40#include <sys/socket.h>
41#include <sys/uio.h>
42#include <sys/un.h>
43#include <syslog.h>
37233df9 44
0cc15f45
AZ
45static int LogType = SOCK_DGRAM; /* type of socket connection */
46static int LogFile = -1; /* fd for log */
47static bool connected; /* have done connect */
48static int LogStat; /* status bits, set by openlog() */
790aa1f2 49static const char *LogTag; /* string to tag the entry with */
0cc15f45
AZ
50static int LogFacility = LOG_USER; /* default facility code */
51static int LogMask = 0xff; /* mask of priorities to be logged */
52extern char *__progname; /* Program name, from crt0. */
790aa1f2
UD
53
54/* Define the lock. */
55__libc_lock_define_initialized (static, syslog_lock)
0cc15f45
AZ
56static void openlog_internal (const char *, int, int);
57static void closelog_internal (void);
790aa1f2
UD
58
59struct cleanup_arg
60{
61 void *buf;
62 struct sigaction *oldaction;
63};
64
65static void
66cancel_handler (void *ptr)
67{
790aa1f2
UD
68 /* Restore the old signal handler. */
69 struct cleanup_arg *clarg = (struct cleanup_arg *) ptr;
70
c4e4b2e1 71 if (clarg != NULL)
ded3cef3
AZ
72 /* Free the memstream buffer, */
73 free (clarg->buf);
c4e4b2e1 74
790aa1f2
UD
75 /* Free the lock. */
76 __libc_lock_unlock (syslog_lock);
77}
78
79
80/*
81 * syslog, vsyslog --
82 * print message on log file; output is intended for syslogd(8).
83 */
84void
0cc15f45 85__syslog (int pri, const char *fmt, ...)
790aa1f2 86{
0cc15f45 87 va_list ap;
790aa1f2 88
0cc15f45
AZ
89 va_start (ap, fmt);
90 __vsyslog_internal (pri, fmt, ap, 0);
91 va_end (ap);
790aa1f2 92}
c6251f03
RM
93ldbl_hidden_def (__syslog, syslog)
94ldbl_strong_alias (__syslog, syslog)
790aa1f2 95
124fc732 96void
0cc15f45 97__vsyslog (int pri, const char *fmt, va_list ap)
124fc732 98{
0cc15f45 99 __vsyslog_internal (pri, fmt, ap, 0);
124fc732
ZW
100}
101ldbl_weak_alias (__vsyslog, vsyslog)
102
790aa1f2 103void
ba745eff 104___syslog_chk (int pri, int flag, const char *fmt, ...)
29c21e49 105{
0cc15f45 106 va_list ap;
29c21e49 107
0cc15f45
AZ
108 va_start (ap, fmt);
109 __vsyslog_internal (pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
110 va_end (ap);
29c21e49 111}
ba745eff
FB
112ldbl_hidden_def (___syslog_chk, __syslog_chk)
113ldbl_strong_alias (___syslog_chk, __syslog_chk)
29c21e49
UD
114
115void
0cc15f45 116__vsyslog_chk (int pri, int flag, const char *fmt, va_list ap)
124fc732 117{
0cc15f45 118 __vsyslog_internal (pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
124fc732
ZW
119}
120
121void
0cc15f45
AZ
122__vsyslog_internal (int pri, const char *fmt, va_list ap,
123 unsigned int mode_flags)
790aa1f2 124{
a583b6ad
AZ
125 /* Try to use a static buffer as an optimization. */
126 char bufs[1024];
6bd0e4ef
AS
127 char *buf = bufs;
128 size_t bufsize;
129
f9f5c70e 130 int msgoff;
0cc15f45 131 int saved_errno = errno;
0cc15f45
AZ
132
133#define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
134 /* Check for invalid bits. */
135 if (pri & ~(LOG_PRIMASK | LOG_FACMASK))
136 {
137 syslog (INTERNALLOG, "syslog: unknown facility/priority: %x", pri);
138 pri &= LOG_PRIMASK | LOG_FACMASK;
139 }
140
141 /* Prepare for multiple users. We have to take care: most syscalls we are
142 using are cancellation points. */
f9f5c70e 143 struct cleanup_arg clarg = { NULL, NULL };
0cc15f45
AZ
144 __libc_cleanup_push (cancel_handler, &clarg);
145 __libc_lock_lock (syslog_lock);
146
147 /* Check priority against setlogmask values. */
148 if ((LOG_MASK (LOG_PRI (pri)) & LogMask) == 0)
149 goto out;
150
151 /* Set default facility if none specified. */
152 if ((pri & LOG_FACMASK) == 0)
153 pri |= LogFacility;
154
a583b6ad
AZ
155 pid_t pid = LogStat & LOG_PID ? __getpid () : 0;
156
157 /* "%b %e %H:%M:%S " */
158 char timestamp[sizeof "MMM DD hh:mm:ss "];
ac0d208b 159 __time64_t now = time64_now ();
a583b6ad 160 struct tm now_tm;
ac0d208b
AZ
161 struct tm *now_tmp = __localtime64_r (&now, &now_tm);
162 bool has_ts = now_tmp != NULL;
163
164 /* In the unlikely case of localtime_r failure (tm_year out of int range)
165 skip the hostname so the message is handled as valid PRI but without
166 TIMESTAMP or invalid TIMESTAMP (which should force the relay to add the
167 timestamp itself). */
168 if (has_ts)
169 __strftime_l (timestamp, sizeof timestamp, "%h %e %T ", now_tmp,
170 _nl_C_locobj_ptr);
a583b6ad
AZ
171
172#define SYSLOG_HEADER(__pri, __timestamp, __msgoff, pid) \
45459476 173 "<%d>%s%n%s%s%.0d%s: ", \
a583b6ad
AZ
174 __pri, __timestamp, __msgoff, \
175 LogTag == NULL ? __progname : LogTag, \
176 "[" + (pid == 0), pid, "]" + (pid == 0)
177
ac0d208b
AZ
178#define SYSLOG_HEADER_WITHOUT_TS(__pri, __msgoff) \
179 "<%d>: %n", __pri, __msgoff
180
6bd0e4ef 181 int l, vl;
ac0d208b
AZ
182 if (has_ts)
183 l = __snprintf (bufs, sizeof bufs,
184 SYSLOG_HEADER (pri, timestamp, &msgoff, pid));
185 else
186 l = __snprintf (bufs, sizeof bufs,
187 SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
7e5a0c28
AS
188 if (l < 0)
189 goto out;
6bd0e4ef
AS
190
191 char *pos;
192 size_t len;
193
7e5a0c28 194 if (l < sizeof bufs)
0cc15f45 195 {
6bd0e4ef
AS
196 /* At this point, there is still a chance that we can print the
197 remaining part of the log into bufs and use that. */
198 pos = bufs + l;
199 len = sizeof (bufs) - l;
200 }
201 else
202 {
203 buf = NULL;
204 /* We already know that bufs is too small to use for this log message.
205 The next vsnprintf into bufs is used only to calculate the total
206 required buffer length. We will discard bufs contents and allocate
207 an appropriately sized buffer later instead. */
208 pos = bufs;
209 len = sizeof (bufs);
210 }
a583b6ad 211
6bd0e4ef
AS
212 {
213 va_list apc;
214 va_copy (apc, ap);
0cc15f45 215
6bd0e4ef
AS
216 /* Restore errno for %m format. */
217 __set_errno (saved_errno);
0cc15f45 218
6bd0e4ef 219 vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags);
7e5a0c28
AS
220 va_end (apc);
221
222 if (vl < 0)
223 goto out;
6bd0e4ef 224
7e5a0c28 225 if (vl >= len)
6bd0e4ef
AS
226 buf = NULL;
227
228 bufsize = l + vl;
6bd0e4ef 229 }
a583b6ad
AZ
230
231 if (buf == NULL)
f9f5c70e 232 {
52a5be0d 233 buf = malloc ((bufsize + 1) * sizeof (char));
a583b6ad
AZ
234 if (buf != NULL)
235 {
236 /* Tell the cancellation handler to free this buffer. */
237 clarg.buf = buf;
238
7e5a0c28 239 int cl;
ac0d208b 240 if (has_ts)
7e5a0c28
AS
241 cl = __snprintf (buf, l + 1,
242 SYSLOG_HEADER (pri, timestamp, &msgoff, pid));
ac0d208b 243 else
7e5a0c28
AS
244 cl = __snprintf (buf, l + 1,
245 SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
246 if (cl != l)
247 goto out;
52a5be0d
AZ
248
249 va_list apc;
250 va_copy (apc, ap);
7e5a0c28
AS
251 cl = __vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc,
252 mode_flags);
52a5be0d 253 va_end (apc);
7e5a0c28
AS
254
255 if (cl != vl)
256 goto out;
a583b6ad
AZ
257 }
258 else
259 {
7e5a0c28 260 int bl;
a583b6ad 261 /* Nothing much to do but emit an error message. */
7e5a0c28
AS
262 bl = __snprintf (bufs, sizeof bufs,
263 "out of memory[%d]", __getpid ());
264 if (bl < 0 || bl >= sizeof bufs)
265 goto out;
266
267 bufsize = bl;
a583b6ad 268 buf = bufs;
7e5a0c28 269 msgoff = 0;
a583b6ad 270 }
f9f5c70e 271 }
0cc15f45
AZ
272
273 /* Output to stderr if requested. */
274 if (LogStat & LOG_PERROR)
f9f5c70e
AZ
275 __dprintf (STDERR_FILENO, "%s%s", buf + msgoff,
276 "\n" + (buf[bufsize - 1] == '\n'));
0cc15f45
AZ
277
278 /* Get connected, output the message to the local logger. */
279 if (!connected)
280 openlog_internal (NULL, LogStat | LOG_NDELAY, LogFacility);
281
282 /* If we have a SOCK_STREAM connection, also send ASCII NUL as a record
283 terminator. */
284 if (LogType == SOCK_STREAM)
285 ++bufsize;
286
287 if (!connected || __send (LogFile, buf, bufsize, MSG_NOSIGNAL) < 0)
288 {
289 if (connected)
290 {
291 /* Try to reopen the syslog connection. Maybe it went down. */
292 closelog_internal ();
293 openlog_internal (NULL, LogStat | LOG_NDELAY, LogFacility);
790aa1f2
UD
294 }
295
0cc15f45
AZ
296 if (!connected || __send (LogFile, buf, bufsize, MSG_NOSIGNAL) < 0)
297 {
298 closelog_internal (); /* attempt re-open next time */
299 /*
300 * Output the message to the console; don't worry
301 * about blocking, if console blocks everything will.
302 * Make sure the error reported is the one from the
303 * syslogd failure.
304 */
f9f5c70e 305 int fd;
0cc15f45
AZ
306 if (LogStat & LOG_CONS &&
307 (fd = __open (_PATH_CONSOLE, O_WRONLY | O_NOCTTY
308 | O_CLOEXEC, 0)) >= 0)
309 {
310 __dprintf (fd, "%s\r\n", buf + msgoff);
311 __close (fd);
312 }
313 }
314 }
315
316out:
317 /* End of critical section. */
318 __libc_cleanup_pop (0);
319 __libc_lock_unlock (syslog_lock);
320
a583b6ad 321 if (buf != bufs)
0cc15f45 322 free (buf);
790aa1f2 323}
790aa1f2 324
5ad1a81c
AZ
325/* AF_UNIX address of local logger */
326static const struct sockaddr_un SyslogAddr =
327 {
328 .sun_family = AF_UNIX,
329 .sun_path = _PATH_LOG
330 };
790aa1f2
UD
331
332static void
0cc15f45 333openlog_internal (const char *ident, int logstat, int logfac)
790aa1f2 334{
0cc15f45
AZ
335 if (ident != NULL)
336 LogTag = ident;
337 LogStat = logstat;
338 if ((logfac & ~LOG_FACMASK) == 0)
339 LogFacility = logfac;
340
341 int retry = 0;
342 while (retry < 2)
343 {
344 if (LogFile == -1)
345 {
346 if (LogStat & LOG_NDELAY)
347 {
348 LogFile = __socket (AF_UNIX, LogType | SOCK_CLOEXEC, 0);
349 if (LogFile == -1)
350 return;
351 }
352 }
353 if (LogFile != -1 && !connected)
354 {
355 int old_errno = errno;
356 if (__connect (LogFile, &SyslogAddr, sizeof (SyslogAddr)) == -1)
357 {
358 int saved_errno = errno;
359 int fd = LogFile;
360 LogFile = -1;
361 __close (fd);
362 __set_errno (old_errno);
363 if (saved_errno == EPROTOTYPE)
790aa1f2 364 {
0cc15f45
AZ
365 /* retry with the other type: */
366 LogType = LogType == SOCK_DGRAM ? SOCK_STREAM : SOCK_DGRAM;
367 ++retry;
368 continue;
790aa1f2 369 }
0cc15f45
AZ
370 }
371 else
372 connected = true;
790aa1f2 373 }
0cc15f45
AZ
374 break;
375 }
790aa1f2
UD
376}
377
378void
379openlog (const char *ident, int logstat, int logfac)
380{
381 /* Protect against multiple users and cancellation. */
382 __libc_cleanup_push (cancel_handler, NULL);
383 __libc_lock_lock (syslog_lock);
384
385 openlog_internal (ident, logstat, logfac);
386
387 __libc_cleanup_pop (1);
388}
389
790aa1f2 390static void
60d2f8f3 391closelog_internal (void)
790aa1f2
UD
392{
393 if (!connected)
394 return;
395
396 __close (LogFile);
397 LogFile = -1;
7cb10381 398 connected = false;
790aa1f2
UD
399}
400
401void
60d2f8f3 402closelog (void)
790aa1f2
UD
403{
404 /* Protect against multiple users and cancellation. */
405 __libc_cleanup_push (cancel_handler, NULL);
406 __libc_lock_lock (syslog_lock);
407
408 closelog_internal ();
409 LogTag = NULL;
410 LogType = SOCK_DGRAM; /* this is the default */
411
412 /* Free the lock. */
413 __libc_cleanup_pop (1);
414}
415
416/* setlogmask -- set the log mask level */
417int
9d46370c 418setlogmask (int pmask)
790aa1f2 419{
0cc15f45 420 int omask;
790aa1f2 421
0cc15f45
AZ
422 /* Protect against multiple users. */
423 __libc_lock_lock (syslog_lock);
c4e4b2e1 424
0cc15f45
AZ
425 omask = LogMask;
426 if (pmask != 0)
427 LogMask = pmask;
c4e4b2e1 428
0cc15f45 429 __libc_lock_unlock (syslog_lock);
c4e4b2e1 430
0cc15f45 431 return (omask);
790aa1f2 432}
This page took 0.474016 seconds and 5 git commands to generate.