1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <assert.h>
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <limits.h>
9 #include <stdbool.h>
10 #include <stdint.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/stat.h>
15 #include <unistd.h>
16
17 #include "filesystems.h"
18 #include "misc.h"
19
20 // Given a buffer of size PATH_MAX, make a 'len' byte long filename (not including null) consisting
21 // of the character 'c'.
make_name(char * buf,size_t len,char c)22 static void make_name(char* buf, size_t len, char c) {
23 memset(buf, ':', 2);
24 buf += 2;
25 memset(buf, c, len);
26 buf[len] = '\0';
27 }
28
29 // Extends 'name' with a string 'len' bytes long, of the character 'c'.
30 // Assumes 'name' is large enough to hold 'len' additional bytes (and a new null character).
extend_name(char * name,size_t len,char c)31 static void extend_name(char* name, size_t len, char c) {
32 char buf[PATH_MAX];
33 assert(len < PATH_MAX);
34 memset(buf, c, len);
35 buf[len] = '\0';
36 strcat(name, "/");
37 strcat(name, buf);
38 }
39
test_overflow_name(void)40 bool test_overflow_name(void) {
41 BEGIN_TEST;
42
43 char name_largest[PATH_MAX];
44 char name_largest_alt[PATH_MAX];
45 char name_too_large[PATH_MAX];
46 make_name(name_largest, NAME_MAX, 'a');
47 make_name(name_largest_alt, NAME_MAX, 'b');
48 make_name(name_too_large, NAME_MAX + 1, 'a');
49
50 // Try opening, closing, renaming, and unlinking the largest acceptable name
51 int fd = open(name_largest, O_RDWR | O_CREAT | O_EXCL, 0644);
52 ASSERT_GT(fd, 0, "");
53 ASSERT_EQ(close(fd), 0, "");
54 ASSERT_EQ(rename(name_largest, name_largest_alt), 0, "");
55 ASSERT_EQ(rename(name_largest_alt, name_largest), 0, "");
56
57 ASSERT_EQ(rename(name_largest, name_too_large), -1, "");
58 ASSERT_EQ(rename(name_too_large, name_largest), -1, "");
59 ASSERT_EQ(unlink(name_largest), 0, "");
60
61 // Try it with a directory too
62 ASSERT_EQ(mkdir(name_largest, 0755), 0, "");
63 ASSERT_EQ(rename(name_largest, name_largest_alt), 0, "");
64 ASSERT_EQ(rename(name_largest_alt, name_largest), 0, "");
65
66 ASSERT_EQ(rename(name_largest, name_too_large), -1, "");
67 ASSERT_EQ(rename(name_too_large, name_largest), -1, "");
68 ASSERT_EQ(unlink(name_largest), 0, "");
69
70 // Try opening an unacceptably large name
71 ASSERT_EQ(open(name_too_large, O_RDWR | O_CREAT | O_EXCL, 0644), -1, "");
72 // Try it with a directory too
73 ASSERT_EQ(mkdir(name_too_large, 0755), -1, "");
74
75 END_TEST;
76 }
77
test_overflow_path(void)78 bool test_overflow_path(void) {
79 BEGIN_TEST;
80
81 // Make the name buffer larger than PATH_MAX so we don't overflow
82 char name[2 * PATH_MAX];
83
84 int depth = 0;
85
86 // Create an initial directory
87 make_name(name, NAME_MAX, 'a');
88 ASSERT_EQ(mkdir(name, 0755), 0, "");
89 depth++;
90 // Create child directories until we hit PATH_MAX
91 while (true) {
92 extend_name(name, NAME_MAX, 'a');
93 int r = mkdir(name, 0755);
94 if (r < 0) {
95 assert(errno == ENAMETOOLONG);
96 break;
97 }
98 depth++;
99 }
100
101 // Remove all child directories
102 while (depth != 0) {
103 char* last_slash = strrchr(name, '/');
104 assert(last_slash != NULL);
105 assert(*last_slash == '/');
106 *last_slash = '\0';
107 ASSERT_EQ(unlink(name), 0, "");
108 depth--;
109 }
110
111 END_TEST;
112 }
113
test_overflow_integer(void)114 bool test_overflow_integer(void) {
115 BEGIN_TEST;
116
117 int fd = open("::file", O_CREAT | O_RDWR | O_EXCL, 0644);
118 ASSERT_GT(fd, 0, "");
119
120 // TODO(smklein): Test extremely large reads/writes when remoteio can handle them without
121 // crashing
122 /*
123 char buf[4096];
124 ASSERT_EQ(write(fd, buf, SIZE_MAX - 1), -1, "");
125 ASSERT_EQ(write(fd, buf, SIZE_MAX), -1, "");
126
127 ASSERT_EQ(read(fd, buf, SIZE_MAX - 1), -1, "");
128 ASSERT_EQ(read(fd, buf, SIZE_MAX), -1, "");
129 */
130
131 ASSERT_EQ(ftruncate(fd, INT_MIN), -1, "");
132 ASSERT_EQ(ftruncate(fd, -1), -1, "");
133 ASSERT_EQ(ftruncate(fd, SIZE_MAX - 1), -1, "");
134 ASSERT_EQ(ftruncate(fd, SIZE_MAX), -1, "");
135
136 ASSERT_EQ(lseek(fd, INT_MIN, SEEK_SET), -1, "");
137 ASSERT_EQ(lseek(fd, -1, SEEK_SET), -1, "");
138 ASSERT_EQ(lseek(fd, SIZE_MAX - 1, SEEK_SET), -1, "");
139 ASSERT_EQ(lseek(fd, SIZE_MAX, SEEK_SET), -1, "");
140 ASSERT_EQ(close(fd), 0, "");
141 ASSERT_EQ(unlink("::file"), 0, "");
142
143 END_TEST;
144 }
145
146 RUN_FOR_ALL_FILESYSTEMS(overflow_tests,
147 RUN_TEST_MEDIUM(test_overflow_name)
148 RUN_TEST_MEDIUM(test_overflow_path)
149 RUN_TEST_MEDIUM(test_overflow_integer)
150 )
151