Bug 17830

Summary: dprintf fails when file descriptor is connected to /dev/kmsg
Product: glibc Reporter: Mike Crowe <mac>
Component: stdioAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED INVALID    
Severity: normal CC: bugdal
Priority: P2 Flags: fweimer: security-
Version: 2.19   
Target Milestone: ---   
Host: Target:
Build: Last reconfirmed:

Description Mike Crowe 2015-01-12 12:33:16 UTC
If the file descriptor passed to dprintf is connected to /dev/kmsg on a modern Linux kernel then dprintf fails (apparently because /dev/kmsg does not support seeking.)

Steps to reproduce:

1. Run a Linux kernel with new-style /dev/kmsg (I was running Debian Jessie's v3.16 kernel but others as old as v3.8 show the same symptom.)

2. Compile the following code:

 #include <stdio.h>
 int main()
 {
     int r = dprintf(1, "test\n");
     fprintf(stderr, "Result: %d %m\n", r);
     return 0;
 }

3. Run ./a.out and the result is as expected

 test
 Result: 5 Success

4. Run "./a.out >/dev/kmsg" and dprintf fails:

 Result: -1 Bad file descriptor

 and no output appears in the kernel log.

Expected result:

 dprintf should work just as well on /dev/kmsg as anything else.


Reproduced in Debian Jessie's glibc v2.19 and glibc master at 56cf2763819d2f721c98f2b8bcc04a3c673837d3.
Comment 1 Andreas Schwab 2015-01-15 11:13:40 UTC
I think this is a bug in the /dev/kmsg driver.  It should return ESPIPE instead of EBADF.
Comment 2 Andreas Schwab 2015-01-15 11:22:34 UTC
The problem appears to be that devkmsg_open returns without allocating a devkmsg_user struct if opened with O_WRONLY, which causes devkmsg_llseek to return EBADF, even though the file is properly opened.  Please report that to the kernel devs.
Comment 3 Mike Crowe 2015-01-15 15:42:36 UTC
(In reply to Andreas Schwab from comment #2)
> The problem appears to be that devkmsg_open returns without allocating a
> devkmsg_user struct if opened with O_WRONLY, which causes devkmsg_llseek to
> return EBADF, even though the file is properly opened.  Please report that
> to the kernel devs.

I think that's intentional. A write-only /dev/kmsg is intended to be lighter-weight than a readable one.

What seems to be wrong is unconditionally returning EBADF in that situation. ESPIPE would presumably be better.

Even if the device were opened for reading too and we got past that point I think dprintf would still get upset since SEEK_CUR isn't handled so devkmsg_llseek would yield EINVAL.

I think both cases need fixing. I'll try posting a kernel patch.

Thanks for your help.
Comment 4 Mike Crowe 2015-01-15 15:57:02 UTC
(In reply to Mike Crowe from comment #3)
> Even if the device were opened for reading too and we got past that point I
> think dprintf would still get upset since SEEK_CUR isn't handled so
> devkmsg_llseek would yield EINVAL.

This case can be reproduced with "./a.out 1<>/dev/kmsg" which yields:

 Result: -1 Invalid argument
Comment 5 Mike Crowe 2015-01-15 17:46:41 UTC
(In reply to Andreas Schwab from comment #2)
> Please report that to the kernel devs.

http://lkml.iu.edu/hypermail/linux/kernel/1501.1/05813.html
Comment 6 Rich Felker 2015-01-30 04:58:06 UTC
Isn't it something of a bug (performance, if nothing else) that dprintf is making useless seek attempts on the file descriptor?
Comment 7 Andreas Schwab 2015-01-30 10:38:17 UTC
Are they useless?
Comment 8 Rich Felker 2015-01-30 15:19:06 UTC
Yes. Presumably the seek is part of setting up the general-case FILE for glibc's libio stdio ops to know about, but it's completely irrelevant to a single write-only operation on a temporary FILE structure. dprintf should be operating more like the virtual FILEs used for snprintf, fmemopen, fopencookie, etc. rather than using the same ops as fopen so it doesn't pull in all this overhead to every write.