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'. 22static 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). 31static 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 40bool 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 78bool 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 114bool 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 146RUN_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