• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 16062852561

03 Jul 2025 10:04PM UTC coverage: 72.193% (+0.1%) from 72.096%
16062852561

push

github

bluca
pcrlock: process components outside of location window properly

So far, when we tried to match a component to eent log entries we
skipped those components if they were outside of our location window.
That however is too aggressive, since it means any components that are
already in the logs, but outside of the location window will be
considered unrecognized in the logs, and thus removed from the PCR
policy.

Change things around: always try to match up all components, regardless
if inside the location window or outside, but then make it non-fatal we
can't find a component outside of the location window.

Fixes: #36079

7 of 9 new or added lines in 1 file covered. (77.78%)

4116 existing lines in 75 files now uncovered.

301219 of 417241 relevant lines covered (72.19%)

730820.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.61
/src/shared/data-fd-util.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <sys/stat.h>
4
#include <unistd.h>
5

6
#include "copy.h"
7
#include "data-fd-util.h"
8
#include "fd-util.h"
9
#include "fs-util.h"
10
#include "memfd-util.h"
11
#include "tmpfile-util.h"
12

13
/* When the data is smaller or equal to 64K, try to place the copy in a memfd */
14
#define DATA_FD_MEMORY_LIMIT (64U * U64_KB)
15

16
/* If memfd didn't work out, then let's use a file in /tmp up to a size of 1M. If it's large than that use /var/tmp/ instead. */
17
#define DATA_FD_TMP_LIMIT (1U * U64_MB)
18

19
int copy_data_fd(int fd) {
95✔
20
        _cleanup_close_ int copy_fd = -EBADF, tmp_fd = -EBADF;
95✔
21
        const char *td;
95✔
22
        struct stat st;
95✔
23
        int r;
95✔
24

25
        /* Creates a 'data' fd from the specified source fd, containing all the same data in a read-only
26
         * fashion, but independent of it (i.e. the source fd can be closed and unmounted after this call
27
         * succeeded). Tries to be somewhat smart about where to place the data. In the best case uses a
28
         * memfd(). For larger data will use an unlinked file in /tmp/, and for even larger data one in
29
         * /var/tmp/. */
30

31
        if (fstat(fd, &st) < 0)
95✔
UNCOV
32
                return -errno;
×
33

34
        /* For now, let's only accept regular files, sockets, pipes and char devices */
35
        if (S_ISDIR(st.st_mode))
95✔
36
                return -EISDIR;
37
        if (S_ISLNK(st.st_mode))
95✔
38
                return -ELOOP;
39
        if (!S_ISREG(st.st_mode) && !S_ISSOCK(st.st_mode) && !S_ISFIFO(st.st_mode) && !S_ISCHR(st.st_mode))
95✔
40
                return -EBADFD;
41

42
        /* If we have reason to believe the data is bounded in size, then let's use memfds as backing
43
         * fd. Note that we use the reported regular file size only as a hint, given that there are plenty
44
         * special files in /proc/ and /sys/ which report a zero file size but can be read from. */
45

46
        if (!S_ISREG(st.st_mode) || (uint64_t) st.st_size < DATA_FD_MEMORY_LIMIT) {
95✔
47

48
                /* Try a memfd first */
49
                copy_fd = memfd_new_full("data-fd", MFD_ALLOW_SEALING);
95✔
50
                if (copy_fd < 0)
95✔
51
                        return copy_fd;
52

53
                r = copy_bytes(fd, copy_fd, DATA_FD_MEMORY_LIMIT, COPY_REFLINK);
95✔
54
                if (r < 0)
95✔
55
                        return r;
56

57
                off_t f = lseek(copy_fd, 0, SEEK_SET);
95✔
58
                if (f < 0)
95✔
UNCOV
59
                        return -errno;
×
60
                if (f != 0)
95✔
61
                        return -EIO;
62

63
                if (r == 0) {
95✔
64
                        /* Did it fit into the limit? If so, we are done. */
65
                        r = memfd_set_sealed(copy_fd);
94✔
66
                        if (r < 0)
94✔
67
                                return r;
68

69
                        return TAKE_FD(copy_fd);
94✔
70
                }
71
        }
72

73
        /* If we have reason to believe this will fit fine in /tmp, then use that as first fallback. */
74
        if ((!S_ISREG(st.st_mode) || (uint64_t) st.st_size < DATA_FD_TMP_LIMIT)) {
1✔
75
                tmp_fd = open_tmpfile_unlinkable(NULL /* NULL as directory means /tmp */, O_RDWR|O_CLOEXEC);
1✔
76
                if (tmp_fd < 0)
1✔
77
                        return tmp_fd;
78

79
                if (copy_fd >= 0) {
1✔
80
                        /* If we tried a memfd first and it ended up being too large, then copy this into the
81
                         * temporary file first. */
82

83
                        r = copy_bytes(copy_fd, tmp_fd, UINT64_MAX, COPY_REFLINK);
1✔
84
                        if (r < 0)
1✔
85
                                return r;
86

87
                        assert(r == 0);
1✔
88
                }
89

90
                r = copy_bytes(fd, tmp_fd, DATA_FD_TMP_LIMIT - DATA_FD_MEMORY_LIMIT, COPY_REFLINK);
1✔
91
                if (r < 0)
1✔
92
                        return r;
93
                if (r == 0)
1✔
UNCOV
94
                        goto finish;  /* Yay, it fit in */
×
95

96
                /* It didn't fit in. Let's not forget to use what we already used */
97
                off_t f = lseek(tmp_fd, 0, SEEK_SET);
1✔
98
                if (f < 0)
1✔
UNCOV
99
                        return -errno;
×
100
                if (f != 0)
1✔
101
                        return -EIO;
102

103
                close_and_replace(copy_fd, tmp_fd);
1✔
104
        }
105

106
        /* As last fallback use /var/tmp/ */
107
        r = var_tmp_dir(&td);
1✔
108
        if (r < 0)
1✔
109
                return r;
110

111
        tmp_fd = open_tmpfile_unlinkable(td, O_RDWR|O_CLOEXEC);
1✔
112
        if (tmp_fd < 0)
1✔
113
                return tmp_fd;
114

115
        if (copy_fd >= 0) {
1✔
116
                /* If we tried a memfd first, or a file in /tmp/, and it ended up being too large, than copy this
117
                 * into the temporary file first. */
118
                r = copy_bytes(copy_fd, tmp_fd, UINT64_MAX, COPY_REFLINK);
1✔
119
                if (r < 0)
1✔
120
                        return r;
121

122
                assert(r == 0);
1✔
123
        }
124

125
        /* Copy in the rest */
126
        r = copy_bytes(fd, tmp_fd, UINT64_MAX, COPY_REFLINK);
1✔
127
        if (r < 0)
1✔
128
                return r;
129

130
        assert(r == 0);
1✔
131

132
finish:
1✔
133
        /* Now convert the O_RDWR file descriptor into an O_RDONLY one (and as side effect seek to the beginning of the
134
         * file again */
135

136
        return fd_reopen(tmp_fd, O_RDONLY|O_CLOEXEC);
1✔
137
}
138

139
int memfd_clone_fd(int fd, const char *name, int mode) {
1✔
140
        _cleanup_close_ int mfd = -EBADF;
1✔
141
        struct stat st;
1✔
142
        bool ro, exec;
1✔
143
        int r;
1✔
144

145
        /* Creates a clone of a regular file in a memfd. Unlike copy_data_fd() this returns strictly a memfd
146
         * (and if it can't it will fail). Thus the resulting fd is seekable, and definitely reports as
147
         * S_ISREG. */
148

149
        assert(fd >= 0);
1✔
150
        assert(name);
1✔
151
        assert(IN_SET(mode & O_ACCMODE_STRICT, O_RDONLY, O_RDWR));
1✔
152
        assert((mode & ~(O_RDONLY|O_RDWR|O_CLOEXEC)) == 0);
1✔
153

154
        if (fstat(fd, &st) < 0)
1✔
UNCOV
155
                return -errno;
×
156

157
        ro = (mode & O_ACCMODE_STRICT) == O_RDONLY;
1✔
158
        exec = st.st_mode & 0111;
1✔
159

160
        mfd = memfd_create_wrapper(name,
1✔
161
                                   ((FLAGS_SET(mode, O_CLOEXEC) || ro) ? MFD_CLOEXEC : 0) |
1✔
162
                                   (ro ? MFD_ALLOW_SEALING : 0) |
1✔
163
                                   (exec ? MFD_EXEC : MFD_NOEXEC_SEAL));
1✔
164
        if (mfd < 0)
1✔
165
                return mfd;
166

167
        r = copy_bytes(fd, mfd, UINT64_MAX, COPY_REFLINK);
1✔
168
        if (r < 0)
1✔
169
                return r;
170

171
        if (ro) {
1✔
UNCOV
172
                r = memfd_set_sealed(mfd);
×
173
                if (r < 0)
×
174
                        return r;
175

UNCOV
176
                return fd_reopen(mfd, mode);
×
177
        }
178

179
        off_t f = lseek(mfd, 0, SEEK_SET);
1✔
180
        if (f < 0)
1✔
UNCOV
181
                return -errno;
×
182

183
        return TAKE_FD(mfd);
184
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc