Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F160372017
D55833.id173758.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D55833.id173758.diff
View Options
diff --git a/sys/compat/lindebugfs/lindebugfs.c b/sys/compat/lindebugfs/lindebugfs.c
--- a/sys/compat/lindebugfs/lindebugfs.c
+++ b/sys/compat/lindebugfs/lindebugfs.c
@@ -117,9 +117,14 @@
struct dentry_meta *d;
struct linux_file lf = {};
struct vnode vn;
- char *buf;
- int rc;
- off_t off = 0;
+ struct iovec *iov;
+ size_t cnt, orig_resid;
+ ssize_t rc;
+ off_t off;
+
+ /* Linux file operations assume a pointer to a user buffer. */
+ if (uio->uio_segflg != UIO_USERSPACE)
+ return (EOPNOTSUPP);
if ((rc = linux_set_current_flags(curthread, M_NOWAIT)))
return (rc);
@@ -130,42 +135,64 @@
rc = d->dm_fops->open(&vn, &lf);
if (rc < 0) {
#ifdef INVARIANTS
- printf("%s:%d open failed with %d\n", __func__, __LINE__, rc);
+ printf("%s:%d open failed with %zd\n", __func__, __LINE__, rc);
#endif
return (-rc);
}
- rc = -ENODEV;
- switch (uio->uio_rw) {
- case UIO_READ:
- if (d->dm_fops->read != NULL) {
- rc = -ENOMEM;
- buf = malloc(sb->s_size, M_DFSINT, M_ZERO | M_NOWAIT);
- if (buf != NULL) {
- rc = d->dm_fops->read(&lf, buf, sb->s_size,
- &off);
- if (rc > 0)
- sbuf_bcpy(sb, buf, strlen(buf));
+ off = uio->uio_offset;
+ orig_resid = uio->uio_resid;
+ while (uio->uio_resid > 0) {
+ KASSERT(uio->uio_iovcnt > 0,
+ ("%s: uio %p iovcnt underflow", __func__, uio));
- free(buf, M_DFSINT);
- }
+ iov = uio->uio_iov;
+ cnt = iov->iov_len;
+ if (cnt == 0) {
+ uio->uio_iov++;
+ uio->uio_iovcnt--;
+ continue;
}
- break;
- case UIO_WRITE:
- if (d->dm_fops->write != NULL) {
- sbuf_finish(sb);
- rc = d->dm_fops->write(&lf, sbuf_data(sb), sbuf_len(sb),
- &off);
+ if (cnt > uio->uio_resid)
+ cnt = uio->uio_resid;
+
+ switch (uio->uio_rw) {
+ case UIO_READ:
+ if (d->dm_fops->read != NULL)
+ rc = d->dm_fops->read(&lf, iov->iov_base, cnt,
+ &off);
+ else
+ rc = -ENODEV;
+ break;
+ case UIO_WRITE:
+ if (d->dm_fops->write != NULL)
+ rc = d->dm_fops->write(&lf, iov->iov_base, cnt,
+ &off);
+ else
+ rc = -ENODEV;
+ break;
}
- break;
+
+ if (rc <= 0)
+ break;
+
+ iov->iov_base = (char *)iov->iov_base + rc;
+ iov->iov_len -= rc;
+ uio->uio_resid -= rc;
+ uio->uio_offset = off;
}
if (d->dm_fops->release)
d->dm_fops->release(&vn, &lf);
+ /* Return success for short operations. */
+ if (orig_resid != uio->uio_resid)
+ rc = 0;
+
if (rc < 0) {
#ifdef INVARIANTS
- printf("%s:%d read/write failed with %d\n", __func__, __LINE__, rc);
+ printf("%s:%d read/write failed with %zd\n", __func__, __LINE__,
+ rc);
#endif
return (-rc);
}
@@ -207,7 +234,7 @@
flags = fops->write ? PFS_RDWR : PFS_RD;
pfs_create_file(pnode, &dnode->d_pfs_node, name, debugfs_fill,
- debugfs_attr, NULL, debugfs_destroy, flags | PFS_NOWAIT);
+ debugfs_attr, NULL, debugfs_destroy, flags | PFS_RAW | PFS_NOWAIT);
if (dnode->d_pfs_node == NULL) {
free(dm, M_DFSINT);
return (NULL);
@@ -671,7 +698,7 @@
}
static ssize_t
-fops_str_write(struct file *filp, const char *buf, size_t write_size,
+fops_str_write(struct file *filp, const char __user *buf, size_t write_size,
loff_t *ppos)
{
char *old, *new;
diff --git a/sys/compat/linuxkpi/common/include/linux/fs.h b/sys/compat/linuxkpi/common/include/linux/fs.h
--- a/sys/compat/linuxkpi/common/include/linux/fs.h
+++ b/sys/compat/linuxkpi/common/include/linux/fs.h
@@ -364,8 +364,9 @@
simple_read_from_buffer(void __user *dest, size_t read_size, loff_t *ppos,
void *orig, size_t buf_size)
{
- void *p, *read_pos = ((char *) orig) + *ppos;
+ void *read_pos = ((char *) orig) + *ppos;
size_t buf_remain = buf_size - *ppos;
+ ssize_t num_read;
if (buf_remain < 0 || buf_remain > buf_size)
return -EINVAL;
@@ -373,18 +374,13 @@
if (read_size > buf_remain)
read_size = buf_remain;
- /*
- * XXX At time of commit only debugfs consumers could be
- * identified. If others will use this function we may
- * have to revise this: normally we would call copy_to_user()
- * here but lindebugfs will return the result and the
- * copyout is done elsewhere for us.
- */
- p = memcpy(dest, read_pos, read_size);
- if (p != NULL)
- *ppos += read_size;
+ /* copy_to_user returns number of bytes NOT read */
+ num_read = read_size - copy_to_user(dest, read_pos, read_size);
+ if (num_read == 0)
+ return -EFAULT;
+ *ppos += num_read;
- return (read_size);
+ return (num_read);
}
MALLOC_DECLARE(M_LSATTR);
@@ -415,11 +411,13 @@
int simple_attr_release(struct inode *inode, struct file *filp);
-ssize_t simple_attr_read(struct file *filp, char *buf, size_t read_size, loff_t *ppos);
+ssize_t simple_attr_read(struct file *filp, char __user *buf, size_t read_size,
+ loff_t *ppos);
-ssize_t simple_attr_write(struct file *filp, const char *buf, size_t write_size, loff_t *ppos);
+ssize_t simple_attr_write(struct file *filp, const char __user *buf,
+ size_t write_size, loff_t *ppos);
-ssize_t simple_attr_write_signed(struct file *filp, const char *buf,
+ssize_t simple_attr_write_signed(struct file *filp, const char __user *buf,
size_t write_size, loff_t *ppos);
#endif /* _LINUXKPI_LINUX_FS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/seq_file.h b/sys/compat/linuxkpi/common/include/linux/seq_file.h
--- a/sys/compat/linuxkpi/common/include/linux/seq_file.h
+++ b/sys/compat/linuxkpi/common/include/linux/seq_file.h
@@ -85,7 +85,7 @@
int (*show) (struct seq_file *m, void *v);
};
-ssize_t seq_read(struct linux_file *, char *, size_t, off_t *);
+ssize_t seq_read(struct linux_file *, char __user *, size_t, off_t *);
int seq_write(struct seq_file *seq, const void *data, size_t len);
void seq_putc(struct seq_file *m, char c);
void seq_puts(struct seq_file *m, const char *str);
diff --git a/sys/compat/linuxkpi/common/src/linux_seq_file.c b/sys/compat/linuxkpi/common/src/linux_seq_file.c
--- a/sys/compat/linuxkpi/common/src/linux_seq_file.c
+++ b/sys/compat/linuxkpi/common/src/linux_seq_file.c
@@ -40,7 +40,7 @@
MALLOC_DEFINE(M_LSEQ, "seq_file", "seq_file");
ssize_t
-seq_read(struct linux_file *f, char *ubuf, size_t size, off_t *ppos)
+seq_read(struct linux_file *f, char __user *ubuf, size_t size, off_t *ppos)
{
struct seq_file *m;
struct sbuf *sbuf;
diff --git a/sys/compat/linuxkpi/common/src/linux_simple_attr.c b/sys/compat/linuxkpi/common/src/linux_simple_attr.c
--- a/sys/compat/linuxkpi/common/src/linux_simple_attr.c
+++ b/sys/compat/linuxkpi/common/src/linux_simple_attr.c
@@ -99,7 +99,8 @@
* On failure, negative signed ERRNO
*/
ssize_t
-simple_attr_read(struct file *filp, char *buf, size_t read_size, loff_t *ppos)
+simple_attr_read(struct file *filp, char __user *buf, size_t read_size,
+ loff_t *ppos)
{
struct simple_attr *sattr;
uint64_t data;
@@ -146,29 +147,38 @@
* On failure, negative signed ERRNO
*/
static ssize_t
-simple_attr_write_common(struct file *filp, const char *buf, size_t write_size,
- loff_t *ppos, bool is_signed)
+simple_attr_write_common(struct file *filp, const char __user *ubuf,
+ size_t write_size, loff_t *ppos, bool is_signed)
{
struct simple_attr *sattr;
unsigned long long data;
- size_t bufsize;
+ char *buf;
ssize_t ret;
sattr = filp->private_data;
- bufsize = strlen(buf) + 1;
if (sattr->set == NULL)
return (-EFAULT);
- if (*ppos >= bufsize || write_size < 1)
+ if (*ppos != 0 || write_size < 1)
return (-EINVAL);
+ buf = malloc(write_size, M_LSATTR, M_WAITOK);
+ if (copy_from_user(buf, ubuf, write_size) != 0) {
+ free(buf, M_LSATTR);
+ return (-EFAULT);
+ }
+ if (strnlen(buf, write_size) == write_size) {
+ free(buf, M_LSATTR);
+ return (-EINVAL);
+ }
+
mutex_lock(&sattr->mutex);
if (is_signed)
- ret = kstrtoll(buf + *ppos, 0, &data);
+ ret = kstrtoll(buf, 0, &data);
else
- ret = kstrtoull(buf + *ppos, 0, &data);
+ ret = kstrtoull(buf, 0, &data);
if (ret)
goto unlock;
@@ -176,23 +186,24 @@
if (ret)
goto unlock;
- ret = bufsize - *ppos;
+ ret = write_size;
unlock:
mutex_unlock(&sattr->mutex);
+ free(buf, M_LSATTR);
return (ret);
}
ssize_t
-simple_attr_write(struct file *filp, const char *buf, size_t write_size,
+simple_attr_write(struct file *filp, const char __user *buf, size_t write_size,
loff_t *ppos)
{
return (simple_attr_write_common(filp, buf, write_size, ppos, false));
}
ssize_t
-simple_attr_write_signed(struct file *filp, const char *buf, size_t write_size,
- loff_t *ppos)
+simple_attr_write_signed(struct file *filp, const char __user *buf,
+ size_t write_size, loff_t *ppos)
{
return (simple_attr_write_common(filp, buf, write_size, ppos, true));
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Jun 24, 8:13 PM (10 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34292249
Default Alt Text
D55833.id173758.diff (8 KB)
Attached To
Mode
D55833: lindebugfs: Pass user buffer pointers to the read/write file operations
Attached
Detach File
Event Timeline
Log In to Comment