filecopy: create new file unaccessible to the user until fully written
Otherwise source domain can modify (append) the file while the user already is accessing it. While incoming files should be treated as untrusted, this problem could allow file modification after the user makes some sanity checks.
This commit is contained in:
parent
b4f48c1770
commit
b0fe4d5868
@ -66,6 +66,8 @@ int copy_file(int outfd, int infd, long long size, unsigned long *crc32);
|
|||||||
const char *copy_file_status_to_str(int status);
|
const char *copy_file_status_to_str(int status);
|
||||||
void set_size_limit(unsigned long long new_bytes_limit, unsigned long long new_files_limit);
|
void set_size_limit(unsigned long long new_bytes_limit, unsigned long long new_files_limit);
|
||||||
void set_verbose(int value);
|
void set_verbose(int value);
|
||||||
|
/* register open fd to /proc/PID/fd of this process */
|
||||||
|
void set_procfs_fd(int value);
|
||||||
int write_all(int fd, const void *buf, int size);
|
int write_all(int fd, const void *buf, int size);
|
||||||
int read_all(int fd, void *buf, int size);
|
int read_all(int fd, void *buf, int size);
|
||||||
int copy_fd_all(int fdout, int fdin);
|
int copy_fd_all(int fdout, int fdin);
|
||||||
|
@ -18,9 +18,19 @@ unsigned long long files_limit = 0;
|
|||||||
unsigned long long total_bytes = 0;
|
unsigned long long total_bytes = 0;
|
||||||
unsigned long long total_files = 0;
|
unsigned long long total_files = 0;
|
||||||
int verbose = 0;
|
int verbose = 0;
|
||||||
|
int use_tmpfile = 0;
|
||||||
|
int procdir_fd = -1;
|
||||||
|
|
||||||
void send_status_and_crc(int code, const char *last_filename);
|
void send_status_and_crc(int code, const char *last_filename);
|
||||||
|
|
||||||
|
/* copy from asm-generic/fcntl.h */
|
||||||
|
#ifndef __O_TMPFILE
|
||||||
|
#define __O_TMPFILE 020000000
|
||||||
|
#endif
|
||||||
|
/* a horrid kludge trying to make sure that this will fail on old kernels */
|
||||||
|
#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
|
||||||
|
#define O_TMPFILE_MASK (__O_TMPFILE | O_DIRECTORY | O_CREAT)
|
||||||
|
|
||||||
void do_exit(int code, const char *last_filename)
|
void do_exit(int code, const char *last_filename)
|
||||||
{
|
{
|
||||||
close(0);
|
close(0);
|
||||||
@ -39,6 +49,12 @@ void set_verbose(int value)
|
|||||||
verbose = value;
|
verbose = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_procfs_fd(int value)
|
||||||
|
{
|
||||||
|
procdir_fd = value;
|
||||||
|
use_tmpfile = 1;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned long crc32_sum = 0;
|
unsigned long crc32_sum = 0;
|
||||||
int read_all_with_crc(int fd, void *buf, int size) {
|
int read_all_with_crc(int fd, void *buf, int size) {
|
||||||
int ret;
|
int ret;
|
||||||
@ -88,7 +104,15 @@ void process_one_file_reg(struct file_header *untrusted_hdr,
|
|||||||
const char *untrusted_name)
|
const char *untrusted_name)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
int fdout = open(untrusted_name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0700); /* safe because of chroot */
|
int fdout;
|
||||||
|
|
||||||
|
/* make the file inaccessible until fully written */
|
||||||
|
fdout = open(".", O_WRONLY | O_TMPFILE, 0700);
|
||||||
|
if (fdout < 0 && errno==ENOENT) {
|
||||||
|
/* if it fails, do not attempt further use - most likely kernel too old */
|
||||||
|
use_tmpfile = 0;
|
||||||
|
fdout = open(untrusted_name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0000); /* safe because of chroot */
|
||||||
|
}
|
||||||
if (fdout < 0)
|
if (fdout < 0)
|
||||||
do_exit(errno, untrusted_name);
|
do_exit(errno, untrusted_name);
|
||||||
/* sizes are signed elsewhere */
|
/* sizes are signed elsewhere */
|
||||||
@ -105,6 +129,13 @@ void process_one_file_reg(struct file_header *untrusted_hdr,
|
|||||||
else
|
else
|
||||||
do_exit(errno, untrusted_name);
|
do_exit(errno, untrusted_name);
|
||||||
}
|
}
|
||||||
|
fdatasync(fdout);
|
||||||
|
if (use_tmpfile) {
|
||||||
|
char fd_str[7];
|
||||||
|
snprintf(fd_str, sizeof(fd_str), "%d", fdout);
|
||||||
|
if (linkat(procdir_fd, fd_str, AT_FDCWD, untrusted_name, AT_SYMLINK_FOLLOW) < 0)
|
||||||
|
do_exit(errno, untrusted_name);
|
||||||
|
}
|
||||||
close(fdout);
|
close(fdout);
|
||||||
fix_times_and_perms(untrusted_hdr, untrusted_name);
|
fix_times_and_perms(untrusted_hdr, untrusted_name);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user