qemu

Форк
0
/
oslib-posix.c 
933 строки · 25.3 Кб
1
/*
2
 * os-posix-lib.c
3
 *
4
 * Copyright (c) 2003-2008 Fabrice Bellard
5
 * Copyright (c) 2010 Red Hat, Inc.
6
 *
7
 * QEMU library functions on POSIX which are shared between QEMU and
8
 * the QEMU tools.
9
 *
10
 * Permission is hereby granted, free of charge, to any person obtaining a copy
11
 * of this software and associated documentation files (the "Software"), to deal
12
 * in the Software without restriction, including without limitation the rights
13
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
 * copies of the Software, and to permit persons to whom the Software is
15
 * furnished to do so, subject to the following conditions:
16
 *
17
 * The above copyright notice and this permission notice shall be included in
18
 * all copies or substantial portions of the Software.
19
 *
20
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26
 * THE SOFTWARE.
27
 */
28

29
#include "qemu/osdep.h"
30
#include <termios.h>
31

32
#include <glib/gprintf.h>
33

34
#include "sysemu/sysemu.h"
35
#include "trace.h"
36
#include "qapi/error.h"
37
#include "qemu/error-report.h"
38
#include "qemu/madvise.h"
39
#include "qemu/sockets.h"
40
#include "qemu/thread.h"
41
#include <libgen.h>
42
#include "qemu/cutils.h"
43
#include "qemu/units.h"
44
#include "qemu/thread-context.h"
45
#include "qemu/main-loop.h"
46

47
#ifdef CONFIG_LINUX
48
#include <sys/syscall.h>
49
#endif
50

51
#ifdef __FreeBSD__
52
#include <sys/thr.h>
53
#include <sys/user.h>
54
#include <libutil.h>
55
#endif
56

57
#ifdef __NetBSD__
58
#include <lwp.h>
59
#endif
60

61
#include "qemu/mmap-alloc.h"
62

63
#define MAX_MEM_PREALLOC_THREAD_COUNT 16
64

65
struct MemsetThread;
66

67
static QLIST_HEAD(, MemsetContext) memset_contexts =
68
    QLIST_HEAD_INITIALIZER(memset_contexts);
69

70
typedef struct MemsetContext {
71
    bool all_threads_created;
72
    bool any_thread_failed;
73
    struct MemsetThread *threads;
74
    int num_threads;
75
    QLIST_ENTRY(MemsetContext) next;
76
} MemsetContext;
77

78
struct MemsetThread {
79
    char *addr;
80
    size_t numpages;
81
    size_t hpagesize;
82
    QemuThread pgthread;
83
    sigjmp_buf env;
84
    MemsetContext *context;
85
};
86
typedef struct MemsetThread MemsetThread;
87

88
/* used by sigbus_handler() */
89
static MemsetContext *sigbus_memset_context;
90
struct sigaction sigbus_oldact;
91
static QemuMutex sigbus_mutex;
92

93
static QemuMutex page_mutex;
94
static QemuCond page_cond;
95

96
int qemu_get_thread_id(void)
97
{
98
#if defined(__linux__)
99
    return syscall(SYS_gettid);
100
#elif defined(__FreeBSD__)
101
    /* thread id is up to INT_MAX */
102
    long tid;
103
    thr_self(&tid);
104
    return (int)tid;
105
#elif defined(__NetBSD__)
106
    return _lwp_self();
107
#elif defined(__OpenBSD__)
108
    return getthrid();
109
#else
110
    return getpid();
111
#endif
112
}
113

114
int qemu_daemon(int nochdir, int noclose)
115
{
116
    return daemon(nochdir, noclose);
117
}
118

119
bool qemu_write_pidfile(const char *path, Error **errp)
120
{
121
    int fd;
122
    char pidstr[32];
123

124
    while (1) {
125
        struct stat a, b;
126
        struct flock lock = {
127
            .l_type = F_WRLCK,
128
            .l_whence = SEEK_SET,
129
            .l_len = 0,
130
        };
131

132
        fd = qemu_create(path, O_WRONLY, S_IRUSR | S_IWUSR, errp);
133
        if (fd == -1) {
134
            return false;
135
        }
136

137
        if (fstat(fd, &b) < 0) {
138
            error_setg_errno(errp, errno, "Cannot stat file");
139
            goto fail_close;
140
        }
141

142
        if (fcntl(fd, F_SETLK, &lock)) {
143
            error_setg_errno(errp, errno, "Cannot lock pid file");
144
            goto fail_close;
145
        }
146

147
        /*
148
         * Now make sure the path we locked is the same one that now
149
         * exists on the filesystem.
150
         */
151
        if (stat(path, &a) < 0) {
152
            /*
153
             * PID file disappeared, someone else must be racing with
154
             * us, so try again.
155
             */
156
            close(fd);
157
            continue;
158
        }
159

160
        if (a.st_ino == b.st_ino) {
161
            break;
162
        }
163

164
        /*
165
         * PID file was recreated, someone else must be racing with
166
         * us, so try again.
167
         */
168
        close(fd);
169
    }
170

171
    if (ftruncate(fd, 0) < 0) {
172
        error_setg_errno(errp, errno, "Failed to truncate pid file");
173
        goto fail_unlink;
174
    }
175

176
    snprintf(pidstr, sizeof(pidstr), FMT_pid "\n", getpid());
177
    if (qemu_write_full(fd, pidstr, strlen(pidstr)) != strlen(pidstr)) {
178
        error_setg(errp, "Failed to write pid file");
179
        goto fail_unlink;
180
    }
181

182
    return true;
183

184
fail_unlink:
185
    unlink(path);
186
fail_close:
187
    close(fd);
188
    return false;
189
}
190

191
/* alloc shared memory pages */
192
void *qemu_anon_ram_alloc(size_t size, uint64_t *alignment, bool shared,
193
                          bool noreserve)
194
{
195
    const uint32_t qemu_map_flags = (shared ? QEMU_MAP_SHARED : 0) |
196
                                    (noreserve ? QEMU_MAP_NORESERVE : 0);
197
    size_t align = QEMU_VMALLOC_ALIGN;
198
    void *ptr = qemu_ram_mmap(-1, size, align, qemu_map_flags, 0);
199

200
    if (ptr == MAP_FAILED) {
201
        return NULL;
202
    }
203

204
    if (alignment) {
205
        *alignment = align;
206
    }
207

208
    trace_qemu_anon_ram_alloc(size, ptr);
209
    return ptr;
210
}
211

212
void qemu_anon_ram_free(void *ptr, size_t size)
213
{
214
    trace_qemu_anon_ram_free(ptr, size);
215
    qemu_ram_munmap(-1, ptr, size);
216
}
217

218
void qemu_socket_set_block(int fd)
219
{
220
    g_unix_set_fd_nonblocking(fd, false, NULL);
221
}
222

223
int qemu_socket_try_set_nonblock(int fd)
224
{
225
    return g_unix_set_fd_nonblocking(fd, true, NULL) ? 0 : -errno;
226
}
227

228
void qemu_socket_set_nonblock(int fd)
229
{
230
    int f;
231
    f = qemu_socket_try_set_nonblock(fd);
232
    assert(f == 0);
233
}
234

235
int socket_set_fast_reuse(int fd)
236
{
237
    int val = 1, ret;
238

239
    ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
240
                     (const char *)&val, sizeof(val));
241

242
    assert(ret == 0);
243

244
    return ret;
245
}
246

247
void qemu_set_cloexec(int fd)
248
{
249
    int f;
250
    f = fcntl(fd, F_GETFD);
251
    assert(f != -1);
252
    f = fcntl(fd, F_SETFD, f | FD_CLOEXEC);
253
    assert(f != -1);
254
}
255

256
int qemu_socketpair(int domain, int type, int protocol, int sv[2])
257
{
258
    int ret;
259

260
#ifdef SOCK_CLOEXEC
261
    ret = socketpair(domain, type | SOCK_CLOEXEC, protocol, sv);
262
    if (ret != -1 || errno != EINVAL) {
263
        return ret;
264
    }
265
#endif
266
    ret = socketpair(domain, type, protocol, sv);
267
    if (ret == 0) {
268
        qemu_set_cloexec(sv[0]);
269
        qemu_set_cloexec(sv[1]);
270
    }
271

272
    return ret;
273
}
274

275
char *
276
qemu_get_local_state_dir(void)
277
{
278
    return get_relocated_path(CONFIG_QEMU_LOCALSTATEDIR);
279
}
280

281
void qemu_set_tty_echo(int fd, bool echo)
282
{
283
    struct termios tty;
284

285
    tcgetattr(fd, &tty);
286

287
    if (echo) {
288
        tty.c_lflag |= ECHO | ECHONL | ICANON | IEXTEN;
289
    } else {
290
        tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN);
291
    }
292

293
    tcsetattr(fd, TCSANOW, &tty);
294
}
295

296
#ifdef CONFIG_LINUX
297
static void sigbus_handler(int signal, siginfo_t *siginfo, void *ctx)
298
#else /* CONFIG_LINUX */
299
static void sigbus_handler(int signal)
300
#endif /* CONFIG_LINUX */
301
{
302
    int i;
303

304
    if (sigbus_memset_context) {
305
        for (i = 0; i < sigbus_memset_context->num_threads; i++) {
306
            MemsetThread *thread = &sigbus_memset_context->threads[i];
307

308
            if (qemu_thread_is_self(&thread->pgthread)) {
309
                siglongjmp(thread->env, 1);
310
            }
311
        }
312
    }
313

314
#ifdef CONFIG_LINUX
315
    /*
316
     * We assume that the MCE SIGBUS handler could have been registered. We
317
     * should never receive BUS_MCEERR_AO on any of our threads, but only on
318
     * the main thread registered for PR_MCE_KILL_EARLY. Further, we should not
319
     * receive BUS_MCEERR_AR triggered by action of other threads on one of
320
     * our threads. So, no need to check for unrelated SIGBUS when seeing one
321
     * for our threads.
322
     *
323
     * We will forward to the MCE handler, which will either handle the SIGBUS
324
     * or reinstall the default SIGBUS handler and reraise the SIGBUS. The
325
     * default SIGBUS handler will crash the process, so we don't care.
326
     */
327
    if (sigbus_oldact.sa_flags & SA_SIGINFO) {
328
        sigbus_oldact.sa_sigaction(signal, siginfo, ctx);
329
        return;
330
    }
331
#endif /* CONFIG_LINUX */
332
    warn_report("qemu_prealloc_mem: unrelated SIGBUS detected and ignored");
333
}
334

335
static void *do_touch_pages(void *arg)
336
{
337
    MemsetThread *memset_args = (MemsetThread *)arg;
338
    sigset_t set, oldset;
339
    int ret = 0;
340

341
    /*
342
     * On Linux, the page faults from the loop below can cause mmap_sem
343
     * contention with allocation of the thread stacks.  Do not start
344
     * clearing until all threads have been created.
345
     */
346
    qemu_mutex_lock(&page_mutex);
347
    while (!memset_args->context->all_threads_created) {
348
        qemu_cond_wait(&page_cond, &page_mutex);
349
    }
350
    qemu_mutex_unlock(&page_mutex);
351

352
    /* unblock SIGBUS */
353
    sigemptyset(&set);
354
    sigaddset(&set, SIGBUS);
355
    pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
356

357
    if (sigsetjmp(memset_args->env, 1)) {
358
        ret = -EFAULT;
359
    } else {
360
        char *addr = memset_args->addr;
361
        size_t numpages = memset_args->numpages;
362
        size_t hpagesize = memset_args->hpagesize;
363
        size_t i;
364
        for (i = 0; i < numpages; i++) {
365
            /*
366
             * Read & write back the same value, so we don't
367
             * corrupt existing user/app data that might be
368
             * stored.
369
             *
370
             * 'volatile' to stop compiler optimizing this away
371
             * to a no-op
372
             */
373
            *(volatile char *)addr = *addr;
374
            addr += hpagesize;
375
        }
376
    }
377
    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
378
    return (void *)(uintptr_t)ret;
379
}
380

381
static void *do_madv_populate_write_pages(void *arg)
382
{
383
    MemsetThread *memset_args = (MemsetThread *)arg;
384
    const size_t size = memset_args->numpages * memset_args->hpagesize;
385
    char * const addr = memset_args->addr;
386
    int ret = 0;
387

388
    /* See do_touch_pages(). */
389
    qemu_mutex_lock(&page_mutex);
390
    while (!memset_args->context->all_threads_created) {
391
        qemu_cond_wait(&page_cond, &page_mutex);
392
    }
393
    qemu_mutex_unlock(&page_mutex);
394

395
    if (size && qemu_madvise(addr, size, QEMU_MADV_POPULATE_WRITE)) {
396
        ret = -errno;
397
    }
398
    return (void *)(uintptr_t)ret;
399
}
400

401
static inline int get_memset_num_threads(size_t hpagesize, size_t numpages,
402
                                         int max_threads)
403
{
404
    long host_procs = sysconf(_SC_NPROCESSORS_ONLN);
405
    int ret = 1;
406

407
    if (host_procs > 0) {
408
        ret = MIN(MIN(host_procs, MAX_MEM_PREALLOC_THREAD_COUNT), max_threads);
409
    }
410

411
    /* Especially with gigantic pages, don't create more threads than pages. */
412
    ret = MIN(ret, numpages);
413
    /* Don't start threads to prealloc comparatively little memory. */
414
    ret = MIN(ret, MAX(1, hpagesize * numpages / (64 * MiB)));
415

416
    /* In case sysconf() fails, we fall back to single threaded */
417
    return ret;
418
}
419

420
static int wait_and_free_mem_prealloc_context(MemsetContext *context)
421
{
422
    int i, ret = 0, tmp;
423

424
    for (i = 0; i < context->num_threads; i++) {
425
        tmp = (uintptr_t)qemu_thread_join(&context->threads[i].pgthread);
426

427
        if (tmp) {
428
            ret = tmp;
429
        }
430
    }
431
    g_free(context->threads);
432
    g_free(context);
433
    return ret;
434
}
435

436
static int touch_all_pages(char *area, size_t hpagesize, size_t numpages,
437
                           int max_threads, ThreadContext *tc, bool async,
438
                           bool use_madv_populate_write)
439
{
440
    static gsize initialized = 0;
441
    MemsetContext *context = g_malloc0(sizeof(MemsetContext));
442
    size_t numpages_per_thread, leftover;
443
    void *(*touch_fn)(void *);
444
    int ret, i = 0;
445
    char *addr = area;
446

447
    /*
448
     * Asynchronous preallocation is only allowed when using MADV_POPULATE_WRITE
449
     * and prealloc context for thread placement.
450
     */
451
    if (!use_madv_populate_write || !tc) {
452
        async = false;
453
    }
454

455
    context->num_threads =
456
        get_memset_num_threads(hpagesize, numpages, max_threads);
457

458
    if (g_once_init_enter(&initialized)) {
459
        qemu_mutex_init(&page_mutex);
460
        qemu_cond_init(&page_cond);
461
        g_once_init_leave(&initialized, 1);
462
    }
463

464
    if (use_madv_populate_write) {
465
        /*
466
         * Avoid creating a single thread for MADV_POPULATE_WRITE when
467
         * preallocating synchronously.
468
         */
469
        if (context->num_threads == 1 && !async) {
470
            ret = 0;
471
            if (qemu_madvise(area, hpagesize * numpages,
472
                             QEMU_MADV_POPULATE_WRITE)) {
473
                ret = -errno;
474
            }
475
            g_free(context);
476
            return ret;
477
        }
478
        touch_fn = do_madv_populate_write_pages;
479
    } else {
480
        touch_fn = do_touch_pages;
481
    }
482

483
    context->threads = g_new0(MemsetThread, context->num_threads);
484
    numpages_per_thread = numpages / context->num_threads;
485
    leftover = numpages % context->num_threads;
486
    for (i = 0; i < context->num_threads; i++) {
487
        context->threads[i].addr = addr;
488
        context->threads[i].numpages = numpages_per_thread + (i < leftover);
489
        context->threads[i].hpagesize = hpagesize;
490
        context->threads[i].context = context;
491
        if (tc) {
492
            thread_context_create_thread(tc, &context->threads[i].pgthread,
493
                                         "touch_pages",
494
                                         touch_fn, &context->threads[i],
495
                                         QEMU_THREAD_JOINABLE);
496
        } else {
497
            qemu_thread_create(&context->threads[i].pgthread, "touch_pages",
498
                               touch_fn, &context->threads[i],
499
                               QEMU_THREAD_JOINABLE);
500
        }
501
        addr += context->threads[i].numpages * hpagesize;
502
    }
503

504
    if (async) {
505
        /*
506
         * async requests currently require the BQL. Add it to the list and kick
507
         * preallocation off during qemu_finish_async_prealloc_mem().
508
         */
509
        assert(bql_locked());
510
        QLIST_INSERT_HEAD(&memset_contexts, context, next);
511
        return 0;
512
    }
513

514
    if (!use_madv_populate_write) {
515
        sigbus_memset_context = context;
516
    }
517

518
    qemu_mutex_lock(&page_mutex);
519
    context->all_threads_created = true;
520
    qemu_cond_broadcast(&page_cond);
521
    qemu_mutex_unlock(&page_mutex);
522

523
    ret = wait_and_free_mem_prealloc_context(context);
524

525
    if (!use_madv_populate_write) {
526
        sigbus_memset_context = NULL;
527
    }
528
    return ret;
529
}
530

531
bool qemu_finish_async_prealloc_mem(Error **errp)
532
{
533
    int ret = 0, tmp;
534
    MemsetContext *context, *next_context;
535

536
    /* Waiting for preallocation requires the BQL. */
537
    assert(bql_locked());
538
    if (QLIST_EMPTY(&memset_contexts)) {
539
        return true;
540
    }
541

542
    qemu_mutex_lock(&page_mutex);
543
    QLIST_FOREACH(context, &memset_contexts, next) {
544
        context->all_threads_created = true;
545
    }
546
    qemu_cond_broadcast(&page_cond);
547
    qemu_mutex_unlock(&page_mutex);
548

549
    QLIST_FOREACH_SAFE(context, &memset_contexts, next, next_context) {
550
        QLIST_REMOVE(context, next);
551
        tmp = wait_and_free_mem_prealloc_context(context);
552
        if (tmp) {
553
            ret = tmp;
554
        }
555
    }
556

557
    if (ret) {
558
        error_setg_errno(errp, -ret,
559
                         "qemu_prealloc_mem: preallocating memory failed");
560
        return false;
561
    }
562
    return true;
563
}
564

565
static bool madv_populate_write_possible(char *area, size_t pagesize)
566
{
567
    return !qemu_madvise(area, pagesize, QEMU_MADV_POPULATE_WRITE) ||
568
           errno != EINVAL;
569
}
570

571
bool qemu_prealloc_mem(int fd, char *area, size_t sz, int max_threads,
572
                       ThreadContext *tc, bool async, Error **errp)
573
{
574
    static gsize initialized;
575
    int ret;
576
    size_t hpagesize = qemu_fd_getpagesize(fd);
577
    size_t numpages = DIV_ROUND_UP(sz, hpagesize);
578
    bool use_madv_populate_write;
579
    struct sigaction act;
580
    bool rv = true;
581

582
    /*
583
     * Sense on every invocation, as MADV_POPULATE_WRITE cannot be used for
584
     * some special mappings, such as mapping /dev/mem.
585
     */
586
    use_madv_populate_write = madv_populate_write_possible(area, hpagesize);
587

588
    if (!use_madv_populate_write) {
589
        if (g_once_init_enter(&initialized)) {
590
            qemu_mutex_init(&sigbus_mutex);
591
            g_once_init_leave(&initialized, 1);
592
        }
593

594
        qemu_mutex_lock(&sigbus_mutex);
595
        memset(&act, 0, sizeof(act));
596
#ifdef CONFIG_LINUX
597
        act.sa_sigaction = &sigbus_handler;
598
        act.sa_flags = SA_SIGINFO;
599
#else /* CONFIG_LINUX */
600
        act.sa_handler = &sigbus_handler;
601
        act.sa_flags = 0;
602
#endif /* CONFIG_LINUX */
603

604
        ret = sigaction(SIGBUS, &act, &sigbus_oldact);
605
        if (ret) {
606
            qemu_mutex_unlock(&sigbus_mutex);
607
            error_setg_errno(errp, errno,
608
                "qemu_prealloc_mem: failed to install signal handler");
609
            return false;
610
        }
611
    }
612

613
    /* touch pages simultaneously */
614
    ret = touch_all_pages(area, hpagesize, numpages, max_threads, tc, async,
615
                          use_madv_populate_write);
616
    if (ret) {
617
        error_setg_errno(errp, -ret,
618
                         "qemu_prealloc_mem: preallocating memory failed");
619
        rv = false;
620
    }
621

622
    if (!use_madv_populate_write) {
623
        ret = sigaction(SIGBUS, &sigbus_oldact, NULL);
624
        if (ret) {
625
            /* Terminate QEMU since it can't recover from error */
626
            perror("qemu_prealloc_mem: failed to reinstall signal handler");
627
            exit(1);
628
        }
629
        qemu_mutex_unlock(&sigbus_mutex);
630
    }
631
    return rv;
632
}
633

634
char *qemu_get_pid_name(pid_t pid)
635
{
636
    char *name = NULL;
637

638
#if defined(__FreeBSD__)
639
    /* BSDs don't have /proc, but they provide a nice substitute */
640
    struct kinfo_proc *proc = kinfo_getproc(pid);
641

642
    if (proc) {
643
        name = g_strdup(proc->ki_comm);
644
        free(proc);
645
    }
646
#else
647
    /* Assume a system with reasonable procfs */
648
    char *pid_path;
649
    size_t len;
650

651
    pid_path = g_strdup_printf("/proc/%d/cmdline", pid);
652
    g_file_get_contents(pid_path, &name, &len, NULL);
653
    g_free(pid_path);
654
#endif
655

656
    return name;
657
}
658

659

660
void *qemu_alloc_stack(size_t *sz)
661
{
662
    void *ptr;
663
    int flags;
664
#ifdef CONFIG_DEBUG_STACK_USAGE
665
    void *ptr2;
666
#endif
667
    size_t pagesz = qemu_real_host_page_size();
668
#ifdef _SC_THREAD_STACK_MIN
669
    /* avoid stacks smaller than _SC_THREAD_STACK_MIN */
670
    long min_stack_sz = sysconf(_SC_THREAD_STACK_MIN);
671
    *sz = MAX(MAX(min_stack_sz, 0), *sz);
672
#endif
673
    /* adjust stack size to a multiple of the page size */
674
    *sz = ROUND_UP(*sz, pagesz);
675
    /* allocate one extra page for the guard page */
676
    *sz += pagesz;
677

678
    flags = MAP_PRIVATE | MAP_ANONYMOUS;
679
#if defined(MAP_STACK) && defined(__OpenBSD__)
680
    /* Only enable MAP_STACK on OpenBSD. Other OS's such as
681
     * Linux/FreeBSD/NetBSD have a flag with the same name
682
     * but have differing functionality. OpenBSD will SEGV
683
     * if it spots execution with a stack pointer pointing
684
     * at memory that was not allocated with MAP_STACK.
685
     */
686
    flags |= MAP_STACK;
687
#endif
688

689
    ptr = mmap(NULL, *sz, PROT_READ | PROT_WRITE, flags, -1, 0);
690
    if (ptr == MAP_FAILED) {
691
        perror("failed to allocate memory for stack");
692
        abort();
693
    }
694

695
    /* Stack grows down -- guard page at the bottom. */
696
    if (mprotect(ptr, pagesz, PROT_NONE) != 0) {
697
        perror("failed to set up stack guard page");
698
        abort();
699
    }
700

701
#ifdef CONFIG_DEBUG_STACK_USAGE
702
    for (ptr2 = ptr + pagesz; ptr2 < ptr + *sz; ptr2 += sizeof(uint32_t)) {
703
        *(uint32_t *)ptr2 = 0xdeadbeaf;
704
    }
705
#endif
706

707
    return ptr;
708
}
709

710
#ifdef CONFIG_DEBUG_STACK_USAGE
711
static __thread unsigned int max_stack_usage;
712
#endif
713

714
void qemu_free_stack(void *stack, size_t sz)
715
{
716
#ifdef CONFIG_DEBUG_STACK_USAGE
717
    unsigned int usage;
718
    void *ptr;
719

720
    for (ptr = stack + qemu_real_host_page_size(); ptr < stack + sz;
721
         ptr += sizeof(uint32_t)) {
722
        if (*(uint32_t *)ptr != 0xdeadbeaf) {
723
            break;
724
        }
725
    }
726
    usage = sz - (uintptr_t) (ptr - stack);
727
    if (usage > max_stack_usage) {
728
        error_report("thread %d max stack usage increased from %u to %u",
729
                     qemu_get_thread_id(), max_stack_usage, usage);
730
        max_stack_usage = usage;
731
    }
732
#endif
733

734
    munmap(stack, sz);
735
}
736

737
/*
738
 * Disable CFI checks.
739
 * We are going to call a signal handler directly. Such handler may or may not
740
 * have been defined in our binary, so there's no guarantee that the pointer
741
 * used to set the handler is a cfi-valid pointer. Since the handlers are
742
 * stored in kernel memory, changing the handler to an attacker-defined
743
 * function requires being able to call a sigaction() syscall,
744
 * which is not as easy as overwriting a pointer in memory.
745
 */
746
QEMU_DISABLE_CFI
747
void sigaction_invoke(struct sigaction *action,
748
                      struct qemu_signalfd_siginfo *info)
749
{
750
    siginfo_t si = {};
751
    si.si_signo = info->ssi_signo;
752
    si.si_errno = info->ssi_errno;
753
    si.si_code = info->ssi_code;
754

755
    /* Convert the minimal set of fields defined by POSIX.
756
     * Positive si_code values are reserved for kernel-generated
757
     * signals, where the valid siginfo fields are determined by
758
     * the signal number.  But according to POSIX, it is unspecified
759
     * whether SI_USER and SI_QUEUE have values less than or equal to
760
     * zero.
761
     */
762
    if (info->ssi_code == SI_USER || info->ssi_code == SI_QUEUE ||
763
        info->ssi_code <= 0) {
764
        /* SIGTERM, etc.  */
765
        si.si_pid = info->ssi_pid;
766
        si.si_uid = info->ssi_uid;
767
    } else if (info->ssi_signo == SIGILL || info->ssi_signo == SIGFPE ||
768
               info->ssi_signo == SIGSEGV || info->ssi_signo == SIGBUS) {
769
        si.si_addr = (void *)(uintptr_t)info->ssi_addr;
770
    } else if (info->ssi_signo == SIGCHLD) {
771
        si.si_pid = info->ssi_pid;
772
        si.si_status = info->ssi_status;
773
        si.si_uid = info->ssi_uid;
774
    }
775
    action->sa_sigaction(info->ssi_signo, &si, NULL);
776
}
777

778
size_t qemu_get_host_physmem(void)
779
{
780
#ifdef _SC_PHYS_PAGES
781
    long pages = sysconf(_SC_PHYS_PAGES);
782
    if (pages > 0) {
783
        if (pages > SIZE_MAX / qemu_real_host_page_size()) {
784
            return SIZE_MAX;
785
        } else {
786
            return pages * qemu_real_host_page_size();
787
        }
788
    }
789
#endif
790
    return 0;
791
}
792

793
int qemu_msync(void *addr, size_t length, int fd)
794
{
795
    size_t align_mask = ~(qemu_real_host_page_size() - 1);
796

797
    /**
798
     * There are no strict reqs as per the length of mapping
799
     * to be synced. Still the length needs to follow the address
800
     * alignment changes. Additionally - round the size to the multiple
801
     * of PAGE_SIZE
802
     */
803
    length += ((uintptr_t)addr & (qemu_real_host_page_size() - 1));
804
    length = (length + ~align_mask) & align_mask;
805

806
    addr = (void *)((uintptr_t)addr & align_mask);
807

808
    return msync(addr, length, MS_SYNC);
809
}
810

811
static bool qemu_close_all_open_fd_proc(const int *skip, unsigned int nskip)
812
{
813
    struct dirent *de;
814
    int fd, dfd;
815
    DIR *dir;
816
    unsigned int skip_start = 0, skip_end = nskip;
817

818
    dir = opendir("/proc/self/fd");
819
    if (!dir) {
820
        /* If /proc is not mounted, there is nothing that can be done. */
821
        return false;
822
    }
823
    /* Avoid closing the directory. */
824
    dfd = dirfd(dir);
825

826
    for (de = readdir(dir); de; de = readdir(dir)) {
827
        bool close_fd = true;
828

829
        if (de->d_name[0] == '.') {
830
            continue;
831
        }
832
        fd = atoi(de->d_name);
833
        if (fd == dfd) {
834
            continue;
835
        }
836

837
        for (unsigned int i = skip_start; i < skip_end; i++) {
838
            if (fd < skip[i]) {
839
                /* We are below the next skipped fd, break */
840
                break;
841
            } else if (fd == skip[i]) {
842
                close_fd = false;
843
                /* Restrict the range as we found fds matching start/end */
844
                if (i == skip_start) {
845
                    skip_start++;
846
                } else if (i == skip_end) {
847
                    skip_end--;
848
                }
849
                break;
850
            }
851
        }
852

853
        if (close_fd) {
854
            close(fd);
855
        }
856
    }
857
    closedir(dir);
858

859
    return true;
860
}
861

862
static bool qemu_close_all_open_fd_close_range(const int *skip,
863
                                               unsigned int nskip,
864
                                               int open_max)
865
{
866
#ifdef CONFIG_CLOSE_RANGE
867
    int max_fd = open_max - 1;
868
    int first = 0, last;
869
    unsigned int cur_skip = 0;
870
    int ret;
871

872
    do {
873
        /* Find the start boundary of the range to close */
874
        while (cur_skip < nskip && first == skip[cur_skip]) {
875
            cur_skip++;
876
            first++;
877
        }
878

879
        /* Find the upper boundary of the range to close */
880
        last = max_fd;
881
        if (cur_skip < nskip) {
882
            last = skip[cur_skip] - 1;
883
            last = MIN(last, max_fd);
884
        }
885

886
        /* With the adjustments to the range, we might be done. */
887
        if (first > last) {
888
            break;
889
        }
890

891
        ret = close_range(first, last, 0);
892
        if (ret < 0) {
893
            return false;
894
        }
895

896
        first = last + 1;
897
    } while (last < max_fd);
898

899
    return true;
900
#else
901
    return false;
902
#endif
903
}
904

905
static void qemu_close_all_open_fd_fallback(const int *skip, unsigned int nskip,
906
                                            int open_max)
907
{
908
    unsigned int cur_skip = 0;
909

910
    /* Fallback */
911
    for (int i = 0; i < open_max; i++) {
912
        if (cur_skip < nskip && i == skip[cur_skip]) {
913
            cur_skip++;
914
            continue;
915
        }
916
        close(i);
917
    }
918
}
919

920
/*
921
 * Close all open file descriptors.
922
 */
923
void qemu_close_all_open_fd(const int *skip, unsigned int nskip)
924
{
925
    int open_max = sysconf(_SC_OPEN_MAX);
926

927
    assert(skip != NULL || nskip == 0);
928

929
    if (!qemu_close_all_open_fd_close_range(skip, nskip, open_max) &&
930
        !qemu_close_all_open_fd_proc(skip, nskip)) {
931
        qemu_close_all_open_fd_fallback(skip, nskip, open_max);
932
    }
933
}
934

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.