Skip to content

Commit ec811b2

Browse files
cypharsmb49
authored andcommitted
fscontext: do not consume log entries when returning -EMSGSIZE
BugLink: https://bugs.launchpad.net/bugs/2131259 commit 72d271a upstream. Userspace generally expects APIs that return -EMSGSIZE to allow for them to adjust their buffer size and retry the operation. However, the fscontext log would previously clear the message even in the -EMSGSIZE case. Given that it is very cheap for us to check whether the buffer is too small before we remove the message from the ring buffer, let's just do that instead. While we're at it, refactor some fscontext_read() into a separate helper to make the ring buffer logic a bit easier to read. Fixes: 007ec26 ("vfs: Implement logging through fs_context") Cc: David Howells <dhowells@redhat.com> Cc: stable@vger.kernel.org # v5.2+ Signed-off-by: Aleksa Sarai <cyphar@cyphar.com> Link: https://lore.kernel.org/20250807-fscontext-log-cleanups-v3-1-8d91d6242dc3@cyphar.com Signed-off-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Alice C. Munduruca <alice.munduruca@canonical.com> Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
1 parent 458bb1d commit ec811b2

File tree

1 file changed

+38
-32
lines changed

1 file changed

+38
-32
lines changed

fs/fsopen.c

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -18,50 +18,56 @@
1818
#include "internal.h"
1919
#include "mount.h"
2020

21+
static inline const char *fetch_message_locked(struct fc_log *log, size_t len,
22+
bool *need_free)
23+
{
24+
const char *p;
25+
int index;
26+
27+
if (unlikely(log->head == log->tail))
28+
return ERR_PTR(-ENODATA);
29+
30+
index = log->tail & (ARRAY_SIZE(log->buffer) - 1);
31+
p = log->buffer[index];
32+
if (unlikely(strlen(p) > len))
33+
return ERR_PTR(-EMSGSIZE);
34+
35+
log->buffer[index] = NULL;
36+
*need_free = log->need_free & (1 << index);
37+
log->need_free &= ~(1 << index);
38+
log->tail++;
39+
40+
return p;
41+
}
42+
2143
/*
2244
* Allow the user to read back any error, warning or informational messages.
45+
* Only one message is returned for each read(2) call.
2346
*/
2447
static ssize_t fscontext_read(struct file *file,
2548
char __user *_buf, size_t len, loff_t *pos)
2649
{
2750
struct fs_context *fc = file->private_data;
28-
struct fc_log *log = fc->log.log;
29-
unsigned int logsize = ARRAY_SIZE(log->buffer);
30-
ssize_t ret;
31-
char *p;
51+
ssize_t err;
52+
const char *p __free(kfree) = NULL, *message;
3253
bool need_free;
33-
int index, n;
54+
int n;
3455

35-
ret = mutex_lock_interruptible(&fc->uapi_mutex);
36-
if (ret < 0)
37-
return ret;
38-
39-
if (log->head == log->tail) {
40-
mutex_unlock(&fc->uapi_mutex);
41-
return -ENODATA;
42-
}
43-
44-
index = log->tail & (logsize - 1);
45-
p = log->buffer[index];
46-
need_free = log->need_free & (1 << index);
47-
log->buffer[index] = NULL;
48-
log->need_free &= ~(1 << index);
49-
log->tail++;
56+
err = mutex_lock_interruptible(&fc->uapi_mutex);
57+
if (err < 0)
58+
return err;
59+
message = fetch_message_locked(fc->log.log, len, &need_free);
5060
mutex_unlock(&fc->uapi_mutex);
61+
if (IS_ERR(message))
62+
return PTR_ERR(message);
5163

52-
ret = -EMSGSIZE;
53-
n = strlen(p);
54-
if (n > len)
55-
goto err_free;
56-
ret = -EFAULT;
57-
if (copy_to_user(_buf, p, n) != 0)
58-
goto err_free;
59-
ret = n;
60-
61-
err_free:
6264
if (need_free)
63-
kfree(p);
64-
return ret;
65+
p = message;
66+
67+
n = strlen(message);
68+
if (copy_to_user(_buf, message, n))
69+
return -EFAULT;
70+
return n;
6571
}
6672

6773
static int fscontext_release(struct inode *inode, struct file *file)

0 commit comments

Comments
 (0)