Allow plugins to access MuseScore's preferences?

• Oct 13, 2019 - 20:00

It could be useful for a plugin to be able to know whether or not MuseScore is using the Dark theme in order to color its UI elements appropriately. It is easy enough to add a property to class Ms::PluginAPI::PluginAPI that returns the value of preferences.isThemeDark() so that a plugin could contain the code

if (isThemeDark) {
      ...
      }
else {
      ...
      }

But we need not stop there. What if a plugin had reason to query some other preference? And what if a plugin wanted to provide a way to automate the setting of one or more preferences? As it turns out, this is not so hard either. See 8766ae3, which gives plugins unlimited read/write access to all of MuseScore's preferences. With this implementation, the above snippet would be rewritten as

if (preferences.isThemeDark) {
      ...
      }
else {
      ...
      }

Note that
preferences.isThemeDark
is a shortcut for
preferences.globalStyle == MuseScoreStyleType.DARK_FUSION
which in turn is a shortcut for
preferences.get("ui/application/globalStyle") == MuseScoreStyleType.DARK_FUSION
All three forms are permitted.

So my question is this: Do we want to give plugins the ability to query the value of any arbitrary preference like this allows? And not just query, but also modify the setting? Or is it enough to simply allow read only access to certain preferences via properties either directly in class Ms::PluginAPI::PluginAPI or in a newly created class Ms::PluginAPI::Preferences? And if so, which preferences should be exposed this way?


Comments

Note that you already have read/write access for all properties contained in the .ini/prefs file using a Qt.labs.Settings instance as long as the value is of a type that is exposed (being something that QML has a QVariant wrapper for, or has been explicitly exposed by MuseScore itself)

My opinion is that the most plug-ins can do the better. Plug-ins have always been the "poor relatives" in MS development since their inception (I think ver. 1 already had some kind of automation, but I may remember incorrectly).

Actually, if deeply and widely implemented, plug-ins could be an effective way to implement less widely needed features by (power) users themselves, relieving the main development from secondary tasks.

So, IMHO, reading ALL preferences FOR SURE!

Writing them? I understand this may sound scary to someone; still, any reasonably powerful plug-in API would allow to make a mess out of a score or to ruin data. Either we think plug-ins are useful (and we allow them to be potentially dangerous) or we do without them, tertium non datur (at least, I cannot see it).

Plug-in code is easy to read and to analyse, so malicious intents are unlikely. Bugs are possible, of course, but even in the programme main code!

So, to summarise, I vote for allowing preference FULL ACCESS to plug-ins.

In reply to by Miwarre

No, plugin code is not easy to read and analyze unless you are a skilled computer programmer (and even if you are one, as I have been for a lengthy career, the plugin language stack is baroque (in the uncomplimentary sense!)). Users not skilled in Javascript, Qt, and security debugging should not have to read source code to prove that an attractive plugin is not going to damage not just their musescore, but maybe their system or their life. The lax attitude towards security in plugins scares me tremendously. Not writing preferences would be a start, but not writing the file system or exfiltrating or corrupting your computer would be even better. Vetting and signing of plugins, as Firefox does, is another path.

No.
It does not make sense to give write (and modify) permissions.
reasons:
1. many saboteur attacks the plugin code like crazy.
2. Someone who wants to make money finds and uses many open doors in the software.
3. There will be many users who complain that "this plugin deleted my file, changed my settings, killed my cat". (And even if that's not the truth)
Reading permission can of course be granted.

jeetee's point is a good one. It is already possible to read and modify preferences from a plugin via Qt.labs.Settings, and I don't know that there is anything we can do to prevent this. The question at this point becomes whether or not to directly support reading and possibly modifying preferences through Ms::PluginAPI. Is there a benefit to providing a method for doing so on our own terms, so to speak, instead of having plugin authors go behind our back, as it were?

Without any intention to start a polemic or to criticise other opinions, to which anybody is entitled — as I am entitled to mines, right or wrong they be —, I find these positions a bit extreme.

First of all, we are not speaking of extensions to Chrome or Firefox, which possibly billions of persons use, this is MuseScore, a very specialised programme, which only a very tiny minority of computer users have installed; also, so far we are dealing with a few dozens of plug-ins at most; it does not seem the best choice to invest time on for a malicious 'invader'.

Also, plug-in are open source, by definition. Their language may not be the most clear out there? possibly, but, they rarely exceed one or two hundreds of lines (often much less than this): hardly an unmanageable mass of code (and it is essentially Javascript, which is hardly an esoteric language).

In addition, I may lack imagination (well, I do!), but I cannot understand how someone could, for instance, gain money by altering subreptitiously someone else's preferences (MuseScore preferences, not my bank account preferences...). And, again, only a few ‘someone else’...

So, plug-ins can be dangerous? Sure, they are here to automate operations on (mostly) scores; then, they MUST be able to modify my scores; then they CAN damage them (among other things). So can do the main MuseScore code, which is MUCH less manageable than the code of a plug-in for its own very size, if nothing else.

However, if we are SO concerned, the only way to eliminate this danger is to remove the plug-in API and do without any plug-in at all. With which I would disagree.

In reply to by Miwarre

This is not so. If a plugin can do whatever it wants to scores you have loaded, including delete them from the running instance, that is not 'dangerous'. If a plugin can, as they now can, write or delete files in your file system, that is dangerous. One corrupt/malicious plugin author is all it takes. I have already seen a plugin whose main action is to download code from a URL somewhere else. The idea that "people are mostly good out there; don't worry about the bad ones" has failed recently, if one watches the world.

Qt is flawed insofar as that it does not provide, as browsers do, a sandboxed scripting environment. This is Modern App Design 101 AFAIAC.

In reply to by BSG

That one plugin got detected and removed the same day IIRC (wrongly as it turned out, see below)

And whether it was really malicious, or just potentially malicoius hadn't even been checked for, the fact that it downloaded code was enough to get it removed from musescore's plugin repository

In reply to by Jojo-Schmitz

Excuse my poor poetry. I mean, you were implying, if I read you correctly (and maybe I didn't), "These things get sorted out and found sooner or later by the community. Fear not." And the apparent reposting of this plugin suggests that that approach is insufficient, so I ask, "What do you think we should do now, knowing this? Whither now?" (Actually, I don't know, so I'm eager for ideas).

In reply to by Jojo-Schmitz

That's the good news and the bad news, huh? If it's not abundantly clear already, I think "product maturity" and "featuring an unsafe non-sandbox from a substrate that doesn't offer a safe one" have just collided. As a proud author of very safe plugins, I have some investment in this outcome.

In reply to by BSG

In that particular case we were at least able to reinstate transparency, by revealing the code that does get downloaded and it does look harmles (at a cursery glance). But indeed that would need to get checked again for every single run of that plugin, to see whether it changed and to what.
In this particular case I'd vote for getting it removed form the repository. I don't see any need for that plugin to load code from a foreign website, it should be all inside the plugin, out in the open to see for everybody.

In reply to by Jojo-Schmitz

If the author had malicious intent, he could change it a day after you looked at it. If the possibility of malicious intent is to be categorically ignored, there is no problem. Otherwise ... the "repository" is a list of links to GitHub, not a store of vetted code. This is IMO a big problem.

And then there is that other fellow's plugin that relies upon execution of shell commands....this is a horror. Cavalier/"Don't worry, we're all good people around here" approaches to security is precisely what attackers seek out.

In reply to by BSG

There is a beautiful, out-of-the-way museum here in Boston that hosted a famous Rembrandt and Vermeer. Security was light, "only fine people come here; not to worry". One bad day in 1990, a criminal ring figured that out, and the world's largest art theft to date was committed and those paintings have not been seen since.

In reply to by BSG

True, and I agree that loading code from the net from within a plugin is bad. Loading a plugin's code from github or the musescore plugin repo though is different, you do this only once and can check the code then, without fearing it to get changed under your feet

In reply to by BSG

Without actually posting an example of malicious code on this forum, can anyone here create a MuseScore plugin that does something malicious? And I'm not talking about fetching and executing code. I am wondering what could be malicious about the code that is executed, and what any of this has to do with my original question.

In reply to by BSG

What it has to do with your original questions about inspecting or modifying preferences is that that is the tip of the iceberg.
If modifying the plugin API like I suggested somehow opens the door for plugin authors to write malicious code, then I could certainly see how all of this would be relevant. But as it is, I just don't see it.

In reply to by BSG

1) On my machine (Linux Mint 19), a user process cannot modify (directly or through a shell script) anything outside the home directory, for sure it cannot write or remove anything to/from, say, /bin or /usr, unless it is run as a super-user (sudo mscore); which is done exceptionally for diagnostic purposes, but if you do it regularly, you are fishing for troubles. A shell script can sudo indeed, but this would prompt for a password and alert even a rather careless user...

If someone runs an OS which allows a user process to modify the system, then I would start blaming the OS in the first place...

2) On another side, if the "bad plug-in" described above is the one I think, it contains the "https://" protocol in a plain text string; this is rather simple to detect with an automated scanning procedure.

Any URI protocol, not only http(s):// (with the possible exception of file:// ?), should be enough to raise a flag on a plug-in, possibly in addition to the name of some questionable classes / methods (to be identified but, for instance, "Loader" is a natural candidate... ).

This in the case an automated scanning procedure is deemed necessary...

In reply to by Miwarre

Reading and modifying files inside /home can also be dangerous, after all, all data of web browser or mail client are stored inside the home directory (or at least can be modified by any program launched with that user's permissions). A malicious plugin can at least delete all user's data which is also not a good thing, even in case one has backups of one's data.

In reply to by dmitrio95

User could also be running with admin privileges (on any OS) out of laziness, not knowing that MuseScore plugins are categorically unsafe (a harsh way to say it, but you can't say it's not so ....) On a multi-user system, an admin can destroy other people. On a personal computer, a non-admin user can only destroy himself; in that, the most common case today, the difference is insignificant.

In reply to by BSG

«User could also be running with admin privileges (on any OS) out of laziness, not knowing that MuseScore plugins are categorically unsafe (a harsh way to say it, but you can't say it's not so ....) [...]»

I totally agree. So, either we accept the potential risk or we drop the plug-in feature; tertium non datur.

In reply to by Miwarre

O tempora! O mores! as Cicero said about MacOS 10.15 (Catilina)--- is it really up to us, or up to users to accept this risk? Is it possible to envision taming the Qt plugin architecture somehow, intercepting dangerous things? The plugin notion is a really powerful tool for users, but where does our responsibility to users lie in this regard? chown root Carthago before it's too late.

In reply to by BSG

QML engine has probably never been designed to be used as an engine for user-specific extensions or plugins, so it is natural that it doesn't have any sandboxing implemented. Still I don't know for sure whether it is not possible to enforce any restrictions on QML code at all or we still can develop something that could be able to prevent plugins from doing certain dangerous things.

In reply to by dmitrio95

About dangerous things: if everything related to connecting with the www could be prevented, that would remove a huge threat. (one of the biggest I believe)

And as @BSG said: what about a (github) public Musescore plugin repo? (unmanageable?)

Could the musescore command line option to run a plugin on a score be used to run a set of tests on that plugin? Nothing elaborated: just to know a few things:
- does it use the FileIO API and what for (reading/writing)?
- does it modify preferences (and which one)
- does it contact the www
- does it delete score/elements
- etc.

Once this is known, if the file raises any of these last flags then maybe it should indeed be checked before appearing in this (soon there:) plugin manager. (The plugin manager will drastically multiply the usage of the existing plugins I believe, so this is a good discussion to have now, before it gets to unexperimented users...)

In reply to by Marr11317

Deleting elements is a reasonable thing, but a plugin should not ever write a score out (I'm sure someone will say "but suppose I want to write a plugin to save out all scores that need saving"). Right now this situation is a seduction to malwarists ("They'll never know it's there!" is what bad actors specialize in finding and exploiting).

In reply to by BSG

It would be easy to add a message box telling the user that the plugin is writing files to the disk. "Plugin: pluginName is writing fileName to the disk, do you want to allow this plugin to do so?"

Maybe a small output could show where files have been written...

In reply to by mattmcclinch

Simply take bool FileIO::write(const QString& data)

bool FileIO::write(const QString& data)
      {
      if (mSource.isEmpty())
            return false;
 
      QFile file(mSource);
      if (!file.open(QFile::WriteOnly | QFile::Truncate))
            return false;
 
      QTextStream out(&file);
      out << data;
      file.close();
      return true;
      }

and modify it:

bool FileIO::write(const QString& data)
      {
      if (mSource.isEmpty())
            return false;
 
      QFile file(mSource);
 
      QMessageBox::StandardButton permissionFromUser = // the message box (" Plugin: pluginName is writing fileName to the disk, do you want to allow this plugin to do so?", QMessageBox::Yes|QMessageBox::No)
 
      if (permissionFromUser == QMessageBox::No) {
            // log to the console: "file could not be written to the disk: permission denied"
            return;
            }
 
      if (!file.open(QFile::WriteOnly | QFile::Truncate))
            return false;
 
      QTextStream out(&file);
      out << data;
      file.close();
      return true;
      }

And the same goes for bool FileIO::remove()

In reply to by dmitrio95

A few sparse comments as, like one could expect from such a topic, the thread is wandering...

First: I think any measure and any concern should be compared to the risk:

it is — I believe — 7 or 8 years (since MS 1) that MS has some automating feature and in this time span only ONE plug-in raised some concerns. I spent a few minutes (it was very easy) retrieving the "code" this plug-in download(ed?) via "https://" to find another, rather regular, plug-in doing the actual job. So, the procedure was very unusual and concerns were legitimate, but to my eye, even the ONLY positive is turning out as a false positive.

The horde of blood-thirsty "intruders" madly looking for "holes" through which penetrate our holy MuseScore and ravage our hard disks (of which there is abundance since MS 2.x) so far failed to manifest itself...

Mainly — I believe — because the MuseScore plug-in user community is too tiny to be relevant: of the very little tiny minority of people actively writing music down (I mean writing it on some support, not "composing" it), only a portion uses some music notation software, of them only a portion uses MuseScore, of them only a VERY LITTLE minority uses plug-ins: of the few instrumentalists of my area and/or interests who use MuseScore , I am the ONLY ONE using plug-in. And I only use plug-in I make myself tailored to my needs (not by choice, just by chance).

The risk is likely to increase as MuseScore audience grows: surely, but the measures proposed in this thread, which surely make sense on the paper, do not look to me as balancing the advantages with the costs.

For instance: intercepting disk writing accesses. Fine, clever, BUT:

  • several of my MS 2 plug-ins had user preferencies and user presets of their own stored on disk; such a measure would trigger a warning box for many operations in the plug-in main dlg box. The n-th time I had to aknowledge it I would remove the plug-in and doing that task more quickly by hand!
  • one of the plug-ins distributed with MS itself and written by such a reputable author as lasconic, the ABC converter, writes on disk and even uploads and downloads stuff to/from a web site: this would (and should!) raise a BIG RED FLAG!
  • say I have a plug-in I wrote myself (which is by far the more frequent case, in which I perfectly know what is inside) and which accesses the HD: I do not want to be pestered by those warning boxes.
  • and so on.

To quote BSG (it is now at least 5 years I ask for a quoting feature in these fora!): « Is it possible to envision taming the Qt plugin architecture somehow [...] ?»

Well, probably not; not:
- without crippling the plug-in potential and/or annoying unnecessarily the users
- without creating an infrastructure (to code and maintain tests, to manually vet plug-ins, ...) hardly compatible with the resources of this community
- and correlated to the actual risk.

Finally, what do others do?

  • LibreOffice has a rather sophisticated macro / extension framework around the UNO language; so sophisticated that I never understood it (UNO probably stands for "Unidentified Non-comprehensible Objects"...); so I have no idea what safeguards they implemented; it may be worth investigating, keeping in mind that they could design everything from scratch and have an audience many orders of magnitude larger than ours.
  • Other open source programmes I use which have a plug-in framework are QGis and FontForge; both use Python as scripting language; I am pretty sure at least FontForge takes no precaution — with Python it is possible to wipe an entire HD - and I know of no complains or concerns in this area! Either they are a bunch (two bunches?) of irresponsible peoples or they perceive a very different level of risk.

To summarize, I remain of my idea: there is a potential risk? Yes, so either we accept this risk or we do without plug-ins.

This post is much longer that I expected and that I can afford to spend time on. So, this is my last contribution to this thread; use it as you like!

In reply to by Miwarre

I will only say that I "did time" programming in UNO, and it was as opaque and bitter as you indicate. Javascript in browsers is the best worked-out and most useful sandbox I know, but even Firefox now has made it really difficult to run un-vetted plugins (they vet them), even if you write them yourself. It's not easy.

In reply to by Miwarre

  • several of my MS 2 plug-ins had user preferencies and user presets of their own stored on disk; such a measure would trigger a warning box for many operations in the plug-in main dlg box. The n-th time I had to aknowledge it I would remove the plug-in and doing that task more quickly by hand!

QSettings would not be affected so that should not be an issue.

  • say I have a plug-in I wrote myself (which is by far the more frequent case, in which I perfectly know what is inside) and which accesses the HD: I do not want to be pestered by those warning boxes.

remembering permissions for plugins doesn't seem to complicated to me: you would only have to give the permission once.

  • of the very little tiny minority of people actively writing music down (I mean writing it on some support, not "composing" it), only a portion uses some music notation software, of them only a portion uses MuseScore, of them only a VERY LITTLE minority uses plug-ins

Like said before I believe this will change as the Plugin Manager gets implemented in 3.4

  • there is a potential risk? Yes, so either we accept this risk or we do without plug-ins.

I cant agree with you there: lots of other opensource programs do have a plugin API which works perfectly and I know none known to cause problems.

I do agree that plugins should not be restricted by permissions, but they should remain safe.
Anyway, there's so many things that can't be done with the plugin API yet that I don't know if plugins are worth all this debate.

In reply to by Marr11317

Writing your own plugins and running plugins loaded from "the street" should be distinguishable. (The Mac is getting increasingly wary of app safety, and XCode (the C++ IDE) has now picked up features to allow you run the programs you yourself build without complaint, but (I think this will happen in January) only in debug builds.) How to distinguish is not clear, but it probably involves cryptographic signatures (as the Mac signing does). I see no reason why even in the strictest schemes imaginable a plugin could not store its own preferences (this is necessary IMO). The plugins I created for 3.3 grant significant power over performance not otherwise available anywhere near this easily. I want more people to use them, not consider plugins esoteric and dangerous. (If plugins went away, I'd implement these features in C++). As I said, Firefox has made it impossible for me to "hey, try my experimental plugin!" without Firefox vetting, and Browser JS API cannot access files, shell, or cross-site AJAX.

Repeating myself, if there are safety tradeoffs to be made, informed users should be making them. But i suspect few non-programmer users are sufficiently informed to evaluate these tradeoffs.

In reply to by BSG

I share the concern mentioned somewhere above in the discussion that if we a going to use the GSoC project for plugins manager with easier plugins installation and auto-updating capabilities then this issue may become much more important.

Concerning the restrictions management,
1) If implemented, it should probably be done in the form of permissions given to a particular plugin rather than a message box which appears every single time a plugin tries to do a certain operation;
2) Large part of potentially dangerous capabilities come from Qt itself, for example from XMLHttpRequest API implementation which can access local files or QML types like FolderListModel. These features will probably be much more difficult to restrict.
3) Even if some form of restrictions gets implemented, some form of review of plugins uploaded to musescore.org will probably be still required, as nothing potentially stops any plugin update to contain something malicious. For that purpose I would say Github links are much less preferable as in this case we have absolutely no control over what code the plugin author can upload later under the given link, and when such an update can happen.

In reply to by dmitrio95

1) agreed. Think like app permission settings in Android for example. One could integrate it into the plugin resource manager

2) you simply can't block a big part of the Qt/QML file interfaces; including doing so would again cripple the export plugins; You can't block QSettings access to your own properties.
All of these access restrictions can be made possible when you don't use QML; but creating your own flavor of it is a huge work effort. Looking at how the effort for even exposing only the MuseScore classes is currently an almost too high burden on development and the limiting factor in developing useful plugins; imo this is just dreaming the (near) impossible from a maintenance perspective

3) If you put a review process into place, somehow requiring the code to be submitted and only published after review. There is no reason to not prefer GitHub links at all. Don't put an extra burden on those writing the plugins.
Have them put in the github link into your system (as it is now), make use of the GitHub release API; when the plugin creator publishes a new release there; it creates a review request on your end. All you need to do is review the release code (which is tagged on commit hash, so uniquely identified) and tick an "approved" checkbox in your system, which makes the new version show up in the plugin resource manager.
But a process such as this also requires a real commitment on review timing. A review can't be postponed for 20 days just because a/the reviewer is on holiday. In that case, you can count on users bypassing that system and directly go and download the plugin from the author directly (just like many *nix users use PPAs rather than the system repository for a bunch of software)

4) None of this is worth the effort imo. I do wonder about the need to have QProcess be exposed and don't remember why it was at all. But so far, implementing such restrictions would afaik make MuseScore the first OS software imposing them.
GIMP for example uses scheme or python as a plugin language; there is a community repository (unvetted) site; and that's it. No vetting, full access.

In reply to by BSG

True, but (aside from sheer manpower) the main difference there is that in a browser, the mere act of opening a page, loads (and runs!) executable code of unknown origin.
In projects such as GIMP/MuseScore/LibreOffice the act of executing(/enabling) that code in itself requires user interaction.

In reply to by Jojo-Schmitz

You "hit the nail on the head". Inability (of any of us) to answer that question should prompt group soul-searching; I have much invested in plugins at this point, and would not be thrilled by a "Surgeon General's Warning" like that put on the sides of US cigarette boxes many years ago, "Warning: this product can kill you"; Prior to those days, there were seductive TV ads for the joys of each brand of cigarettes. "My plugins are safe, they can't hurt you! Would I lie to you!?"

In reply to by Jojo-Schmitz

(cough, cough). That's a start ... The SG warning mentions emphysema, cancer, and death. Perhaps "mailcious code" should mention "can compromise or damage your system", i.e., this is not about just corrupting random notes in your score.

In reply to by BSG

Warning: Plugins can potentially contain bad or malicious code, which can compromise or damage your system or scores. Plugins are entirely unvetted (except for those that are part of the MuseScore installation). You'd either need to trust the author or check the code yourself.

You also want some of those ugly pictures they put on cigarette packs over here?

In reply to by Jojo-Schmitz

We can imagine what they would look like; you wouldn't be able to post them. I would interchange "system and scores" ... "scores or system"... "You need" not "You would need". Nothing conditional about it. I suppose a ransomware "pay me" screen might be a good compromise.

In reply to by Marr11317

The problem with the Android system is that in practice it is an "all or nothing" system. The usual 'dialogue' between the app installer and the user is something like this:
APP: May I slap you in the face and strangle you, should I feel the urge of it?
USER: (Hmmm..., if really necessary, I could stand being slapped, but I would prefer not to be strangled: ) No, thanks.
APP: Then, I cannot run. Bye.

I know that, in theory, permissions could have more granularity at run time, but as far as I can tell, few apps implement things like this.

Not to mention that this would require to put up an infrastructure in the plug-in framework which, at the rate at which progress is made in this area, would defer plug-in availability for a rather long time.

A big, terrifying, warning on the pages about plug-ins and from were plug-ins could be downloaded, along the line of the above exchange between BSG and Joachim and the one recently added, but B I G G E R, would seems to me a much more practical way of reminding the users that there are risks involved, without delaying things with development loads above the resource of this community and, I remain convinced, above the actual risk level.

EDIT: Ok, I said I would have no longer posted in this thread, but I could not resist. Amen.

In reply to by Miwarre

The "Android" system as just described means that the app has to be honest up front (which is useless for malware). MacOS Catalina certainly asks you at runtime (see the MuseScore installation instructions) "MuseScoreBeta3.app wants to use the Downloads directory. Let it?", although you can give it this permission a priori. It's not up to the app. The fact that my left side say "Users! Please try my wonderful plugins!" and my right side says "Users, don't use plugins unless you're a competent programmer who can study the code!" is just terrible. Thanks for posting the Android images!

In reply to by Miwarre

On Android you can revoke rights granted on App install later, on newer Andoid versions at least. Some Apps then may just fail, other may ask ti get them granted again, depends on what Adndroid version they had been written for IIRC.
But indeed it'd be better to give the detailed choice at install time, or asking at run time, like iOS does

In reply to by Jojo-Schmitz

If you can't ask at runtime, asking at install time is a poor choice, IMNSHO, for it would give the idea that the interaction provides protection against malware, while, in fact, malware will never ask "may I?" up front before committing evil while running.

In reply to by BSG

On the other hand, maybe you're proposing, if it could be done, "ask up front, and if not granted, the actual facilities are denied you", which would, of course, require preventing certain classes and API's from operating, but there seems to be an issue as to whether the latter can be done.

Do you still have an unanswered question? Please log in first to post your question.