diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-09-11 10:39:13 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-09-11 10:39:13 +0000 |
commit | fa05074eeed1a6a25393d4b466c7512112f39104 (patch) | |
tree | 5032b21d6c04f915069da7b94e009c50c8674305 | |
parent | 976690afe0b376c580dd2756e6d8eafe1317a011 (diff) |
cp: make "cp file /dev/node" special case; explained in comments
function old new delta
copy_file 1487 1538 +51
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 51/0) Total: 51 bytes
text data bss dec hex filename
772502 1051 10724 784277 bf795 busybox_old
772554 1051 10724 784329 bf7c9 busybox_unstripped
-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 @@ // (or fail, if it points to dir/nonexistent location/etc). // This is strange, but POSIX-correct. // coreutils cp has --remove-destination to override this... +// +// NB: we have special code which still allows for "cp file /dev/node" +// to work POSIX-ly (the only realistic case where it makes sense) #define DO_POSIX_CP 0 /* 1 - POSIX behavior, 0 - safe behavior */ @@ -243,13 +246,18 @@ int copy_file(const char *source, const char *dest, int flags) if (src_fd < 0) return -1; -#if DO_POSIX_CP /* POSIX way (a security problem versus symlink attacks!): */ - dst_fd = open(dest, (flags & FILEUTILS_INTERACTIVE) - ? O_WRONLY|O_CREAT|O_EXCL - : O_WRONLY|O_CREAT|O_TRUNC, source_stat.st_mode); -#else /* safe way: */ - dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, source_stat.st_mode); -#endif + /* POSIX way is a security problem versus symlink attacks, + * we do it only for dest's which are device nodes, + * and only for non-recursive, non-interactive cp. NB: it is still racy + * for "cp file /home/bad_user/device_node" case + * (user can rm device_node and create link to /etc/passwd) */ + if (DO_POSIX_CP + || (dest_exists && !(flags & (FILEUTILS_RECUR|FILEUTILS_INTERACTIVE)) + && (S_ISBLK(dest_stat.st_mode) || S_ISCHR(dest_stat.st_mode))) + ) { + dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, source_stat.st_mode); + } else /* safe way: */ + dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, source_stat.st_mode); if (dst_fd == -1) { ovr = ask_and_unlink(dest, flags); if (ovr <= 0) { |