Flags as a system call API design pattern
Flags as a system call API design pattern
Posted Feb 13, 2014 8:16 UTC (Thu) by blackwood (guest, #44174)Parent article: Flags as a system call API design pattern
So nowadays this is one of the iron rules I have when adding new ioctls. We're not yet at the "actually bother to document the ioctl" stage because this is drm and we need to protect our claim of fame ;-)
Posted Feb 13, 2014 9:17 UTC (Thu)
by kugel (subscriber, #70540)
[Link] (1 responses)
Posted Feb 13, 2014 17:26 UTC (Thu)
by meuh (guest, #22042)
[Link]
http://blog.ffwll.ch/2013/11/botching-up-ioctls.html
Posted Feb 13, 2014 10:14 UTC (Thu)
by paulj (subscriber, #341)
[Link] (7 responses)
See the O_TMPFILE open fun in: https://lwn.net/Articles/558940/
Posted Feb 13, 2014 14:35 UTC (Thu)
by kugel (subscriber, #70540)
[Link] (1 responses)
Optional flags (those that you would like to be ignored if unknown or unsupport for whatever reason) should can be handled in user space, for example by retrying the syscall without the flag, without adding more measures into syscall interface.
Posted Feb 13, 2014 15:08 UTC (Thu)
by paulj (subscriber, #341)
[Link]
Generally, to be able to introduce new mandatory flags, while allowing optional flags, you need either to distinguish between mandatory flags and optional in the API in some way, or you need some other way to allow the application to feature-test at runtime (but what if it forgets to do this, and then gets run on an old kernel?).
Otherwise, you need to rely on being able to find an API useage-specific hack that happens to work, as was done for open/O_TMPFILE, by also setting some other unrelated flags that *would* together cause an error on older kernels. ;) These kind of API-specific hacks might not always be available.
Posted Feb 14, 2014 18:28 UTC (Fri)
by giraffedata (guest, #1954)
[Link] (4 responses)
I'm not sure what issue this describes, but what I do when I design an interface with extra flags for forward compatibility is I add a word of flag space and declare the first half to be for mandatory flags and the second half to be for optional flags. The recipient rejects any nonzero reserved bits in the first half and ignores any reserved bits in the second half.
The mandatory/optional flag forward compatibility issue hasn't received much attention, but it's really just a special case of a larger compatibility validation issue. Imagine a web server written by someone who knows only Firefox and tested only with Firefox. The server detects at run time that the browser is "Iceweasel." The author never heard of Iceweasel. Should the program send the Firefox-oriented data to Iceweasel and assume it is smart enough to emulate Firefox, or tell the user it doesn't know how to drive Iceweasel and avoid a possible disaster?
I know storage servers that refuse to use a SCSI disk drive of a model number not in a list with which the server is known to work. And SCSI is a standard carefully designed to make that never necessary. These designers, working on a system call processor, might refuse to recognize any unknown flag as optional.
Posted Feb 14, 2014 20:01 UTC (Fri)
by nybble41 (subscriber, #55106)
[Link] (3 responses)
While I appreciate the elegance of this approach, it does have a major flaw: since the recipient ignores anything it doesn't recognize in the second half, senders are free to put whatever random data they want there. Later, when new optional flags are defined, these applications break.
This has happened multiple times in the Linux userspace APIs, and since breaking previously-working user applications isn't allowed no matter how they abuse the APIs, you effectively can't redefine any bit you've previously ignored. If you don't require a specific value for unused bits, you won't be able to use them in any later versions. Better to just reject unrecognized bits and leave userspace to implement a fallback when the syscall fails.
> Imagine a web server written by someone who knows only Firefox and tested only with Firefox. The server detects at run time that the browser is "Iceweasel." The author never heard of Iceweasel. Should the program send the Firefox-oriented data to Iceweasel and assume it is smart enough to emulate Firefox, or tell the user it doesn't know how to drive Iceweasel and avoid a possible disaster?
To answer that you would need a protocol specification. Doing this properly requires senders and receivers to work from the same spec. If you're just inferring one possible spec from the way you've seen Firefox behave then you can make up whatever arbitrary rules you want, so long as Firefox passes them, though it's safest to bail out early rather than continue after seeing something unexpected.
Normally, of course, you'd write your web server to the HTTP specification, not a particular browser, and a browser reporting itself as "Iceweasel" is still acting within the spec and thus not giving you any reason to error out.
Posted Feb 14, 2014 20:34 UTC (Fri)
by paulj (subscriber, #341)
[Link] (1 responses)
That isn't really optional then. Rather, using the API becomes potentially a hand-shaking process ("let me try see if the kernel knows this new flag.. Hmm, no. What about this one ..." etc.). Better then to have a single call that lets the application query for the accepted flags once.
In network protocols too, specifying unused flags as "Must Be Zero" has meant that later, when people wanted to use them, they often effectively could not (sometimes it is not possible to fall-back, there may be no opportunity to probe for supported flags). MBZ bits often end up being completely useless and wasted.
Posted Feb 15, 2014 11:41 UTC (Sat)
by khim (subscriber, #9252)
[Link]
Optional flags do not exist period. There are only “flags you don't care about” and “flags you do care about”. Think FUTEX_PRIVATE. It was added as very much “optional” flag to make pthreads faster. For pthreads implementation it's “optional” flag. But for something like NaCl that same flag is very much a mandatory flag because it's use prevents information leaks. Why? “Let me try see if the kernel knows this new flag” is very simple and cheap if you do it right (take a look on GLibC—it contains dozeons of such cases).
Posted Feb 14, 2014 22:42 UTC (Fri)
by giraffedata (guest, #1954)
[Link]
Has this really happened with fields that are documented as "reserved for future use - must be zero" and someone put random garbage in there?
It isn't really true that you can't break previously-working user applications with new kernel code. There are a few cases of API abuse becoming the standard that make the news because the abuse was so widespread to be worth tolerating, but I'm sure there are thousands of instances where some application bug that was innocuous in Linux N expressed itself in Linux N+1 and everyone agreed breaking the application was appropriate.
The widespread abuses usually were somewhat deliberate - it saved someone significant effort or seemed to be legal. In contrast, failing to initialize memory is more likely to be in the rare and unforgiven category.
Flags as a system call API design pattern
Flags as a system call API design pattern
Flags as a system call API design pattern
Flags as a system call API design pattern
Flags as a system call API design pattern
Flags as a system call API design pattern
So then you have to consider how to deal with that. E.g., yet another variant of the syscall, e.g. to have 2 different arguments for each set of flags?
Flags as a system call API design pattern
Flags as a system call API design pattern
Flags as a system call API design pattern
How do you reject unrecognised flags while still allowing for optional flags?
Better then to have a single call that lets the application query for the accepted flags once.
Flags as a system call API design pattern
This has happened multiple times in the Linux userspace APIs, and since breaking previously-working user applications isn't allowed no matter how they abuse the APIs, you effectively can't redefine any bit you've previously ignored.