9

Applications should not have access to data of other applications or to user's private data unless user allows them. Isn't this an obvious need? But every program we launch has full access to our $HOME dir, to our mic and cam. Most users will not even notice if (for example) Skype start sending somewhere their private files or streaming sound from their mic.

I'm looking for ways to fix this. Feel free to suggest anything even if your method implies writing SELinux policies, LSM modules, kernel patches, switching to another UNIX-like OS.

Here is some ideas I had and reasons I rejected them:

  1. We create new unix users for every untrusted app. We use SUID bit to make that app always run as it's user. Bad. Because we need to blacklist every app we don't trust and every new app we install. Tons of work, easy to miss something. Also binaries may lose SUID flag when we upgrade/reinstall app. In addition, there is problem with child processes: in theory, apps that don't have some permission, can use other app to achieve their goal. And if we don't use SUID, it will be hard to remember that we need to use "su" to start every untrusted app.
  2. We use SELinux domain transition to confine untrusted apps. Also bad. Same problem as with #1. We need to write/update/inject SELinux policies for every app we don't trust. I want apps to have no special access by default, not full access.
  3. We create new "trusted" unix users for trusted apps. We can use groups to implement various categories of private data: photos, notes etc. But we can't use SUID and we need manually switch to that user before starting app (with password). Problem of this option is child processes. We can't allow all child processes of trusted program to be trusted (if we open media file in trusted file manager, we don't want media player to inherit trusted status of file manager). But we also can't allow all child processes to drop their permissions to default. Also bad!
  4. We use SELinux to implement "trusted" domains for every trusted app. We can't use automatic domain transition in this case. So we need to switch domain with password. This option is slightly better than #3 because we can forbid launching untrusted apps in such trusted domains. But still bad and uncomfortable.
  5. If we think more, we are starting to see that we can't bind permissions to executible binaries at all. For example, Python interpreter may need different permissions depending on script it runs. So we can forget about options #1 and #2.
  6. We can make our own LSM module (like SELinux). But how it is supposed to work? Not sure I have ideas. Interactive mode? Asking user's permission every time some process attempts to read private files? Or should we take some ideas from "lomac" (low watermark) model? Say, reading untrusted data makes environment tainted and blocks it from reading private data.
  7. Userspace daemon + LD_PRELOAD library? In this case, apps don't have access to private files by default, but they can contact privileged daemon and ask it to open such files and pass file descriptor. This is doable and will look like old "interactive firewalls" for Windows.

More ideas? Please tell me you know ready-made solution :)

schroeder
  • 123,438
  • 55
  • 284
  • 319
Sion0
  • 101
  • 6
  • 1
    Unfortunately, as others said, it seems Linux wasn't designed with this kind of security in mind. It's a pity. I wish I could also have such a control over internet connections (block every outbound connection by default, and only allow specific processes to connect to specific hosts, getting alerts about the program's behavior before allowing or denying a connection, etc). Unfortunately that's not easy to do either, on Linux. Apparently the current popular approach to untrusted stuff on Linux is to run it in separate VMs (wasting resources). – reed Sep 18 '18 at 13:40
  • Thanks for understanding. I started to develop my own LSM (SELinux replacement). It already allows to achieve almost what I wanted. – Sion0 Oct 01 '18 at 04:23

5 Answers5

4

Applications should not have access to data of other applications or to user's private data unless user allows them. Isn't this an obvious need?

No, this is not obvious. Traditionally software installed on the system was considered trusted, i.e. it was not expected that users just go to the internet and download some possible harmful application. It was also not expected that users run insecure software which might interact badly with some remote site and thus give a remote attacker access to local data.

Therefore the security boundary in UNIX (and other OS) is by design the user and not the application. In fact, there is not even a concept of an application as you would like to have - complex applications (like Office) are actually made up of several binaries, libraries, config files etc.

I think that this design is still valid in many use cases, i.e. cases where the systems does not get changed much in the first place or where only trusted software gets installed. But there are also now cases where users actually install software from potentially untrusted sources or install potentially insecure software and expect this software to not do much harm. In these cases the original paradigm of using only the user as a security boundary is not sufficient.

There are OS designed with a different paradigm, i.e. where it is common that users download possible malicious application from the internet and want to restrict access to private data. For example in Android each application is essentially installed as its own user and thus the user boundary is used to restrict access to data generated by another application (this is slightly simplified on how it works).

Thus, if you consider applications untrusted by default you might better run an OS which is designed around this paradigm from start instead of trying to modify an OS which was designed with a different paradigm. As you realized yourself - any attempts to apply the concepts of untrusted applications to a system designed around trusted applications are clumsy and inconvenient to use.

Steffen Ullrich
  • 184,332
  • 29
  • 363
  • 424
  • This is not really an answer. It may not have been always obvious, but it should be obvious now. Just like it was not obvious that many types of security that exists today were needed 5 decades ago. – KalEl Jul 09 '22 at 20:28
4

I recommend looking at AppArmor as an alternative to SELinux; it provides the behavior you want and is simpler to maintain. However, it is a great deal of work to define AppArmor profiles suitable for all programs you might want to run, so generally you still would only use it with untrusted or low-security programs unless the developer/publisher has provided a profile.

With that said... general-purpose operating systems are not, by and large, designed for this kind of sandboxing. Sandboxing has become increasingly popular as an OS feature over the recent years, but there are still good reasons why it isn't implemented as universally as you might expect. In short, sandboxing is both hard to get right (for both the sandbox enforcers and the developers who have to make their app work correctly within the sandbox), and is not the way general-purpose OS security has usually worked and therefore is incompatible with a lot of legacy code.

Early approaches to sandboxing on Linux and similar OSes often used chroot jails, and those are still an option (though they are hard to get right). However, there are other, more-configurable and less-brittle options now. "Containerization" of processes using systems like Docker makes it relatively easy to separate processes from the rest of the system, though Docker itself isn't particularly designed for the use case you describe. It might be possible to adapt it, or its technology, for your uses.

As for other OSes...

  • FreeBSD supports "jails" (with a jail command) that sandbox processes. It is probably the most similar to using Linux with sandboxing techniques, and indeed will run most Linux software and supports much of the same hardware.
  • Android apps run sandboxed, with permissions specified in a manifest that is part of the app package. Modern versions of Android generally allow fine-grained control over the permissions each app gets, so you don't have to decide between giving an app all the permissions it wants vs. not running it at all. While not generally intended for use as a desktop OS, it does sport a very wide range of available software and can be convinced to run on most hardware.
  • Chrom[e|ium] OS runs apps sandboxed, and is essentially a web browser as an OS. It's of limited use if you don't do most of your work online, although newer versions can also run Android apps.
  • MacOS supports sandboxing, and uses it extensively for apps installed from the app store. Traditional MacOS apps will still run with full privileges, though. Proprietary software (with some open-source components), and (legally) requires Apple hardware.
  • Apple iOS runs all apps sandboxed with a permissions mode much like Android, but is much restrictive in what it allows. Lots of apps, but very restrictive in what hardware it will run on (iPad, iPhone, iPod Touch) and very proprietary. Also gives the nominal owner minimal low-level control over the device.
  • Windows 10 supports app sandboxing (used for apps from the app store, and some built-in apps), though most traditional Windows apps still run with full trust (it is difficult to sandbox third-party programs). Proprietary software, but does support running Linux binaries as of the recent releases (generally without any special sandboxing, though, and does not support Linux kernel modules).
CBHacking
  • 40,303
  • 3
  • 74
  • 98
  • 1
    Thanks for overview! Android's security model (minimum permissions by default) is very close to what I want... I am here to make sure I didn't miss some easy and well-known solution to my problem. If there is no such solution, I'll try to implement one of my ideas. – Sion0 Sep 16 '18 at 11:16
1

I didn't find any solution that would suit me. So, in the end, I started to develop my own LSM (Linux Security Module). Currently, it is in the initial stage of development, but already allows to achieve (almost) what I wanted. Here are the basic principles:

  1. User can define up to 64 permissions. Permissions are identified by number, but also may have human-readable aliases. Examples:

    • 1="Permission to read private photos"
    • 2="Permission to read and write browser cookies"
    • 3="Permission to read and write private notes"
  2. Using simple utility, user can mark any file to set:
    a) permissions required to read this file;
    b) permissions required to modify this file;
    c) permissions this file may have if executed.
    Examples:

    • We make permission #1 (read priv photos) required to read some particular photo file.
    • We set that program "/bin/firefox" cannot have any permissions if executed (meaningless because this is default).
    • We set that program "/bin/cat" can have any permissions if executed.
    • We set that program "/bin/imageview" can have permission #1 but not any other.
  3. IMPORTANT Programs (processes) can't have permissions that their parent doesn't have. Examples:

    • "/bin/firefox" can't use "/bin/cat" to read private photo. "cat" will lose all permissions if launched by "firefox".
  4. PID 1 (parent of all userspace processes) starts with full permissions. After that, permissions of every program are determined by removing permissions this program doesn't have from it's parent's permissions.

  5. By default, programs have no permissions. And files need no permissions to read/modify them. So enabling my LSM can't break anything.

  6. There are also plans to implement system permissions like "use internet" or "use microphone".

Something like this... Please tell me if you see critical breaches in such logic.

On my PC, I was forced to give full permissions to following programs: systemd, agetty, login, bash, xinit, sh, startkde, start_kdeinit_wrapper, start_kdeinit, kdeinit5, konsole

Now programs I launch from KDE menu or from konsole may have any permissions. But most of them doesn't have any of course.

Sion0
  • 101
  • 6
  • The thing that I like the most is that by default programs have NO permissions, which is the only way to truly achieve a secure environment. To configure such a system, of course you need a way to monitor what each program is doing and what permissions it asks for, so you can decide to allow the action (if it makes sense) or deny it (if it's unexpected or suspicious). It would be great to have a way to do the same with outbound internet connections (allow or deny). – reed Oct 04 '18 at 12:40
  • Permission #63 is currently reserved and determines if program is allowed to use internet... But access denials currently only logged to dmesg: [43040.384535] chariot: process=16206(/usr/bin/ktorrent) ip=79.165.75.240 port=11200 allow=0. – Sion0 Oct 04 '18 at 16:11
  • It's also possible to set required permissions on /dev nodes (microphone, camera etc.), but such labels are reset after reboot... I will make utility that will be able to label /dev nodes during system startup. – Sion0 Oct 04 '18 at 16:30
  • Hello @Sion0, your gitlab link is broken. Is that project dead? – Bogdan Mart Oct 03 '21 at 23:43
0

Now in 2022, macOS can do it.

Apple believes that users should have full transparency, consent, and control over what apps are doing with their data. In macOS 10.15, this model is enforced by the system to help ensure that all apps must obtain user consent before accessing files in Documents, Downloads, Desktop, iCloud Drive, and network volumes. In macOS 10.13 or later, apps that require access to the full storage device must be explicitly added in System Preferences.

Controlling app access to files in macOS

I don't know about windows or linux.

0

Here's what I do to achieve exactly what you asked.

Part 1: Walling Off

Suppose the restricted data is stored in ~/.local/share/myapp. Then do the following -

# Create a user to restrict access.
# You'll not actually need to login to this user, you'll just need the group.
useradd myapp_restricted

# Change ownership and permissions of the directory.
# This will now prevent any script in your hope to access it.
readonly TARGET="~/.local/share/myapp"
sudo chown -R myapp_restricted:myapp_restricted $TARGET
sudo chmod -R g+u,o-rwX $TARGET

Now it is walled off, applications or scripts won't be able to access that directory.

NOTE: Any new files will be created under your user. For any new files, applications can have access if they are able to guess the exact path names for those (as the can't list directory nor access existing files whose ownership you just changed).

Part 2: Getting access for the app

The sudoers file

Run sudoedit /etc/sudoers.d/app_restrictions to create a new file, and add -

ALL ALL=(ALL:myapp_restricted) ALL
ALL ALL=(ALL:myapp_restricted) SETENV:NOPASSWD:/usr/bin/myapp

Running the application

You can now start the application like below -

# This should work without prompting for password.
sudo -Eg myapp_restricted /usr/bin/myapp

The application will run as yourself with all your environment variables.

If you don't want to invoke with sudo everytime, make a script or desktop shortcut for a GUI.

[Optional] Managing these files

To manage these files, you can also temporarily enter a shell with yourself added to the group -

sudo -Esg myapp_restricted

# Now you should be able to list the files.
ls -l ~/.local/share/myapp
KalEl
  • 101
  • 2