Lazarus

Programming => General => Topic started by: jw on December 01, 2020, 04:19:36 am

Title: self elevation in linux
Post by: jw on December 01, 2020, 04:19:36 am
I'm accessing serial ports in linux, which means the program needs to run as root, or I gotta know if the user has rights to use tty, else synaser will try, but the program won't crash or anything, it just won't communicate...

As such, with gksudo now gone etc,  here's my code to self elevate, which doesn't work and I don't know why....  I have found that it's extremely hard to visualize what the command line is going to look like in order to figure out why things fail in both linux and windows.  I wish it was as easy as it looks in the memo.

Code: Pascal  [Select][+][-]
  1. if FpGetuid <> 0 then
  2.      begin
  3.  
  4.           password := PasswordBox('Attention', 'Access to serial ports requires the right permissions.' + #10#13 + 'With the wrong permissions the program looks like it''s working, but actually does nothing.' + #10#13 + 'If you are sure you have tty permissions then leave the password blank.' + #10#13 + 'Else enter the root password.');
  5.           if password <> '' then
  6.           begin
  7.           // memo1.append('echo ' + password + ' | sudo -S "' + paramstr(0) + '"');
  8.  
  9.           AProcess := TProcess.Create(nil);
  10.           //AProcess.Executable:= 'echo';
  11.           //AProcess.Parameters.Add(' ' + password + ' | sudo -S "' + paramstr(0) + '"');
  12.  
  13.           AProcess.CommandLine:= 'echo ' + password + ' | sudo -S "' + paramstr(0) + '"';
  14.           AProcess.Options := AProcess.Options + [poWaitOnExit];
  15.           AProcess.Execute;
  16.           AProcess.Free;
  17.           halt(1);
  18.  
  19.           end;
  20.  
  21.      end;          
  22.  
  23.  
  24.  
Title: Re: self elevation in linux
Post by: BlueIcaro on December 01, 2020, 07:59:18 am
I'm accessing serial ports in linux, which means the program needs to run as root, or I gotta know if the user has rights to use tty, else synaser will try, but the program won't crash or anything, it just won't communicate...

As such, with gksudo now gone etc,  here's my code to self elevate, which doesn't work and I don't know why....  I have found that it's extremely hard to visualize what the command line is going to look like in order to figure out why things fail in both linux and windows.  I wish it was as easy as it looks in the memo.

Code: Pascal  [Select][+][-]
  1. if FpGetuid <> 0 then
  2.      begin
  3.  
  4.           password := PasswordBox('Attention', 'Access to serial ports requires the right permissions.' + #10#13 + 'With the wrong permissions the program looks like it''s working, but actually does nothing.' + #10#13 + 'If you are sure you have tty permissions then leave the password blank.' + #10#13 + 'Else enter the root password.');
  5.           if password <> '' then
  6.           begin
  7.           // memo1.append('echo ' + password + ' | sudo -S "' + paramstr(0) + '"');
  8.  
  9.           AProcess := TProcess.Create(nil);
  10.           //AProcess.Executable:= 'echo';
  11.           //AProcess.Parameters.Add(' ' + password + ' | sudo -S "' + paramstr(0) + '"');
  12.  
  13.           AProcess.CommandLine:= 'echo ' + password + ' | sudo -S "' + paramstr(0) + '"';
  14.           AProcess.Options := AProcess.Options + [poWaitOnExit];
  15.           AProcess.Execute;
  16.           AProcess.Free;
  17.           halt(1);
  18.  
  19.           end;
  20.  
  21.      end;          
  22.  
  23.  
  24.  
I think you can give permision to your user, to user serial port.

Quote
sudo chown username  /dev/ttyACM0
Title: Re: self elevation in linux
Post by: lucamar on December 01, 2020, 08:37:34 am
As for your code, it doesn't work because:
which means your command-line goes to never-never land :)

Instead, try:
Code: Pascal  [Select][+][-]
  1. AProcess.CommandLine:= 'bash echo ' + password + ' | sudo -S "' + paramstr(0) + '"';
though note that CommandLine is deprecated; instead you should be using the properties Executable and Parameters.

HTH!
Title: Re: self elevation in linux
Post by: MarkMLl on December 01, 2020, 10:13:12 am
I'm accessing serial ports in linux, which means the program needs to run as root

It most certainly does not. It means that you need to identify whether the serial port is owned by a specific group such as (on Debian) dialout, and make sure that the user as which you are running is a member of that group.

If a hotplugged serial port is not owned by dialout, then fix your udev rules.

For anything more than that, you use POSIX capabilities.

You might have problems debugging a program using POSIX capabilities from the IDE, in which case you run it as root using gdbserver... there's one or two odd issues that give problems relating to e.g. stuff in the /sys tree but nothing that would affect ordinary programs.

MarkMLl
Title: Re: self elevation in linux
Post by: MarkMLl on December 01, 2020, 10:15:15 am
  • echo is a shell command, not a program you can run; and

Careful there. It's one of a number of commands which exist as both shell intrinsics and binaries on disc, so can be confusing.

MarkMLl
Title: Re: self elevation in linux
Post by: lucamar on December 01, 2020, 02:10:29 pm
Careful there. It's one of a number of commands which exist as both shell intrinsics and binaries on disc, so can be confusing.

Yes, you're right, but the shell one (if it exists) usually supersedes the independent one, more so for simple:
Code: Pascal  [Select][+][-]
  1. echo something
lines, without options.
Title: Re: self elevation in linux
Post by: MarkMLl on December 01, 2020, 09:30:13 pm
Careful there. It's one of a number of commands which exist as both shell intrinsics and binaries on disc, so can be confusing.

Yes, you're right, but the shell one (if it exists) usually supersedes the independent one, more so for simple:
Code: Pascal  [Select][+][-]
  1. echo something
lines, without options.

Yes, but the risk is that somebody might do man echo or man time and then puzzle over why reality doesn't conform.

MarkMLl
Title: Re: self elevation in linux
Post by: lucamar on December 02, 2020, 12:11:22 am
Well, yes ... though reality conforms more times than not since for calling an internal command with unknown (by the shell) options makes it (most of the times) look for an external one.

It's a little confusing at first but thus is the "zen" of *nix :D

Anyway (and yes, I know you know; just to clarify for future generations and get back to on-topic ;)) the OP's "CommandLine" clearly needs the shell (or some more complex thing) because how sudo -S (in his command) works.
Title: Re: self elevation in linux
Post by: jw on December 02, 2020, 03:09:15 am
Yip, after I posted and retired to bed I realized that bash was doing the piping so I leaned/dreamed very heavily towards exactly what Lucamar posted....

Code: Pascal  [Select][+][-]
  1. AProcess.CommandLine:= 'bash echo ' + password + ' | sudo -S "' + paramstr(0) + '"';
  2.  

Unfortunately that still fails with no a clue as to why?  It's Linux Mint 19.3 Tricia and bash is the default shell, yet perhaps the path is not there?  How would I know?   

Even this still fails silently!
Code: Pascal  [Select][+][-]
  1. AProcess.CommandLine:= '/bin/bash echo ' + password + ' | sudo -S "' + paramstr(0) + '"';

As I said, it's very hard to understand what goes wrong with tprocess without it telling me something like, "Hey you, I couldn't find that bash thing you were looking for."  Though I should probably just start piping the shelled data back to the tmemo to try to find out what may be happening.

Yes I should be using the properties Executable and Parameters, but as per the commented memo.append line, the tprocess.commandline resembles that tmemo.append syntax exactly, thus eliminating a stray space, or some such anomaly, that has ruined many of my past shell attempts.  Thus, with a quick cut and past from a visual text representation of tmemo that works when cut and pasted into a bash prompt it's an easy thing to do.  So again how does bash echo ' + password + ' | sudo -S "' + paramstr(0) + '" not work???

As far as the philosophy of linux and it's permissions, there's no point in arguing any of that especially when folks find it necessary to criticize an entire premise based on a single portion of an extreamly mal-constructed sentence designed to convey the exact nature of the Linux beast..   And so, as MarkMLI explained and explained and explained, thereby again proving why such a user unfriendly beast should be tamed by a fool such as I for the sake of the world;  the facts are this: Linux and it various flavors have throwbacks to that of electronic typewriters tty's.  When a user sits down at a linux box they are usually allowed to surf the web, yet they're not allowed to access to an antiquated serial interface!!  To to fix that programmatically without administrating every box that my software my hit root is required or the user themselves must be savvy enough on their own, which is quite plainy found written in my message to the user via the password box....
Title: Re: self elevation in linux
Post by: Cyrax on December 02, 2020, 03:39:12 am
You should learn how polkit works. https://www.freedesktop.org/software/polkit/docs/latest/polkit.8.html

I use this script code snippet in my bash script to launch all my GUI or terminal programs at root privileges.
Code: Bash  [Select][+][-]
  1. eval pkexec env DISPLAY=$DISPLAY PATH=$PATH dbus-launch "${1}" "${@:2}"

Yip, after I posted and retired to bed I realized that bash was doing the piping so I leaned/dreamed very heavily towards exactly what Lucamar posted....

Code: Pascal  [Select][+][-]
  1. AProcess.CommandLine:= 'bash echo ' + password + ' | sudo -S "' + paramstr(0) + '"';
  2.  

Unfortunately that still fails with no a clue as to why?  It's Linux Mint 19.3 Tricia and bash is the default shell, yet perhaps the path is not there?  How would I know?   

Even this still fails silently!
Code: Pascal  [Select][+][-]
  1. AProcess.CommandLine:= '/bin/bash echo ' + password + ' | sudo -S "' + paramstr(0) + '"';

As I said, it's very hard to understand what goes wrong with tprocess without it telling me something like, "Hey you, I couldn't find that bash thing you were looking for."  Though I should probably just start piping the shelled data back to the tmemo to try to find out what may be happening.

Yes I should be using the properties Executable and Parameters, but as per the commented memo.append line, the tprocess.commandline resembles that tmemo.append syntax exactly, thus eliminating a stray space, or some such anomaly, that has ruined many of my past shell attempts.  Thus, with a quick cut and past from a visual text representation of tmemo that works when cut and pasted into a bash prompt it's an easy thing to do.  So again how does bash echo ' + password + ' | sudo -S "' + paramstr(0) + '" not work???

As far as the philosophy of linux and it's permissions, there's no point in arguing any of that especially when folks find it necessary to criticize an entire premise based on a single portion of an extreamly mal-constructed sentence designed to convey the exact nature of the Linux beast..   And so, as MarkMLI explained and explained and explained, thereby again proving why such a user unfriendly beast should be tamed by a fool such as I for the sake of the world;  the facts are this: Linux and it various flavors have throwbacks to that of electronic typewriters tty's.  When a user sits down at a linux box they are usually allowed to surf the web, yet they're not allowed to access to an antiquated serial interface!!  To to fix that programmatically without administrating every box that my software my hit root is required or the user themselves must be savvy enough on their own, which is quite plainy found written in my message to the user via the password box....


You need to feed -c option to bash and make sure that there is no quotation included when passing the program name to sudo -S command.
Code: Pascal  [Select][+][-]
  1. AProcess.CommandLine:= '/bin/bash -c "echo ' + password + ' | sudo -S ' + paramstr(0) + '"';
Title: Re: self elevation in linux
Post by: dbannon on December 02, 2020, 04:05:21 am
Yip, after I posted and retired to bed I realized that bash was doing the piping so I leaned/dreamed very heavily towards exactly what Lucamar posted....

While Lucamar is correct in what he says, there are some policy issues that take (IMHO) precedence.  Firstly, the model of an application asking the user for the root password has some issues-
* Giving an application the root password allows it to do anything. I imagine your app wont run off the rails but can you guarantee that ?  What about if your app is somehow hacked ?  In the *nix world, we have very clear borders between user space and system space to minimize that risk, by running your app, even part of it, in root space, you bypass all those safe guards.
* Because of the above, most experienced *nix users will get very nervous when asked for the root password. There are some apps we know will make that request and we know their history, my guess is you app will not yet be so trusted.  Even if your app is completely safe, we do not want apps 'training' end users to supply root password when asked.
* The user may not even know the root password.

Mark's model is vastly better and its the standard way to do things in the *nix world. You add the (ordinary) user who will run the app to the group that can use the serial port. Just like, its all you need to do. If your app runs amok or is replaced by some malicious one, all it can do is use the serial port. Thats quite a modest risk.

Importantly, thats the tried and tested way to achieve what you are trying to do. I believe you would need a very good reason to look for another way ....

Davo
Title: Re: self elevation in linux
Post by: MarkMLl on December 02, 2020, 09:43:37 am
As far as the philosophy of linux and it's permissions, there's no point in arguing any of that especially when folks find it necessary to criticize an entire premise based on a single portion of an extreamly mal-constructed sentence designed to convey the exact nature of the Linux beast..   And so, as MarkMLI explained and explained and explained, thereby again proving why such a user unfriendly beast should be tamed by a fool such as I for the sake of the world;  the facts are this: Linux and it various flavors have throwbacks to that of electronic typewriters tty's.  When a user sits down at a linux box they are usually allowed to surf the web, yet they're not allowed to access to an antiquated serial interface!!  To to fix that programmatically without administrating every box that my software my hit root is required or the user themselves must be savvy enough on their own, which is quite plainy found written in my message to the user via the password box....

<Shrug> You're doing it wrong. Read the Linux documentation, read the documentation which came with the development board you're using. Most of this was fixed about 20 years ago, when serial ports were moved onto /dev/ttyXXX rather than the older /dev/cuaXXX inherited from UUCP.

MarkMLl
Title: Re: self elevation in linux
Post by: Warfley on December 02, 2020, 03:03:09 pm
First to your problem, try '/bin/bash -c "echo ... | sudo ..."

But, do you really want to execute your whole program as root? this get's really messy, if all you need is a single stream you could use something like this:
Code: Pascal  [Select][+][-]
  1. AProcess.CommandLine := 'sudo tail -f ' + Filename;
  2. AProcess.Options := AProcess.Options + [poUsePipes];
  3. AProcess.Execute;
  4. // sudo asks for a passwort, so let's supply it with one
  5. AProcess.Input.Write(Password[1], Length(Password));
  6. AProcess.Input.WriteByte(#10); // Newline
  7. AProcess.CloseInput; // tail does not require stdin, if the passwort is wrong, sudo will now terminate with an error code
  8. // TODO: sudo error checking
  9. // From this point onwards use AProcess.Output provides a stream to read from that file
This technique can also be used to read real files not only pseudo files that require root (by using cat instead of tail -f)

If you need a real filedescriptor in the filesystem, then you can use named pipes (fifos), by executing the following:
Code: Pascal  [Select][+][-]
  1. fpMkFifo('temporary.fifo', &600); // from unit BaseUnix
  2. AProcess.CommandLine := 'bash -c "sudo tail -f ' + Filename + ' > temporary.fifo"'
  3. ...
Now you can read from temporary.fifo as if it is the real file, but with the difference that you own the file and tail does the reading as admin.

You of course need to delete the fifo afterwards, using fpUnlink from BaseUnix (probably DeleteFile also works)

This can also all be combined into one command:
Code: Pascal  [Select][+][-]
  1. AProcess.CommandLine := 'bash -c "mkfifo temporary.fifo && sudo tail -f ' + Filename + ' > temporary.fifo; unlink temporary.fifo"'

PS: you probably don't want to use poWaitOnExit in either scenario

PPS: if you don't expect the user to have root rights all the time, providing your own programm that calls tail on the correct file and set the setuid bit on this file as root. This needs to be done only once (on installation of your program) and then this program always runs with root previliges regardless which user calls it

PPPS: sudo might not be installed on all linux systems, just keep that in mind
Title: Re: self elevation in linux
Post by: MarkMLl on December 02, 2020, 03:19:06 pm
But, do you really want to execute your whole program as root?

That's one of the key things. Unix doctrine is to give a program as few rights as possible, and the capabilities mechanism was specifically added to make this fine-grained. If the requirements of the program /demand/ that access to a device be granted by a password, then it would be far better to organise it so that this granted a single extra capability (which is removed as soon as the device has been opened) rather than making the whole thing root which /will/ eventually cause problems.

And I'd expect sudo in this context to have -k so that the password isn't cached longer than necessary.

MarkMLl
Title: Re: self elevation in linux
Post by: trev on December 02, 2020, 10:42:30 pm
But, do you really want to execute your whole program as root?

That's one of the key things. Unix doctrine is to give a program as few rights as possible, and the capabilities mechanism was specifically added to make this fine-grained. If the requirements of the program /demand/ that access to a device be granted by a password, then it would be far better to organise it so that this granted a single extra capability (which is removed as soon as the device has been opened) rather than making the whole thing root which /will/ eventually cause problems.

Spot on. This is also why daemons which need to bind to low ports start as root but then switch to a non-privileged user after accomplishing that. Anything else introduces a serious security issue. Expecting any user to run a user application as root is just so wrong on so many levels, quite apart from the assumption that a normal user has root access.
Title: Re: self elevation in linux
Post by: MarkMLl on December 02, 2020, 11:19:55 pm
Spot on. This is also why daemons which need to bind to low ports start as root but then switch to a non-privileged user after accomplishing that. Anything else introduces a serious security issue. Expecting any user to run a user application as root is just so wrong on so many levels, quite apart from the assumption that a normal user has root access.

Actually, in Debian at least there's been some "give and take" over the last few years.

There are two commands which users expect to be able to run but which demand elevated privilege: ping and traceroute. In the past I've noted that one or two releases allocated a capability to the binaries that allowed them to get the resources they needed without running as root, but then the distro reverted to running them setuid root: my own suspicion is that the amount of grief caused to standard backup etc. procedures outweighed the elegance. Note that at no time did these programs demand a password from the user.

I've used POSIX capabilities fairly heavily on a couple of occasions, but particularly over the last few months when I've been porting a program that used low-numbered UDP ports, created a unix-domain socket in /var/run and various other things. It's possible to integrate the initial capability manipulation into the IDE's compilation commands, /but/ since the capabilities are stored in filesystem extended attributes they're lost if you tar a file or move it around: I suspect that this was a conscious decision on the part of the kernel developers.

There's not an option to set capabilities with the standard install command, neither is it able to invoke an external command to handle that sort of thing. The way I worked around the problem was to have the program announce what commands were needed to get things set up properly if it realised it had a problem, at that point I had to use sudo to sort things out but that was only needed when I loaded an updated version.

Obviously in at least some cases there's other possibilities which exploit egid etc.

MarkMLl
Title: Re: self elevation in linux
Post by: Thaddy on December 03, 2020, 01:41:14 am
Actually, in Debian at least there's been some "give and take" over the last few years.
Be careful, total nonsense. Debian has become MORE strict, not less.
You are playing a Trump? IOW really inexcusable nonsense. >:D >:D >:D

Apart from the user, you need to add to the group that has sufficient rights first and then add to the device group.
Title: Re: self elevation in linux
Post by: MarkMLl on December 03, 2020, 09:23:54 am
Actually, in Debian at least there's been some "give and take" over the last few years.
Be careful, total nonsense. Debian has become MORE strict, not less.
You are playing a Trump? IOW really inexcusable nonsense. >:D >:D >:D

Apart from the user, you need to add to the group that has sufficient rights first and then add to the device group.

I didn't say- and certainly didn't intend to imply- that Debian had relaxed its security. What I was trying to point out is that Debian started off with those two programs running setuid root, then for either one or two versions set the appropriate capability on the binary instead of using setuid, and then reverted to setuid when capabilities were obviously giving problems. If you don't understand that then RTFM >:-|

I can't remember the timescale: not recent, possibly Jessie and/or Wheezy. I was definitely seeing the capability vanish if files were moved around for any reason (e.g. move the /usr tree onto a different physical device).

So please don't accuse me of total nonsense. And definitely keep Trump out of it.

MarkMLl
Title: Re: self elevation in linux
Post by: dbannon on December 05, 2020, 11:49:28 pm
You mean
Code: Pascal  [Select][+][-]
  1. ping -f
I think ?

That is a good example of what I said several posts ago. On bullseye, using ping -f does require root but if an ordinary user tries it, it does not prompt for root password.  It tells you, only superuser is allowed to do that. The application, ping, is never told the root password.

My point was that if it did prompt for a password, that would be like training the user to supply the password on demand, a very bad thing. And the thing the OP was planning to do.

Lets keep on topic here, random applications asking for the root password is a bad thing !

Davo
Title: Re: self elevation in linux
Post by: MarkMLl on December 06, 2020, 10:37:01 am

$ sudo getcap `which ping`
/usr/bin/ping = cap_net_raw+ep


That's from Buster, and shows that Debian has started allocating the net_raw capability to the binary again. I'm not fiddling with it right now since I've got other things to do, but if that binary were moved around I'd expect the capability to be lost until the superuser reinstated it.

If you go back to the previous release you see


$ ls -l `which ping`
-rwsr-xr-x 1 root root 61240 Nov 10  2016 /bin/ping


i.e. it's run setuid root.

If a program wants to "self elevate" it would be reasonable for it to prompt for the user's password before it enables the capability. That's a slightly different can of worms since it will probably mean interacting with PAM in some way.

MarkMLl
TinyPortal © 2005-2018