Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libc/tests/gen/realpath2_test.c
103830 views
1
/*
2
* Copyright (c) 2017 Jan Kokemüller
3
* All rights reserved.
4
* Copyright (c) 2025 Klara, Inc.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*/
27
28
#include <sys/param.h>
29
#include <sys/stat.h>
30
31
#include <errno.h>
32
#include <fcntl.h>
33
#include <stdio.h>
34
#include <stdlib.h>
35
#include <string.h>
36
#include <unistd.h>
37
38
#include <atf-c.h>
39
40
ATF_TC(realpath_null);
41
ATF_TC_HEAD(realpath_null, tc)
42
{
43
atf_tc_set_md_var(tc, "descr", "Test null input");
44
}
45
ATF_TC_BODY(realpath_null, tc)
46
{
47
ATF_REQUIRE_ERRNO(EINVAL, realpath(NULL, NULL) == NULL);
48
}
49
50
ATF_TC(realpath_empty);
51
ATF_TC_HEAD(realpath_empty, tc)
52
{
53
atf_tc_set_md_var(tc, "descr", "Test empty input");
54
}
55
ATF_TC_BODY(realpath_empty, tc)
56
{
57
char resb[PATH_MAX] = "";
58
59
ATF_REQUIRE_EQ(0, mkdir("foo", 0755));
60
ATF_REQUIRE_EQ(0, chdir("foo"));
61
ATF_REQUIRE_ERRNO(ENOENT, realpath("", resb) == NULL);
62
ATF_REQUIRE_STREQ("", resb);
63
}
64
65
ATF_TC(realpath_buffer_overflow);
66
ATF_TC_HEAD(realpath_buffer_overflow, tc)
67
{
68
atf_tc_set_md_var(tc, "descr",
69
"Test for out of bounds read from 'left' array "
70
"(compile realpath.c with '-fsanitize=address')");
71
}
72
73
ATF_TC_BODY(realpath_buffer_overflow, tc)
74
{
75
char path[PATH_MAX] = "";
76
char resb[PATH_MAX] = "";
77
78
memset(path, 'a', sizeof(path) - 1);
79
path[1] = '/';
80
ATF_REQUIRE(realpath(path, resb) == NULL);
81
}
82
83
ATF_TC(realpath_empty_symlink);
84
ATF_TC_HEAD(realpath_empty_symlink, tc)
85
{
86
atf_tc_set_md_var(tc, "descr",
87
"Test for correct behavior when encountering empty symlinks");
88
}
89
90
ATF_TC_BODY(realpath_empty_symlink, tc)
91
{
92
char path[PATH_MAX] = "";
93
char slnk[PATH_MAX] = "";
94
char resb[PATH_MAX] = "";
95
int fd;
96
97
(void)strlcat(slnk, "empty_symlink", sizeof(slnk));
98
99
ATF_REQUIRE(symlink("", slnk) == 0);
100
101
fd = open("aaa", O_RDONLY | O_CREAT, 0600);
102
103
ATF_REQUIRE(fd >= 0);
104
ATF_REQUIRE(close(fd) == 0);
105
106
(void)strlcat(path, "empty_symlink", sizeof(path));
107
(void)strlcat(path, "/aaa", sizeof(path));
108
109
ATF_REQUIRE_ERRNO(ENOENT, realpath(path, resb) == NULL);
110
111
ATF_REQUIRE(unlink("aaa") == 0);
112
ATF_REQUIRE(unlink(slnk) == 0);
113
}
114
115
ATF_TC(realpath_partial);
116
ATF_TC_HEAD(realpath_partial, tc)
117
{
118
atf_tc_set_md_var(tc, "descr",
119
"Test that failure leaves a partial result");
120
atf_tc_set_md_var(tc, "require.user", "unprivileged");
121
}
122
123
ATF_TC_BODY(realpath_partial, tc)
124
{
125
char resb[PATH_MAX] = "";
126
size_t len;
127
128
/* scenario 1: missing directory */
129
ATF_REQUIRE_EQ(0, mkdir("foo", 0755));
130
ATF_REQUIRE_ERRNO(ENOENT, realpath("foo/bar/baz", resb) == NULL);
131
len = strnlen(resb, sizeof(resb));
132
ATF_REQUIRE(len > 8 && len < sizeof(resb));
133
ATF_REQUIRE_STREQ("/foo/bar", resb + len - 8);
134
135
/* scenario 2: dead link 1 */
136
ATF_REQUIRE_EQ(0, symlink("nix", "foo/bar"));
137
ATF_REQUIRE_ERRNO(ENOENT, realpath("foo/bar/baz", resb) == NULL);
138
len = strnlen(resb, sizeof(resb));
139
ATF_REQUIRE(len > 8 && len < sizeof(resb));
140
ATF_REQUIRE_STREQ("/foo/nix", resb + len - 8);
141
142
/* scenario 3: missing file */
143
ATF_REQUIRE_EQ(0, unlink("foo/bar"));
144
ATF_REQUIRE_EQ(0, mkdir("foo/bar", 0755));
145
ATF_REQUIRE_ERRNO(ENOENT, realpath("foo/bar/baz", resb) == NULL);
146
len = strnlen(resb, sizeof(resb));
147
ATF_REQUIRE(len > 12 && len < sizeof(resb));
148
ATF_REQUIRE_STREQ("/foo/bar/baz", resb + len - 12);
149
150
/* scenario 4: dead link 2 */
151
ATF_REQUIRE_EQ(0, symlink("nix", "foo/bar/baz"));
152
ATF_REQUIRE_ERRNO(ENOENT, realpath("foo/bar/baz", resb) == NULL);
153
len = strnlen(resb, sizeof(resb));
154
ATF_REQUIRE(len > 12 && len < sizeof(resb));
155
ATF_REQUIRE_STREQ("/foo/bar/nix", resb + len - 12);
156
157
/* scenario 5: unreadable directory */
158
ATF_REQUIRE_EQ(0, chmod("foo", 000));
159
ATF_REQUIRE_ERRNO(EACCES, realpath("foo/bar/baz", resb) == NULL);
160
len = strnlen(resb, sizeof(resb));
161
ATF_REQUIRE(len > 4 && len < sizeof(resb));
162
ATF_REQUIRE_STREQ("/foo", resb + len - 4);
163
164
/* scenario 6: not a directory */
165
ATF_REQUIRE_EQ(0, close(creat("bar", 0644)));
166
ATF_REQUIRE_ERRNO(ENOTDIR, realpath("bar/baz", resb) == NULL);
167
len = strnlen(resb, sizeof(resb));
168
ATF_REQUIRE(len > 4 && len < sizeof(resb));
169
ATF_REQUIRE_STREQ("/bar", resb + len - 4);
170
}
171
172
ATF_TP_ADD_TCS(tp)
173
{
174
ATF_TP_ADD_TC(tp, realpath_null);
175
ATF_TP_ADD_TC(tp, realpath_empty);
176
ATF_TP_ADD_TC(tp, realpath_buffer_overflow);
177
ATF_TP_ADD_TC(tp, realpath_empty_symlink);
178
ATF_TP_ADD_TC(tp, realpath_partial);
179
180
return atf_no_error();
181
}
182
183