Bug Summary

File:build-scan/../src/basic/xattr-util.c
Warning:line 174, column 23
The left operand of '!=' is a garbage value

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 xattr-util.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 pic -pic-level 2 -fhalf-no-semantic-interposition -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 src/basic/libbasic.a.p -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 -I . -I .. -I /usr/include/blkid -I /usr/include/libmount -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 default -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/basic/xattr-util.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <errno(*__errno_location ()).h>
4#include <fcntl.h>
5#include <stdint.h>
6#include <stdlib.h>
7#include <string.h>
8#include <sys/time.h>
9#include <sys/xattr.h>
10
11#include "alloc-util.h"
12#include "fd-util.h"
13#include "macro.h"
14#include "missing.h"
15#include "sparse-endian.h"
16#include "stdio-util.h"
17#include "string-util.h"
18#include "time-util.h"
19#include "xattr-util.h"
20
21int getxattr_malloc(const char *path, const char *name, char **value, bool_Bool allow_symlink) {
22 char *v;
23 size_t l;
24 ssize_t n;
25
26 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/basic/xattr-util.c", 26
, __PRETTY_FUNCTION__); } while (0)
;
27 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/basic/xattr-util.c", 27
, __PRETTY_FUNCTION__); } while (0)
;
28 assert(value)do { if ((__builtin_expect(!!(!(value)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("value"), "../src/basic/xattr-util.c", 28
, __PRETTY_FUNCTION__); } while (0)
;
29
30 for (l = 100; ; l = (size_t) n + 1) {
31 v = new0(char, l)((char*) calloc((l), sizeof(char)));
32 if (!v)
33 return -ENOMEM12;
34
35 if (allow_symlink)
36 n = lgetxattr(path, name, v, l);
37 else
38 n = getxattr(path, name, v, l);
39
40 if (n >= 0 && (size_t) n < l) {
41 *value = v;
42 return n;
43 }
44
45 free(v);
46
47 if (n < 0 && errno(*__errno_location ()) != ERANGE34)
48 return -errno(*__errno_location ());
49
50 if (allow_symlink)
51 n = lgetxattr(path, name, NULL((void*)0), 0);
52 else
53 n = getxattr(path, name, NULL((void*)0), 0);
54 if (n < 0)
55 return -errno(*__errno_location ());
56 }
57}
58
59int fgetxattr_malloc(int fd, const char *name, char **value) {
60 char *v;
61 size_t l;
62 ssize_t n;
63
64 assert(fd >= 0)do { if ((__builtin_expect(!!(!(fd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fd >= 0"), "../src/basic/xattr-util.c"
, 64, __PRETTY_FUNCTION__); } while (0)
;
65 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/basic/xattr-util.c", 65
, __PRETTY_FUNCTION__); } while (0)
;
66 assert(value)do { if ((__builtin_expect(!!(!(value)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("value"), "../src/basic/xattr-util.c", 66
, __PRETTY_FUNCTION__); } while (0)
;
67
68 for (l = 100; ; l = (size_t) n + 1) {
69 v = new0(char, l)((char*) calloc((l), sizeof(char)));
70 if (!v)
71 return -ENOMEM12;
72
73 n = fgetxattr(fd, name, v, l);
74
75 if (n >= 0 && (size_t) n < l) {
76 *value = v;
77 return n;
78 }
79
80 free(v);
81
82 if (n < 0 && errno(*__errno_location ()) != ERANGE34)
83 return -errno(*__errno_location ());
84
85 n = fgetxattr(fd, name, NULL((void*)0), 0);
86 if (n < 0)
87 return -errno(*__errno_location ());
88 }
89}
90
91int fgetxattrat_fake(
92 int dirfd,
93 const char *filename,
94 const char *attribute,
95 void *value, size_t size,
96 int flags,
97 size_t *ret_size) {
98
99 char fn[STRLEN("/proc/self/fd/")(sizeof("""/proc/self/fd/""") - 1) + DECIMAL_STR_MAX(int)(2+(sizeof(int) <= 1 ? 3 : sizeof(int) <= 2 ? 5 : sizeof
(int) <= 4 ? 10 : sizeof(int) <= 8 ? 20 : sizeof(int[-2
*(sizeof(int) > 8)])))
+ 1];
100 _cleanup_close___attribute__((cleanup(closep))) int fd = -1;
101 ssize_t l;
102
103 /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */
104
105 if (flags & ~(AT_SYMLINK_NOFOLLOW0x100|AT_EMPTY_PATH0x1000))
9
Taking false branch
106 return -EINVAL22;
107
108 if (isempty(filename)) {
10
Taking false branch
109 if (!(flags & AT_EMPTY_PATH0x1000))
110 return -EINVAL22;
111
112 xsprintf(fn, "/proc/self/fd/%i", dirfd)do { if ((__builtin_expect(!!(!(((size_t) snprintf(fn, __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(fn), typeof(&*(fn))), sizeof(fn)/sizeof((fn)[0]), ((void
)0))), "/proc/self/fd/%i", dirfd) < (__extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(fn), typeof(&*(fn)
)), sizeof(fn)/sizeof((fn)[0]), ((void)0))))))),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("xsprintf: " "fn" "[] must be big enough"
), "../src/basic/xattr-util.c", 112, __PRETTY_FUNCTION__); } while
(0)
;
113 } else {
114 fd = openat(dirfd, filename, O_CLOEXEC02000000|O_PATH010000000|(flags & AT_SYMLINK_NOFOLLOW0x100 ? O_NOFOLLOW0400000 : 0));
11
'?' condition is false
115 if (fd < 0)
12
Assuming 'fd' is < 0
13
Taking true branch
116 return -errno(*__errno_location ());
14
Returning without writing to '*ret_size'
117
118 xsprintf(fn, "/proc/self/fd/%i", fd)do { if ((__builtin_expect(!!(!(((size_t) snprintf(fn, __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(fn), typeof(&*(fn))), sizeof(fn)/sizeof((fn)[0]), ((void
)0))), "/proc/self/fd/%i", fd) < (__extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(fn), typeof(&*(fn)
)), sizeof(fn)/sizeof((fn)[0]), ((void)0))))))),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("xsprintf: " "fn" "[] must be big enough"
), "../src/basic/xattr-util.c", 118, __PRETTY_FUNCTION__); } while
(0)
;
119 }
120
121 l = getxattr(fn, attribute, value, size);
122 if (l < 0)
123 return -errno(*__errno_location ());
124
125 *ret_size = l;
126 return 0;
127}
128
129static int parse_crtime(le64_t le, usec_t *usec) {
130 uint64_t u;
131
132 assert(usec)do { if ((__builtin_expect(!!(!(usec)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("usec"), "../src/basic/xattr-util.c", 132
, __PRETTY_FUNCTION__); } while (0)
;
133
134 u = le64toh(le);
135 if (IN_SET(u, 0, (uint64_t) -1)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){0, (uint64_t) -1})/sizeof(int)]; switch(
u) { case 0: case (uint64_t) -1: _found = 1; break; default: break
; } _found; })
)
136 return -EIO5;
137
138 *usec = (usec_t) u;
139 return 0;
140}
141
142int fd_getcrtime_at(int dirfd, const char *name, usec_t *ret, int flags) {
143 struct_statx sx;
144 usec_t a, b;
145 le64_t le;
146 size_t n;
2
'n' declared without an initial value
147 int r;
148
149 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/basic/xattr-util.c", 149
, __PRETTY_FUNCTION__); } while (0)
;
3
Assuming 'ret' is non-null
4
Taking false branch
5
Loop condition is false. Exiting loop
150
151 if (flags & ~(AT_EMPTY_PATH0x1000|AT_SYMLINK_NOFOLLOW0x100))
6
Taking false branch
152 return -EINVAL22;
153
154 /* So here's the deal: the creation/birth time (crtime/btime) of a file is a relatively newly supported concept
155 * on Linux (or more strictly speaking: a concept that only recently got supported in the API, it was
156 * implemented on various file systems on the lower level since a while, but never was accessible). However, we
157 * needed a concept like that for vaccuuming algorithms and such, hence we emulated it via a user xattr for a
158 * long time. Starting with Linux 4.11 there's statx() which exposes the timestamp to userspace for the first
159 * time, where it is available. Thius function will read it, but it tries to keep some compatibility with older
160 * systems: we try to read both the crtime/btime and the xattr, and then use whatever is older. After all the
161 * concept is useful for determining how "old" a file really is, and hence using the older of the two makes
162 * most sense. */
163
164 if (statx(dirfd, strempty(name), flags|AT_STATX_DONT_SYNC0x4000, STATX_BTIME0x00000800U, &sx) >= 0 &&
7
Assuming the condition is false
165 (sx.stx_mask & STATX_BTIME0x00000800U) &&
166 sx.stx_btime.tv_sec != 0)
167 a = (usec_t) sx.stx_btime.tv_sec * USEC_PER_SEC((usec_t) 1000000ULL) +
168 (usec_t) sx.stx_btime.tv_nsec / NSEC_PER_USEC((nsec_t) 1000ULL);
169 else
170 a = USEC_INFINITY((usec_t) -1);
171
172 r = fgetxattrat_fake(dirfd, name, "user.crtime_usec", &le, sizeof(le), flags, &n);
8
Calling 'fgetxattrat_fake'
15
Returning from 'fgetxattrat_fake'
173 if (r >= 0) {
16
Assuming 'r' is >= 0
17
Taking true branch
174 if (n != sizeof(le))
18
The left operand of '!=' is a garbage value
175 r = -EIO5;
176 else
177 r = parse_crtime(le, &b);
178 }
179 if (r < 0) {
180 if (a != USEC_INFINITY((usec_t) -1)) {
181 *ret = a;
182 return 0;
183 }
184
185 return r;
186 }
187
188 if (a != USEC_INFINITY((usec_t) -1))
189 *ret = MIN(a, b)__extension__ ({ const typeof((a)) __unique_prefix_A2 = ((a))
; const typeof((b)) __unique_prefix_B3 = ((b)); __unique_prefix_A2
< __unique_prefix_B3 ? __unique_prefix_A2 : __unique_prefix_B3
; })
;
190 else
191 *ret = b;
192
193 return 0;
194}
195
196int fd_getcrtime(int fd, usec_t *ret) {
197 return fd_getcrtime_at(fd, NULL((void*)0), ret, AT_EMPTY_PATH0x1000);
198}
199
200int path_getcrtime(const char *p, usec_t *ret) {
201 return fd_getcrtime_at(AT_FDCWD-100, p, ret, 0);
1
Calling 'fd_getcrtime_at'
202}
203
204int fd_setcrtime(int fd, usec_t usec) {
205 le64_t le;
206
207 assert(fd >= 0)do { if ((__builtin_expect(!!(!(fd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fd >= 0"), "../src/basic/xattr-util.c"
, 207, __PRETTY_FUNCTION__); } while (0)
;
208
209 if (IN_SET(usec, 0, USEC_INFINITY)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){0, ((usec_t) -1)})/sizeof(int)]; switch(
usec) { case 0: case ((usec_t) -1): _found = 1; break; default
: break; } _found; })
)
210 usec = now(CLOCK_REALTIME0);
211
212 le = htole64((uint64_t) usec);
213 if (fsetxattr(fd, "user.crtime_usec", &le, sizeof(le), 0) < 0)
214 return -errno(*__errno_location ());
215
216 return 0;
217}