diff options
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/copy_file.c | 22 |
1 files changed, 15 insertions, 7 deletions
diff --git a/libbb/copy_file.c b/libbb/copy_file.c index efb969faa..86449f27c 100644 --- a/libbb/copy_file.c +++ b/libbb/copy_file.c | |||
@@ -19,6 +19,9 @@ | |||
19 | // (or fail, if it points to dir/nonexistent location/etc). | 19 | // (or fail, if it points to dir/nonexistent location/etc). |
20 | // This is strange, but POSIX-correct. | 20 | // This is strange, but POSIX-correct. |
21 | // coreutils cp has --remove-destination to override this... | 21 | // coreutils cp has --remove-destination to override this... |
22 | // | ||
23 | // NB: we have special code which still allows for "cp file /dev/node" | ||
24 | // to work POSIX-ly (the only realistic case where it makes sense) | ||
22 | 25 | ||
23 | #define DO_POSIX_CP 0 /* 1 - POSIX behavior, 0 - safe behavior */ | 26 | #define DO_POSIX_CP 0 /* 1 - POSIX behavior, 0 - safe behavior */ |
24 | 27 | ||
@@ -243,13 +246,18 @@ int copy_file(const char *source, const char *dest, int flags) | |||
243 | if (src_fd < 0) | 246 | if (src_fd < 0) |
244 | return -1; | 247 | return -1; |
245 | 248 | ||
246 | #if DO_POSIX_CP /* POSIX way (a security problem versus symlink attacks!): */ | 249 | /* POSIX way is a security problem versus symlink attacks, |
247 | dst_fd = open(dest, (flags & FILEUTILS_INTERACTIVE) | 250 | * we do it only for dest's which are device nodes, |
248 | ? O_WRONLY|O_CREAT|O_EXCL | 251 | * and only for non-recursive, non-interactive cp. NB: it is still racy |
249 | : O_WRONLY|O_CREAT|O_TRUNC, source_stat.st_mode); | 252 | * for "cp file /home/bad_user/device_node" case |
250 | #else /* safe way: */ | 253 | * (user can rm device_node and create link to /etc/passwd) */ |
251 | dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, source_stat.st_mode); | 254 | if (DO_POSIX_CP |
252 | #endif | 255 | || (dest_exists && !(flags & (FILEUTILS_RECUR|FILEUTILS_INTERACTIVE)) |
256 | && (S_ISBLK(dest_stat.st_mode) || S_ISCHR(dest_stat.st_mode))) | ||
257 | ) { | ||
258 | dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, source_stat.st_mode); | ||
259 | } else /* safe way: */ | ||
260 | dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, source_stat.st_mode); | ||
253 | if (dst_fd == -1) { | 261 | if (dst_fd == -1) { |
254 | ovr = ask_and_unlink(dest, flags); | 262 | ovr = ask_and_unlink(dest, flags); |
255 | if (ovr <= 0) { | 263 | if (ovr <= 0) { |