Re: [PATCH 2/4] configfs: Fix writing at a non-zero offset

From: Bart Van Assche
Date: Tue Jul 27 2021 - 12:47:31 EST


On 7/27/21 12:27 AM, Bodo Stroesser wrote:
What I meant is, that changing the source code in such a way, that
writing a buffer in multiple writes works in general, could cause
trouble in case userspace uses this.

But for special syscall sequences your changes still change the result
on existing configfs files. Example:

1) userspace program opens qfull_time_out
2) userspace program writes "90", count=2 to set timeout to 90 sec
3) userspace again wants to change timeout, so it writes "55", count=2

Before the changes we end up with timeout being 55 seconds. After the
change - due to data gathering - we finally have timeout 9055 seconds.

Hi Bodo,

How about replacing patches 1 and 2 from this series with the patch below?
Do you agree that this patch is sufficient to restore the behavior from
kernel v5.13 and before?

Thanks,

Bart.

Subject: [PATCH 1/3] configfs: Restore the kernel v5.13 text attribute write behavior

Instead of writing at the offset specified by the write() system call,
always write at offset zero.

Cc: Bodo Stroesser <bostroesser@xxxxxxxxx>
Cc: Martin K. Petersen <martin.petersen@xxxxxxxxxx>
Cc: Yanko Kaneti <yaneti@xxxxxxxxxxx>
Cc: Brendan Higgins <brendanhiggins@xxxxxxxxxx>
Reported-by: Bodo Stroesser <bostroesser@xxxxxxxxx>
Signed-off-by: Bart Van Assche <bvanassche@xxxxxxx>
---
fs/configfs/file.c | 20 ++++++++------------
1 file changed, 8 insertions(+), 12 deletions(-)

diff --git a/fs/configfs/file.c b/fs/configfs/file.c
index 5a0be9985bae..8adf6250b207 100644
--- a/fs/configfs/file.c
+++ b/fs/configfs/file.c
@@ -177,12 +177,11 @@ static ssize_t configfs_bin_read_iter(struct kiocb *iocb, struct iov_iter *to)
return retval;
}

-/* Fill [buffer, buffer + pos) with data coming from @from. */
-static int fill_write_buffer(struct configfs_buffer *buffer, loff_t pos,
+/* Fill @buffer with data coming from @from. */
+static int fill_write_buffer(struct configfs_buffer *buffer,
struct iov_iter *from)
{
- loff_t to_copy;
- int copied;
+ int to_copy, copied;
u8 *to;

if (!buffer->page)
@@ -190,11 +189,8 @@ static int fill_write_buffer(struct configfs_buffer *buffer, loff_t pos,
if (!buffer->page)
return -ENOMEM;

- to_copy = SIMPLE_ATTR_SIZE - 1 - pos;
- if (to_copy <= 0)
- return 0;
- to = buffer->page + pos;
- copied = copy_from_iter(to, to_copy, from);
+ to = buffer->page;
+ copied = copy_from_iter(to, SIMPLE_ATTR_SIZE - 1, from);
buffer->needs_read_fill = 1;
/* if buf is assumed to contain a string, terminate it by \0,
* so e.g. sscanf() can scan the string easily */
@@ -227,14 +223,14 @@ static ssize_t configfs_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
struct file *file = iocb->ki_filp;
struct configfs_buffer *buffer = file->private_data;
- ssize_t len;
+ int len;

mutex_lock(&buffer->mutex);
- len = fill_write_buffer(buffer, iocb->ki_pos, from);
+ len = fill_write_buffer(buffer, from);
if (len > 0)
len = flush_write_buffer(file, buffer, len);
if (len > 0)
- iocb->ki_pos += len;
+ iocb->ki_pos = len;
mutex_unlock(&buffer->mutex);
return len;
}