mupuf.org // we are octopimupuf.org

Sandbox Utils and the Cranky File Chooser Dialog

Once Upon a Time

Try­ing my best to make the ti­tle sound like one of those tales you’d tell your kids when putting them to bed. Those who know me well know that I’m do­ing a PhD, al­legedly on ac­tiv­ity con­fine­ment, and those who know me even bet­ter have wit­nessed me rant every day for three months about how it’s im­pos­si­ble (be­cause eth­nomethod­ol­ogy, phe­nom­e­nol­ogy, em­bod­ied in­ter­ac­tion, sit­u­ated ac­tion, etc.). So I de­cided to con­vert to an­other re­li­gion. I’m now a guru of the church of sand­box­ing. Hope­fully nei­ther cog­ni­tive dis­so­nance nor my PhD ad­vi­sor will catch up on me be­fore my de­fense (ah ah).

There’s a plethora of tools for app sand­box­ing out there, on every ma­jor OS, and even more peo­ple ar­gu­ing over which is the most se­cure – noth­ing I can con­vince my­self to care about. Be­cause all these sand­box­ing tools as­sume, in one way or an­other, that the thing they’re try­ing to con­tain is de­signed to be put in their box. This world­view fits server apps in­cred­i­bly well: they’re de­signed to process one type of data, con­tin­u­ously, and to pro­duce a spe­cific out­put at a spe­cific place for a spe­cific in­put. Se­cu­rity re­searchers also got very wealthy ex­ploit­ing the sili­cia nugget of mo­bile phones: phone apps have such lit­tle util­ity and phones such re­stricted in­ter­ac­tion tech­niques that you never do any sub­stan­tial mul­ti­task­ing or process any com­plex kind of data, you have fewer op­tions for app cus­tomiza­tion than on the desk­top, and as a re­sult most mo­bile apps process their own data rather than your doc­u­ments.

All of that is won­der­ful, but when you’re in­ter­ested in gen­eral pur­pose mul­ti­task­ing-ca­pa­ble com­plex op­er­at­ing sys­tems, it doesn’t work. Users tend to keep a lot of data around on their desk­top OS, they have apps that process mul­ti­ple for­mats and they reuse a file across mul­ti­ple apps. They con­stantly mul­ti­task with apps that don’t care the least about proper pass­word stor­age, etc. You’re even rou­tinely asked to process data from mul­ti­ple un­trusted sources on a rou­tine ba­sis to earn your salary! And yet apps eas­ily get com­pro­mised (es­pe­cially Linux apps), and stay com­pro­mised af­ter­wards. They can de­stroy all of your data, abuse your re­sources and steal your root pass­word with sur­pris­ingly lit­tle ef­fort!

It should be ob­vi­ous to all that ac­cess con­trol poli­cies and “fine-grained” sand­box­ing are no cure to the dis­ease of the desk­top. If not, read field stud­ies on in­for­ma­tion work­ers’ daily life, con­tem­plate the sheer com­plex­ity of their work days and then come back and ask them if they want to sit and write poli­cies be­cause they get any work done. Our chal­lenge is to have the pol­icy be pro­duced on-the-fly, and with no user cost (time, money or cog­ni­tive load) s’il-vous-plaît. Sand­box Utils is my col­lec­tion of black magic tricks that do just that.

App Sand­box­ing: Friends vs Foes

Re­mem­ber, I said sand­box­ing tools were de­signed to sand­box co­op­er­a­tive apps, that ac­cept drop­ping their priv­i­leges, tell you what they need and don’t need, and nat­u­rally process data in well-iso­lated chuncks. They can be put into VMs, SELinux do­mains, NaCl, LXCs, etc. to serve them. What we want on the desk­top is not to sat­isfy friend apps who’ll work with us, but en­able the writ­ing and use of foe apps who’ll cheat on us. So rather than the “start-almighty-and-keep-your­self-un­der-con­trol” par­a­digm, we’ll adopt “start-from-the-bot­tom-and-prove-your-worth”. Apps start en­tirely sand­boxed, and the user de­cides on-the-fly what apps gain ac­cess too – an ac­cess which (un­less stated oth­er­wise) lasts only un­til the user moves on to some­thing else. This con­cept is called se­cu­rity by des­ig­na­tion: the user des­ig­nates what a process should be al­lowed to ac­cess.

Given that zero-user-ef­fort is crit­i­cal for the tech­nol­ogy to be de­ployed and adopted, I want the des­ig­na­tion to oc­cur nat­u­rally in the ways peo­ple use their com­put­ers. There has been at least one im­ple­men­ta­tion called User-Dri­ven Ac­cess Con­trol (al­beit in the won­der­ful world of Sam­sung Nuggets), that al­lows pro­vid­ing ac­cess to de­vices like a phone’s cam­era when a user clicks a but­ton. The con­cepts be­hind are no won­der to a se­cu­rity en­gi­neer: ca­pa­bil­i­ties and a trusted path. No black magic. And yet no ma­jor OSes un­til very re­cently im­ple­mented any­thing sim­i­lar!

What I want to do with Sand­box Utils is serve the foes, and pro­vide them all the fea­tures they need to write awe­some apps for my users! I want them to be able to ac­cess files, with what­ever model they en­joy best (atomic ac­cesses, ac­cess to re­cent files, scan­ning for all your videos, re­triev­ing groups of in­ter-re­lated files in one in­ter­ac­tion, etc.). Be­cause I want my users to know what they’re up to, ac­cess will be granted via a user in­ter­ac­tion in a trusted and priv­i­leged wid­get. Like what has been done in UDAC, I’ll pro­vide ac­cess to all the ca­pa­bil­i­ties we’ve been speak­ing about here and there through spe­cial but­tons and di­alogs. That’s for the the­ory.

In prac­tice, GUI apps al­ready ex­ist and make use of per­mis­sive APIs. No­body wants to rewrite their apps just for fun, let alone to use a more re­stric­tive API and lose key fea­tures. Fea­ture par­ity is hardly reach­able (as we shall see on one ex­am­ple) so yes, APIs will break and yes, we’ll have to rewrite apps. I’d like to use the oc­ca­sion to re­flect upon things that pro­gram­mers com­monly try to achieve, to re­duce their work­load in ex­change for a more tightly-con­trolled work­flow and the abil­ity for me to do se­cu­rity by des­ig­na­tion. This is also an oc­ca­sion to im­prove user ex­pe­ri­ence by forc­ing more key el­e­ments of their in­ter­ac­tions with apps to be­come more con­sis­tent. Users learn au­toma­tisms so we might as well make use of that from times to times rather than re­sent it when try­ing to catch their at­ten­tion and get them to make se­cu­rity de­ci­sions (oh, the irony).

I won’t even speak about how one goes about sand­box­ing an app, launch­ing it and pro­vid­ing it with a priv­i­leged helper that ex­poses the API I’ll dis­cuss. This is en­gi­neer­ing de­tails. Let’s have a look at this ex­am­ple used by Ka-Ping Yee and many oth­ers, that seems so triv­ial at first: the almighty and hon­or­able file chooser di­a­log.

Sand­box File Chooser Di­a­log

The Sand­box­File­Chooser­Dia­log class is the Sand­box Utils equiv­a­lent of GTK+’s Gtk­File­Chooser­Dia­log. It al­lows de­vel­op­ers to dis­play a di­a­log in which users will ei­ther se­lect files or fold­ers to open or a lo­ca­tion for them to save a file.

In GTK+ this API is only a con­ve­nient method for apps to use a stan­dard­ized pre-coded di­a­log, and since apps have ac­cess to the file sys­tem, they can do a lot of neat things such as pre­view­ing the cur­rently se­lected file, mod­ify the file­name typed by the user to in­clude a for­got­ten ex­ten­sion, etc. Once file sys­tem ac­cess has been taken, two con­se­quences arise:

  • Users must also be pro­tected into apps that at­tempt to fool them, for in­stance by mod­i­fy­ing the di­a­log just be­fore they press Open
  • Apps lose the abil­ity to read files or covertly mod­ify the user-cho­sen file­name, and the API must be ex­panded for all valid use cases that made use of such an abil­ity

The for­mer is­sue is solved by in­tro­duc­ing state­ful­ness to the di­a­log: de­vel­op­ers must fin­ish con­fig­ur­ing their di­a­log be­fore they run it. Once it runs, it can­not be touched (only can­celled, brought to the fore­ground or de­stroyed). Then, and only if the run was suc­cess­ful, de­vel­op­ers can read what­ever files the user se­lected. The work­flow in­duced by the states ac­tu­ally maps the com­mon way of us­ing a Gtk­File­Chooser­Dia­log. Ma­jor dif­fer­ences with the stan­dard API for ba­sic us­ages are that all func­tions take a GEr­ror pa­ra­me­ter and that the sfcd_run() method no-longer re­turns a re­sponse di­rectly. In­stead, one must con­nect to the response sig­nal. Both changes are side-ef­fects of need­ing to carry method calls across D-Bus to a re­mote server: IPC is more fail­ure-prone.

A de­vel­oper might at­tempt to cheat by se­lect­ing a file they want to steal whilst in the con­fig­u­ra­tion state, run­ning the di­a­log and wait­ing for a be­wil­dered user to click Cancel. To pre­vent that, only cer­tain la­bels can be as­so­ci­ated with a pos­i­tive out­come grant­ing ac­cess to files. This is some­what a re­gres­sion back to the good old world of stock la­bels, but I’m afraid it’s nec­es­sary to pre­vent so­cial en­gi­neer­ing at­tacks. One can also ar­gue it re­in­forces con­sis­tency across apps to limit the pos­si­ble la­bels.

API ex­ten­sion is a bit harder to tackle. At the mo­ment my API does not sup­port cer­tain things. I pro­vide sup­port for em­bed­ding (sand­boxed) ex­tra wid­gets into a (priv­i­leged) di­a­log us­ing the XEm­bed spec (know­ing that this is tem­po­rary and will be re­placed with a so­lu­tion that will be se­cu­rity-as­sessed later on in Way­land/We­ston). Sup­port for file fil­ters will be rein­tro­duced (ex­cept for cus­tom file fil­ters which pose the prob­lem of leak­ing the cur­rent folder’s con­tent). The GFile func­tions will not be rein­tro­duced with­out a good rea­son (be­cause they’re mostly fea­tu­ri­tis from my lay­man view, and they’re hard to carry across D-Bus).

For pre­view wid­gets, I’m tempted to say app devs should write thumb­nail­ers rather than pre­view­ers. Thumb­nail­ers can be used both by the file chooser di­a­log and by the file man­ager, and al­low ren­der­ing files in­side sand­boxes! This means no risk of in­for­ma­tion leak­age, and no more dan­gers in­her­ent to bugs in ren­der­ing li­braries. In any case, app devs would need to pro­vide a sep­a­rate piece of code or method to do file pre­view­ing from the CLI for us to run a sand­boxed pre­viewer live. I’d rather rely on some­thing like Tum­bler and a bit of ex­tra sand­box­ing than ask app devs to pro­vide sand­box­able li­braries that end up be­ing used just for pre­view­ing.

Fi­nally, the gtk_­file_­choos­er_get_cur­ren­t_­name() method sug­gests de­vel­op­ers may need to ap­pend an ex­ten­sion to the user-pro­vided file­name based on the state of a file for­mat se­lec­tion ex­tra wid­get. In fact, it seems to me that file for­mat se­lec­tion is the most com­mon us­age for an ex­tra wid­get. I’m also a bit an­noyed at how ex­tra wid­gets are placed in Gtk­File­Chooser­Dia­log (very frankly, the left align­ment of the ex­tra wid­get and right align­ment of the file fil­ter make for a big waste of screen real es­tate).

Since it is known to de­vel­op­ers what for­mats they want to sup­port and how they’d change the file ex­ten­sion de­pend­ing on this for­mat, I’m tempted to have a spe­cialised wid­get in Sand­box­File­Chooser­Dia­log that maps a cur­rently se­lected for­mat to an ex­ten­sion, with­out the de­vel­oper ever see­ing the file­name and with the user get­ting im­me­di­ate feed­back. Many in­ter­ac­tions can be imag­ined to al­low users to ei­ther copy the cor­rected file­name in their buffer and fur­ther edit it, or to mod­ify the ex­ten­sion on-the-fly with a GtkPopover. Ac­tu­ally, this wid­get could serve ex­tra pur­poses such as en­forc­ing file­names that are com­pat­i­ble with a spe­cific file sys­tem (e.g., au­to­mat­i­cally re­plac­ing : with - for FAT), or time­stamp­ing saved files. There are only so many things that de­vel­op­ers need on a reg­u­lar ba­sis to im­prove their users’ ex­pe­ri­ence, but those things will no longer be pos­si­ble for sand­boxed ap­pli­ca­tions un­less catered for.

In­ter­nally, Two Di­alogs for one API

I won’t de­scribe the whole in­ner bolts, but it’s worth noth­ing that the class used by the server to map to GTK+ and the one used by the client to per­form D-Bus calls have the same par­ent class, and that it is this par­ent class that is ex­posed to de­vel­op­ers and doc­u­mented. Con­se­quently, users can choose whether to use sand­box-ca­pa­ble or lo­cal di­alogs sim­ply by typ­ing --sandbox or --no-sandbox when launch­ing their app. With D-Bus ac­ti­vat­able apps, a desk­top en­vi­ron­ment could de­ter­mine in sit­u­a­tion whether it should launch a sand­boxed app or not, and ad­just the launch­ing en­vi­ron­ment and pa­ra­me­ters ac­cord­ingly. App de­vel­op­ers only need to use a sin­gle lib, and not to worry about com­pile-time pa­ra­me­ters. It’s not quite the same as not be­ing aware of the sand­box, how­ever: app de­vel­op­ers just have to use the sand­box-com­pat­i­ble API all the time – which is why it needs to rock and pro­vide even higher value than GTK+3 !

Epi­logue

I’d like to thank Mar­tin (mupuf) for our usual chat­ting and his san­ity checks on the Git tree, but also all the GTK+ and GNOME peo­ple I’ve been bug­ging on IRC in the past few weeks! Matthias Clasen also pro­vided very use­ful in­put and I’m afraid he was right on all the line! You guys prob­a­bly saved me an ex­tra week-end’s worth of time!

A fi­nal note: I don’t care much whether sand­box-ca­pa­ble APIs are im­ple­mented in­side a toolkit, or as an ad­di­tional layer; whether they should be writ­ten as plain C code or neat GOb­jects with prop­er­ties, etc.; whether one should use G-DBus or an­other lib, etc. I care about the ex­posed APIs feel­ing to app de­vel­op­ers like sys­tem APIs rather than a toolkit they can tweak in what­ever way they want, be­cause the dis­tinc­tion should be made clear and de­vel­op­ers should know that hacks will not re­sult in fea­tures but in de­nied ac­cesses. I’m merely writ­ing code to play with ideas, be­cause that’s what my job is about (lucky stu­dents…)!

I hope Sand­box Utils can get us started dis­cussing ex­actly how apps will ob­tain and use user doc­u­ments, and so I’m in­ter­ested in the opin­ions of app de­vel­op­ers: which fea­tures do you need – which are use­less to you? What type of data do you want from your users and how do you process it? What makes your day when us­ing a toolkit – and what ru­ins it and makes you lose time? How can we im­prove the APIs you use to build apps, to the point where we pro­vide you more value than what you cur­rently have?

Ex­tra Links

Comments