Re: [PATCH] drivers/char/mem.c: fix null and zero dev lseek

From: Greg KH

Date: Fri Mar 20 2026 - 02:06:59 EST


On Fri, Mar 20, 2026 at 01:17:22PM +0900, David Timber wrote:
> lseek() on /dev/null and /dev/zero always returns 0. This is
> problematic for userland programs that detect holes and advancing
> the offset by the delta (SEEK_HOLE - SEEK_DATA), which will always be
> calculated as zero.

But it's always worked this way, what changed to require this to now
change?

What userspace tools are you going to break by doing this?

> Link: https://github.com/util-linux/util-linux/pull/4132
>
> Signed-off-by: David Timber <dxdt@xxxxxxxxxxxx>
> ---
> drivers/char/mem.c | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
> diff --git a/drivers/char/mem.c b/drivers/char/mem.c
> index cca4529431f8..e2bde4ad5677 100644
> --- a/drivers/char/mem.c
> +++ b/drivers/char/mem.c
> @@ -573,9 +573,21 @@ static ssize_t write_full(struct file *file, const char __user *buf,
> * Special lseek() function for /dev/null and /dev/zero. Most notably, you
> * can fopen() both devices with "a" now. This was previously impossible.
> * -- SRB.
> + *
> + * For SEEK_DATA and SEEK_HOLE, return an error. Otherwise, userland conforming
> + * to the POSIX spec could end up in an infinite loop.

Where does POSIX require this to happen for these device nodes?


> */
> static loff_t null_lseek(struct file *file, loff_t offset, int orig)
> {
> + switch (orig) {
> + case SEEK_CUR:
> + case SEEK_SET:
> + case SEEK_END:
> + break;
> + default:
> + return -EINVAL;

You just changed how userspace reacts to this, are you SURE that is
going to be ok? And if you really want to do this, shouldn't you
explicitly list what options you are going to return an error for, not
the other way around in this switch statement?

thanks,

greg k-h