summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormillert <>2017-12-24 01:50:50 +0000
committermillert <>2017-12-24 01:50:50 +0000
commita646c7b0917026d9681b2688a1c90fe1f7d66479 (patch)
tree7dc9c7966f30dfbc2102defd6b4a89a0b591c9f7
parent2eba43d0c1c78cf2d13b896bb9a608c482a585df (diff)
downloadopenbsd-a646c7b0917026d9681b2688a1c90fe1f7d66479.tar.gz
openbsd-a646c7b0917026d9681b2688a1c90fe1f7d66479.tar.bz2
openbsd-a646c7b0917026d9681b2688a1c90fe1f7d66479.zip
Fix one possible buffer overflow and one underflow. Also some minor
cleanups. From Jan Kokemueller. OK deraadt@
-rw-r--r--src/lib/libc/stdlib/realpath.c56
1 files changed, 36 insertions, 20 deletions
diff --git a/src/lib/libc/stdlib/realpath.c b/src/lib/libc/stdlib/realpath.c
index c691252ccf..5d226d9abc 100644
--- a/src/lib/libc/stdlib/realpath.c
+++ b/src/lib/libc/stdlib/realpath.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: realpath.c,v 1.21 2016/08/28 04:08:59 guenther Exp $ */ 1/* $OpenBSD: realpath.c,v 1.22 2017/12/24 01:50:50 millert Exp $ */
2/* 2/*
3 * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru> 3 * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru>
4 * 4 *
@@ -45,12 +45,19 @@
45char * 45char *
46realpath(const char *path, char *resolved) 46realpath(const char *path, char *resolved)
47{ 47{
48 char *p, *q, *s; 48 const char *p;
49 size_t left_len, resolved_len; 49 char *q;
50 size_t left_len, resolved_len, next_token_len;
50 unsigned symlinks; 51 unsigned symlinks;
51 int serrno, slen, mem_allocated; 52 int serrno, mem_allocated;
53 ssize_t slen;
52 char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; 54 char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];
53 55
56 if (path == NULL) {
57 errno = EINVAL;
58 return (NULL);
59 }
60
54 if (path[0] == '\0') { 61 if (path[0] == '\0') {
55 errno = ENOENT; 62 errno = ENOENT;
56 return (NULL); 63 return (NULL);
@@ -85,7 +92,7 @@ realpath(const char *path, char *resolved)
85 resolved_len = strlen(resolved); 92 resolved_len = strlen(resolved);
86 left_len = strlcpy(left, path, sizeof(left)); 93 left_len = strlcpy(left, path, sizeof(left));
87 } 94 }
88 if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { 95 if (left_len >= sizeof(left)) {
89 errno = ENAMETOOLONG; 96 errno = ENAMETOOLONG;
90 goto err; 97 goto err;
91 } 98 }
@@ -99,16 +106,19 @@ realpath(const char *path, char *resolved)
99 * and its length. 106 * and its length.
100 */ 107 */
101 p = strchr(left, '/'); 108 p = strchr(left, '/');
102 s = p ? p : left + left_len; 109
103 if (s - left >= sizeof(next_token)) { 110 next_token_len = p ? (size_t) (p - left) : left_len;
104 errno = ENAMETOOLONG; 111 memcpy(next_token, left, next_token_len);
105 goto err; 112 next_token[next_token_len] = '\0';
113
114 if (p != NULL) {
115 left_len -= next_token_len + 1;
116 memmove(left, p + 1, left_len + 1);
117 } else {
118 left[0] = '\0';
119 left_len = 0;
106 } 120 }
107 memcpy(next_token, left, s - left); 121
108 next_token[s - left] = '\0';
109 left_len -= s - left;
110 if (p != NULL)
111 memmove(left, s + 1, left_len + 1);
112 if (resolved[resolved_len - 1] != '/') { 122 if (resolved[resolved_len - 1] != '/') {
113 if (resolved_len + 1 >= PATH_MAX) { 123 if (resolved_len + 1 >= PATH_MAX) {
114 errno = ENAMETOOLONG; 124 errno = ENAMETOOLONG;
@@ -136,16 +146,17 @@ realpath(const char *path, char *resolved)
136 } 146 }
137 147
138 /* 148 /*
139 * Append the next path component and lstat() it. If 149 * Append the next path component and readlink() it. If
140 * lstat() fails we still can return successfully if 150 * readlink() fails we still can return successfully if
141 * there are no more path components left. 151 * it exists but isn't a symlink, or if there are no more
152 * path components left.
142 */ 153 */
143 resolved_len = strlcat(resolved, next_token, PATH_MAX); 154 resolved_len = strlcat(resolved, next_token, PATH_MAX);
144 if (resolved_len >= PATH_MAX) { 155 if (resolved_len >= PATH_MAX) {
145 errno = ENAMETOOLONG; 156 errno = ENAMETOOLONG;
146 goto err; 157 goto err;
147 } 158 }
148 slen = readlink(resolved, symlink, sizeof(symlink) - 1); 159 slen = readlink(resolved, symlink, sizeof(symlink));
149 if (slen < 0) { 160 if (slen < 0) {
150 switch (errno) { 161 switch (errno) {
151 case EINVAL: 162 case EINVAL:
@@ -160,6 +171,12 @@ realpath(const char *path, char *resolved)
160 default: 171 default:
161 goto err; 172 goto err;
162 } 173 }
174 } else if (slen == 0) {
175 errno = EINVAL;
176 goto err;
177 } else if (slen == sizeof(symlink)) {
178 errno = ENAMETOOLONG;
179 goto err;
163 } else { 180 } else {
164 if (symlinks++ > SYMLOOP_MAX) { 181 if (symlinks++ > SYMLOOP_MAX) {
165 errno = ELOOP; 182 errno = ELOOP;
@@ -170,9 +187,8 @@ realpath(const char *path, char *resolved)
170 if (symlink[0] == '/') { 187 if (symlink[0] == '/') {
171 resolved[1] = 0; 188 resolved[1] = 0;
172 resolved_len = 1; 189 resolved_len = 1;
173 } else if (resolved_len > 1) { 190 } else {
174 /* Strip the last path component. */ 191 /* Strip the last path component. */
175 resolved[resolved_len - 1] = '\0';
176 q = strrchr(resolved, '/') + 1; 192 q = strrchr(resolved, '/') + 1;
177 *q = '\0'; 193 *q = '\0';
178 resolved_len = q - resolved; 194 resolved_len = q - resolved;