aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-08-27 16:51:30 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-08-27 16:51:30 +0000
commit8a5fab6333eee874e0675a89937d31b9ae3a7345 (patch)
tree67e8f21b25ccc1ab4d73f3dc5136854e6a432f91
parent512499c8cab30684785c6b116abbb7c868ac5be9 (diff)
downloadbusybox-w32-8a5fab6333eee874e0675a89937d31b9ae3a7345.tar.gz
busybox-w32-8a5fab6333eee874e0675a89937d31b9ae3a7345.tar.bz2
busybox-w32-8a5fab6333eee874e0675a89937d31b9ae3a7345.zip
cp: detect and prevent infinite recursion
-rw-r--r--libbb/copy_file.c52
1 files changed, 35 insertions, 17 deletions
diff --git a/libbb/copy_file.c b/libbb/copy_file.c
index a86e497f0..b70d7b5e0 100644
--- a/libbb/copy_file.c
+++ b/libbb/copy_file.c
@@ -114,6 +114,7 @@ int copy_file(const char *source, const char *dest, int flags)
114 114
115 if (S_ISDIR(source_stat.st_mode)) { 115 if (S_ISDIR(source_stat.st_mode)) {
116 DIR *dp; 116 DIR *dp;
117 const char *existing_name;
117 struct dirent *d; 118 struct dirent *d;
118 mode_t saved_umask = 0; 119 mode_t saved_umask = 0;
119 120
@@ -122,6 +123,15 @@ int copy_file(const char *source, const char *dest, int flags)
122 return -1; 123 return -1;
123 } 124 }
124 125
126 /* Did we ever create source ourself before? */
127 existing_name = is_in_ino_dev_hashtable(&source_stat);
128 if (existing_name) {
129 /* We did! it's a recursion! man the lifeboats... */
130 bb_error_msg("recursion detected, omitting directory '%s'",
131 existing_name);
132 return -1;
133 }
134
125 /* Create DEST */ 135 /* Create DEST */
126 if (dest_exists) { 136 if (dest_exists) {
127 if (!S_ISDIR(dest_stat.st_mode)) { 137 if (!S_ISDIR(dest_stat.st_mode)) {
@@ -143,7 +153,15 @@ int copy_file(const char *source, const char *dest, int flags)
143 return -1; 153 return -1;
144 } 154 }
145 umask(saved_umask); 155 umask(saved_umask);
156 /* need stat info for add_to_ino_dev_hashtable */
157 if (lstat(dest, &dest_stat) < 0) {
158 bb_perror_msg("cannot stat '%s'", dest);
159 return -1;
160 }
146 } 161 }
162 /* remember (dev,inode) of each created dir.
163 * NULL: name is not remembered */
164 add_to_ino_dev_hashtable(&dest_stat, NULL);
147 165
148 /* Recursively copy files in SOURCE */ 166 /* Recursively copy files in SOURCE */
149 dp = opendir(source); 167 dp = opendir(source);
@@ -169,8 +187,8 @@ int copy_file(const char *source, const char *dest, int flags)
169 if (!dest_exists 187 if (!dest_exists
170 && chmod(dest, source_stat.st_mode & ~saved_umask) < 0 188 && chmod(dest, source_stat.st_mode & ~saved_umask) < 0
171 ) { 189 ) {
172 bb_perror_msg("cannot change permissions of '%s'", dest); 190 bb_perror_msg("cannot preserve %s of '%s'", "permissions", dest);
173 retval = -1; 191 /* retval = -1; - WRONG! copy *WAS* made */
174 } 192 }
175 goto preserve_mode_ugid_time; 193 goto preserve_mode_ugid_time;
176 } 194 }
@@ -197,7 +215,7 @@ int copy_file(const char *source, const char *dest, int flags)
197 } 215 }
198 216
199 if (S_ISREG(source_stat.st_mode) 217 if (S_ISREG(source_stat.st_mode)
200 /* Huh? DEREF uses stat, which never returns links! */ 218 /* DEREF uses stat, which never returns S_ISLNK() == true. */
201 /* || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) */ 219 /* || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) */
202 ) { 220 ) {
203 int src_fd; 221 int src_fd;
@@ -269,14 +287,13 @@ int copy_file(const char *source, const char *dest, int flags)
269#endif 287#endif
270 if (bb_copyfd_eof(src_fd, dst_fd) == -1) 288 if (bb_copyfd_eof(src_fd, dst_fd) == -1)
271 retval = -1; 289 retval = -1;
290 /* Ok, writing side I can understand... */
272 if (close(dst_fd) < 0) { 291 if (close(dst_fd) < 0) {
273 bb_perror_msg("cannot close '%s'", dest); 292 bb_perror_msg("cannot close '%s'", dest);
274 retval = -1; 293 retval = -1;
275 } 294 }
276 if (close(src_fd) < 0) { 295 /* ...but read size is already checked by bb_copyfd_eof */
277 bb_perror_msg("cannot close '%s'", source); 296 close(src_fd);
278 retval = -1;
279 }
280 goto preserve_mode_ugid_time; 297 goto preserve_mode_ugid_time;
281 } 298 }
282 299
@@ -289,18 +306,18 @@ int copy_file(const char *source, const char *dest, int flags)
289 return ovr; 306 return ovr;
290 } 307 }
291 if (S_ISLNK(source_stat.st_mode)) { 308 if (S_ISLNK(source_stat.st_mode)) {
292 char *lpath; 309 char *lpath = xmalloc_readlink_or_warn(source);
293 310 if (lpath) {
294 lpath = xmalloc_readlink_or_warn(source); 311 int r = symlink(lpath, dest);
295 if (lpath && symlink(lpath, dest) < 0) {
296 bb_perror_msg("cannot create symlink '%s'", dest);
297 free(lpath); 312 free(lpath);
298 return -1; 313 if (r < 0) {
314 bb_perror_msg("cannot create symlink '%s'", dest);
315 return -1;
316 }
317 if (flags & FILEUTILS_PRESERVE_STATUS)
318 if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0)
319 bb_perror_msg("cannot preserve %s of '%s'", "ownership", dest);
299 } 320 }
300 free(lpath);
301 if (flags & FILEUTILS_PRESERVE_STATUS)
302 if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0)
303 bb_perror_msg("cannot preserve %s of '%s'", "ownership", dest);
304 /* _Not_ jumping to preserve_mode_ugid_time: 321 /* _Not_ jumping to preserve_mode_ugid_time:
305 * symlinks don't have those */ 322 * symlinks don't have those */
306 return 0; 323 return 0;
@@ -327,6 +344,7 @@ int copy_file(const char *source, const char *dest, int flags)
327 344
328 times.actime = source_stat.st_atime; 345 times.actime = source_stat.st_atime;
329 times.modtime = source_stat.st_mtime; 346 times.modtime = source_stat.st_mtime;
347 /* BTW, utimes sets usec-precision time - just FYI */
330 if (utime(dest, &times) < 0) 348 if (utime(dest, &times) < 0)
331 bb_perror_msg("cannot preserve %s of '%s'", "times", dest); 349 bb_perror_msg("cannot preserve %s of '%s'", "times", dest);
332 if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) { 350 if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) {