Coverage Report

Created: 2023-09-25 06:33

/src/qubes-os/qubes-core-qrexec/libqrexec/write-stdin.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * The Qubes OS Project, http://www.qubes-os.org
3
 *
4
 * Copyright (C) 2010  Rafal Wojtczuk  <rafal@invisiblethingslab.com>
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19
 *
20
 */
21
22
#include <stdio.h>
23
#include <unistd.h>
24
#include <errno.h>
25
#include <fcntl.h>
26
#include <stdlib.h>
27
#include <libvchan.h>
28
#include "qrexec.h"
29
#include "libqrexec-utils.h"
30
31
/* 
32
There is buffered data in "buffer" for client and poll()
33
reports that "fd" is writable. Write as much as possible to fd.
34
*/
35
int flush_client_data(int fd, struct buffer *buffer)
36
421
{
37
421
    if (fd == -1)
38
0
        return 0;
39
421
    int ret;
40
421
    int len;
41
421
    for (;;) {
42
421
        len = buffer_len(buffer);
43
421
        if (!len) {
44
421
            return WRITE_STDIN_OK;
45
421
        }
46
0
        ret = write(fd, buffer_data(buffer), len);
47
0
        if (ret == -1) {
48
0
            if (errno != EAGAIN)
49
0
                return WRITE_STDIN_ERROR;
50
0
            else
51
0
                return WRITE_STDIN_BUFFERED;
52
0
        }
53
        // we previously called buffer_remove(buffer, len)
54
        // it will be wrong if we change MAX_DATA_CHUNK to something large
55
        // as pipes writes are atomic only to PIPE_MAX limit 
56
0
        buffer_remove(buffer, ret);
57
0
    }
58
59
421
}
60
61
/*
62
 * Write "len" bytes from "data" to "fd". If not all written, buffer the rest
63
 * to "buffer".
64
 */
65
int write_stdin(int fd, const char *data, int len, struct buffer *buffer)
66
1.50k
{
67
1.50k
    int ret;
68
1.50k
    int written = 0;
69
70
1.50k
    if (buffer_len(buffer)) {
71
0
        buffer_append(buffer, data, len);
72
0
        return WRITE_STDIN_BUFFERED;
73
0
    }
74
3.01k
    while (written < len) {
75
1.50k
        ret = write(fd, data + written, len - written);
76
1.50k
        if (ret == 0) {
77
0
            PERROR("write_stdin: write returns 0 ???");
78
0
            exit(1);
79
0
        }
80
1.50k
        if (ret == -1) {
81
0
            if (errno != EAGAIN)
82
0
                return WRITE_STDIN_ERROR;
83
84
0
            buffer_append(buffer, data + written,
85
0
                    len - written);
86
87
0
            return WRITE_STDIN_BUFFERED;
88
0
        }
89
1.50k
        written += ret;
90
1.50k
    }
91
1.50k
    return WRITE_STDIN_OK;
92
1.50k
}
93
94
/* 
95
 * Data feed process has exited, so we need to clear all control structures for 
96
 * the client. However, if we have buffered data for the client (which is rare btw),
97
 * fire&forget a separate process to flush them.
98
 */
99
int fork_and_flush_stdin(int fd, struct buffer *buffer)
100
0
{
101
0
    int i;
102
0
    if (!buffer_len(buffer))
103
0
        return 0;
104
0
    switch (fork()) {
105
0
        case -1:
106
0
            PERROR("fork");
107
0
            exit(1);
108
0
        case 0:
109
0
            break;
110
0
        default:
111
0
            return 1;
112
0
    }
113
0
    for (i = 0; i < MAX_FDS; i++)
114
0
        if (i != fd && i != 2)
115
0
            close(i);
116
0
    set_block(fd);
117
0
    write_all(fd, buffer_data(buffer), buffer_len(buffer));
118
0
    _exit(0);
119
0
}