static int scribe_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { int ret; scribe_data_non_det(); ret = sock->real_ops->ioctl(sock, cmd, arg); scribe_data_pop_flags(); return ret; }
static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf) { struct stat tmp; #if BITS_PER_LONG == 32 if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev)) return -EOVERFLOW; #else if (!new_valid_dev(stat->dev) || !new_valid_dev(stat->rdev)) return -EOVERFLOW; #endif memset(&tmp, 0, sizeof(tmp)); #if BITS_PER_LONG == 32 tmp.st_dev = old_encode_dev(stat->dev); #else tmp.st_dev = new_encode_dev(stat->dev); #endif tmp.st_ino = stat->ino; if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) return -EOVERFLOW; tmp.st_mode = stat->mode; tmp.st_nlink = stat->nlink; if (tmp.st_nlink != stat->nlink) return -EOVERFLOW; SET_UID(tmp.st_uid, stat->uid); SET_GID(tmp.st_gid, stat->gid); #if BITS_PER_LONG == 32 tmp.st_rdev = old_encode_dev(stat->rdev); #else tmp.st_rdev = new_encode_dev(stat->rdev); #endif #if BITS_PER_LONG == 32 if (stat->size > MAX_NON_LFS) return -EOVERFLOW; #endif tmp.st_size = stat->size; tmp.st_atime = stat->atime.tv_sec; tmp.st_mtime = stat->mtime.tv_sec; tmp.st_ctime = stat->ctime.tv_sec; #ifdef STAT_HAVE_NSEC tmp.st_atime_nsec = stat->atime.tv_nsec; tmp.st_mtime_nsec = stat->mtime.tv_nsec; tmp.st_ctime_nsec = stat->ctime.tv_nsec; #endif tmp.st_blocks = stat->blocks; tmp.st_blksize = stat->blksize; scribe_data_non_det(); return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; }
SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf) { struct path path; int error; error = user_path(pathname, &path); if (!error) { struct statfs tmp; error = vfs_statfs_native(path.dentry, &tmp); scribe_data_non_det(); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; path_put(&path); } return error; }
static int filldir(void * __buf, const char * name, int namlen, loff_t offset, u64 ino, unsigned int d_type) { struct linux_dirent __user * dirent; struct getdents_callback * buf = (struct getdents_callback *) __buf; unsigned long d_ino; int reclen = ALIGN(NAME_OFFSET(dirent) + namlen + 2, sizeof(long)); int ret; buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; d_ino = ino; if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { buf->error = -EOVERFLOW; return -EOVERFLOW; } dirent = buf->previous; if (dirent) { if (__put_user(offset, &dirent->d_off)) goto efault; } dirent = buf->current_dir; scribe_data_non_det(); ret = __put_user(d_ino, &dirent->d_ino); scribe_data_pop_flags(); if (ret) goto efault; if (__put_user(reclen, &dirent->d_reclen)) goto efault; if (copy_to_user(dirent->d_name, name, namlen)) goto efault; if (__put_user(0, dirent->d_name + namlen)) goto efault; if (__put_user(d_type, (char __user *) dirent + reclen - 1)) goto efault; buf->previous = dirent; dirent = (void __user *)dirent + reclen; buf->current_dir = dirent; buf->count -= reclen; return 0; efault: buf->error = -EFAULT; return -EFAULT; }
SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf) { struct file *file; struct statfs tmp; int error; error = -EBADF; file = fget(fd); if (!file) goto out; error = vfs_statfs_native(file->f_path.dentry, &tmp); scribe_data_non_det(); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; fput(file); out: return error; }
SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf) { struct path path; long error; if (sz != sizeof(*buf)) return -EINVAL; error = user_path(pathname, &path); if (!error) { struct statfs64 tmp; error = vfs_statfs64(path.dentry, &tmp); scribe_data_non_det(); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; path_put(&path); } return error; }
static ssize_t scribe_do_read(struct file *file, char __user *buf, ssize_t len, loff_t *ppos) { struct scribe_ps *scribe = current->scribe; int force_block = 0; ssize_t ret; if (!is_scribed(scribe)) return do_read(file, buf, len, ppos, force_block); if (is_kernel_copy()) goto out; if (!should_scribe_data(scribe)) goto out; scribe_need_syscall_ret(scribe); if (is_replaying(scribe)) { len = scribe->orig_ret; if (len <= 0) return len; force_block = 1; } if (is_deterministic(file)) goto out; scribe_data_non_det(); if (is_recording(scribe)) goto out; return scribe_emul_copy_to_user(scribe, buf, len); out: scribe->in_read_write = true; ret = do_read(file, buf, len, ppos, force_block); scribe->in_read_write = false; return ret; }
SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf) { struct file *file; struct statfs64 tmp; int error; if (sz != sizeof(*buf)) return -EINVAL; error = -EBADF; file = fget(fd); if (!file) goto out; error = vfs_statfs64(file->f_path.dentry, &tmp); scribe_data_non_det(); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; fput(file); out: return error; }
/* * For backward compatibility? Maybe this should be moved * into arch/i386 instead? */ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * statbuf) { static int warncount = 5; struct __old_kernel_stat tmp; if (warncount > 0) { warncount--; printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.\n", current->comm); } else if (warncount < 0) { /* it's laughable, but... */ warncount = 0; } memset(&tmp, 0, sizeof(struct __old_kernel_stat)); tmp.st_dev = old_encode_dev(stat->dev); tmp.st_ino = stat->ino; if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) return -EOVERFLOW; tmp.st_mode = stat->mode; tmp.st_nlink = stat->nlink; if (tmp.st_nlink != stat->nlink) return -EOVERFLOW; SET_UID(tmp.st_uid, stat->uid); SET_GID(tmp.st_gid, stat->gid); tmp.st_rdev = old_encode_dev(stat->rdev); #if BITS_PER_LONG == 32 if (stat->size > MAX_NON_LFS) return -EOVERFLOW; #endif tmp.st_size = stat->size; tmp.st_atime = stat->atime.tv_sec; tmp.st_mtime = stat->mtime.tv_sec; tmp.st_ctime = stat->ctime.tv_sec; scribe_data_non_det(); return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; }
SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf) { struct super_block *s; struct ustat tmp; struct kstatfs sbuf; int err; s = user_get_super(new_decode_dev(dev)); if (!s) return -EINVAL; err = vfs_statfs(s->s_root, &sbuf); drop_super(s); if (err) return err; memset(&tmp,0,sizeof(struct ustat)); tmp.f_tfree = sbuf.f_bfree; tmp.f_tinode = sbuf.f_ffree; scribe_data_non_det(); return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0; }
static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf) { struct stat64 tmp; memset(&tmp, 0, sizeof(struct stat64)); #ifdef CONFIG_MIPS /* mips has weird padding, so we don't get 64 bits there */ if (!new_valid_dev(stat->dev) || !new_valid_dev(stat->rdev)) return -EOVERFLOW; tmp.st_dev = new_encode_dev(stat->dev); tmp.st_rdev = new_encode_dev(stat->rdev); #else tmp.st_dev = huge_encode_dev(stat->dev); tmp.st_rdev = huge_encode_dev(stat->rdev); #endif tmp.st_ino = stat->ino; if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) return -EOVERFLOW; #ifdef STAT64_HAS_BROKEN_ST_INO tmp.__st_ino = stat->ino; #endif tmp.st_mode = stat->mode; tmp.st_nlink = stat->nlink; tmp.st_uid = stat->uid; tmp.st_gid = stat->gid; tmp.st_atime = stat->atime.tv_sec; tmp.st_atime_nsec = stat->atime.tv_nsec; tmp.st_mtime = stat->mtime.tv_sec; tmp.st_mtime_nsec = stat->mtime.tv_nsec; tmp.st_ctime = stat->ctime.tv_sec; tmp.st_ctime_nsec = stat->ctime.tv_nsec; tmp.st_size = stat->size; tmp.st_blocks = stat->blocks; tmp.st_blksize = stat->blksize; scribe_data_non_det(); return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; }
static ssize_t scribe_do_readv_writev(int type, struct file *file, const struct iovec __user * uvector, unsigned long nr_segs, loff_t *pos) { struct scribe_ps *scribe = current->scribe; struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov = iovstack; int force_block = 0; ssize_t ret, len = 0; if (!is_scribed(scribe)) return do_readv_writev(type, file, uvector, nr_segs, 0, pos, force_block); if (is_kernel_copy()) goto out; if (!should_scribe_data(scribe)) goto out; scribe_need_syscall_ret(scribe); if (is_replaying(scribe)) { len = scribe->orig_ret; if (len <= 0) { rw_copy_check_uvector(type, uvector, nr_segs, ARRAY_SIZE(iovstack), iovstack, &iov); ret = len; goto free; } force_block = 1; } if (type == READ) { if (is_deterministic(file)) goto out; scribe_data_non_det(); if (is_recording(scribe)) goto out; rw_copy_check_uvector(type, uvector, nr_segs, ARRAY_SIZE(iovstack), iovstack, &iov); ret = __do_loop_readv_writev(file, iov, nr_segs, len, pos, io_scribe_emul_copy_to_user); goto free; } out: scribe->in_read_write = true; ret = do_readv_writev(type, file, uvector, nr_segs, len, pos, force_block); scribe->in_read_write = false; free: if (iov != iovstack) kfree(iov); return ret; }