|
|
Subscribe / Log in / New account

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 step 1 is to add a flags parameter everywhere, then step 2 is to have a testcase to check that the kernel indeed rejects still unused bits with -EINVAL. Since otherwise some userspace piece _will_ put random gunk in there, rendering your shiny new flags parameter immediately useless. At least that's been my experience with driver-private command submission interfaces for gpu drivers.

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 ;-)


to post comments

Flags as a system call API design pattern

Posted Feb 13, 2014 9:17 UTC (Thu) by kugel (subscriber, #70540) [Link] (1 responses)

I agree, step 2 is equally important. This should be in some syscall cook book :)

Flags as a system call API design pattern

Posted Feb 13, 2014 17:26 UTC (Thu) by meuh (guest, #22042) [Link]

That could be article "Botching up ioctls", by Daniel Vetter:

http://blog.ffwll.ch/2013/11/botching-up-ioctls.html

Flags as a system call API design pattern

Posted Feb 13, 2014 10:14 UTC (Thu) by paulj (subscriber, #341) [Link] (7 responses)

Step 3 you need some way distinguish between mandatory flags and optional flags. 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?

See the O_TMPFILE open fun in: https://lwn.net/Articles/558940/

Flags as a system call API design pattern

Posted Feb 13, 2014 14:35 UTC (Thu) by kugel (subscriber, #70540) [Link] (1 responses)

Nah, O_TMPFILE is a showcase why step 2 is important and that it hasn't been done for open().

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.

Flags as a system call API design pattern

Posted Feb 13, 2014 15:08 UTC (Thu) by paulj (subscriber, #341) [Link]

The problem with open() and O_TMPFILE was that the kernel treated unknown flags as optional, but an application using O_TMPFILE would want it as *mandatory*. Such an application would have no way to tell whether O_TMPFILE actually was honoured, because the open() would succeed, regardless of whether kernel recognised that flag (e.g. if you run the application on an older kernel). You can't test and retry, because open generally didn't treat unknown flags as a failure.

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.

Flags as a system call API design pattern

Posted Feb 14, 2014 18:28 UTC (Fri) by giraffedata (guest, #1954) [Link] (4 responses)

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?

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.

Flags as a system call API design pattern

Posted Feb 14, 2014 20:01 UTC (Fri) by nybble41 (subscriber, #55106) [Link] (3 responses)

> The recipient rejects any nonzero reserved bits in the first half and ignores any reserved bits in the second half.

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.

Flags as a system call API design pattern

Posted Feb 14, 2014 20:34 UTC (Fri) by paulj (subscriber, #341) [Link] (1 responses)

How do you reject unrecognised flags while still allowing for optional flags?

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.

Flags as a system call API design pattern

Posted Feb 15, 2014 11:41 UTC (Sat) by khim (subscriber, #9252) [Link]

How do you reject unrecognised flags while still allowing for optional flags?

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.

Better then to have a single call that lets the application query for the accepted flags once.

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).

Flags as a system call API design pattern

Posted Feb 14, 2014 22:42 UTC (Fri) by giraffedata (guest, #1954) [Link]

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.

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.


Copyright © 2025, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds