Thursday, February 13, 2020

Digest for comp.lang.c++@googlegroups.com - 20 updates in 3 topics

Frederick Gotham <cauldwell.thomas@gmail.com>: Feb 13 05:58AM -0800

A note on topicality: This post isn't very much to do with C++ itself, but some people who frequent this group might find this of interest as the main PC operating systems MS-Windows, Linux and MacOS can be programmed for in C++.
 
I've started work again on my network analysis program that I first released back in 2011. My application is a GUI program that uses wxWidgets, and so far I've got it working for Linux (running GTK+), and MS-Windows.
 
Up until now, the user has had to explicitly run the program as an Administrator (or as "root"). So if they run it as a normal user, it will load up and say "Failed to open network interface". I want to change this. If my program is run as a normal user then I want the user to be prompted to elevate to Administrator (or "root") and to input their password as necessary.
 
I've already found code online for achieving this in MS-Windows: https://www.codeproject.com/Articles/320748/Haephrati-Elevating-during-runtime
 
When it comes to Linux, I don't think it's possible to elevate a process to be owned by 'root'. Please correct me if I'm wrong on this. I think on Linux, I will have to have a starter program (which can be run as a normal user) which then tries to run my main application as root.
 
I've looked a the source code on GitHub for "GParted", the partition manager in Ubuntu, and I can see how it uses a starter script to load the main program. This would be fine for me however there's one condition with my program that I don't want to break:
- My program can be distributed as a single file that does not need to be installed, and it does not make any changes to the computer (specifically, it doesn't write to the hard disk)
 
So here's what I'm thinking I might have to do on Linux:
 
(1) I have my main program 'prog'
(2) I write my starter program 'progstart', and I embed the binary hex values of 'prog' inside it as a char array.
(3) When 'progstart' is run, it creates a shared memory object in the Linux files system, and then it maps the raw binary values of my main application into this shared memory object. This shared memory object will be accessible at "/dev/shm/prog_binary". As everything is a file in Linux, I can then set the execution bit on "/dev/shm/prog_binary" and then try to start it as root.
 
If I can get this to work, it would mean that I can still distribute my application on Linux as a single executable file that doesn't need to write to the hard disk. Oh by the way, I realise that the directory "/tmp" is a RAM disk on most Linux computers but I just want to guarantee myself that I'm using RAM by going with a shared memory object instead.
 
Any advice or ideas on this?
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Feb 13 03:42PM +0100

On 13.02.2020 14:58, Frederick Gotham wrote:
 
> I've started work again on my network analysis program that I first released back in 2011. My application is a GUI program that uses wxWidgets, and so far I've got it working for Linux (running GTK+), and MS-Windows.
 
> Up until now, the user has had to explicitly run the program as an Administrator (or as "root"). So if they run it as a normal user, it will load up and say "Failed to open network interface". I want to change this. If my program is run as a normal user then I want the user to be prompted to elevate to Administrator (or "root") and to input their password as necessary.
 
> I've already found code online for achieving this in MS-Windows: https://www.codeproject.com/Articles/320748/Haephrati-Elevating-during-runtime
 
Relaunching isn't exactly a good way.
 
There are three main ways to do things:
 
* Just mark the executable as requiring elevation. Then Windows will
always ask before running it.
* Let it launch another program (not itself) using ShellExecute family.
* Use the COM interface that ShellExecute uses internally, to call a
function in a DLL that you provide, elevated.
 
 
> (3) When 'progstart' is run, it creates a shared memory object in the Linux files system, and then it maps the raw binary values of my main application into this shared memory object. This shared memory object will be accessible at "/dev/shm/prog_binary". As everything is a file in Linux, I can then set the execution bit on "/dev/shm/prog_binary" and then try to start it as root.
 
> If I can get this to work, it would mean that I can still distribute my application on Linux as a single executable file that doesn't need to write to the hard disk. Oh by the way, I realise that the directory "/tmp" is a RAM disk on most Linux computers but I just want to guarantee myself that I'm using RAM by going with a shared memory object instead.
 
> Any advice or ideas on this?
 
You know, invoke it as `sudo gork`, where `gork` is whatever program.
 
Linux users are accustomed to having to use `sudo` to do things of
administrative flavor.
 
- Alf
Frederick Gotham <cauldwell.thomas@gmail.com>: Feb 13 06:53AM -0800

On Thursday, February 13, 2020 at 2:42:22 PM UTC, Alf P. Steinbach wrote:
 
> Relaunching isn't exactly a good way.
 
 
I didn't look closely at that code, I just brushed past it because I thought it elevated the privileges of the current process. (I'm focusing on Linux right now and I'll get back to MS-Windows later).
 
 
> You know, invoke it as `sudo gork`, where `gork` is whatever program.
 
> Linux users are accustomed to having to use `sudo` to do things of
> administrative flavor.
 
 
"gksudo" has been removed from Ubuntu.
 
Anyway, here's the beginnings of the code for the starter program:
 
#include <stdlib.h>
#include <string.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <sys/types.h>
#include <fcntl.h> /* For O_* constants */
#include <unistd.h>
 
extern char unsigned const g_prog[3521531u];
 
int main(void)
{
/* create the shared memory object */
int const f = shm_open("/prog_binary", O_CREAT | O_RDWR, 0666);

/* configure the size of the shared memory object */
ftruncate(f, sizeof g_prog);

/* memory map the shared memory object */
void *const ptr = mmap(0, sizeof g_prog, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED, f, 0);

/* write to the shared memory object */
memcpy(ptr, g_prog, sizeof g_prog);

/* unmap the memory */
munmap(ptr, sizeof g_prog);

/* Mark the file as executable */
system("chmod +x /dev/shm/prog_binary");
 
/* Run the main program */
system("/dev/shm/prog_binary");

for ( ; /* ever */ ; )
{
/* Do Nothing */
;
}

return 0;
}
 
Unfortunately when I try to run this, I get:
 
sh: 1: /dev/shm/prog_binary: Text file busy
Frederick Gotham <cauldwell.thomas@gmail.com>: Feb 13 06:59AM -0800

On Thursday, February 13, 2020 at 2:53:24 PM UTC, Frederick Gotham wrote:
 
> Unfortunately when I try to run this, I get:
 
> sh: 1: /dev/shm/prog_binary: Text file busy
 
 
I got it to work by adding in:
 
close(f);
 
before I try to execute it. It will remain in memory like that until you delete the file "/dev/shm/prog_binary".
Frederick Gotham <cauldwell.thomas@gmail.com>: Feb 13 07:49AM -0800

On Thursday, February 13, 2020 at 2:59:28 PM UTC, Frederick Gotham wrote:
 
> I got it to work by adding in:
 
> close(f);
 
> before I try to execute it. It will remain in memory like that until you delete the file "/dev/shm/prog_binary".
 
 
It displays a GUI interface for the user to enter their superuser password if I change:
 
"sudo /dev/shm/prog_binary"
 
to:
 
"pkexec env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY /dev/shm/prog_binary"
 
This looks really nice and it's exactly what I'm looking for.
 
Now... I want to see if it's possible to have my main program in memory just once instead of twice. If you look at my previous code, you'll see that I create the shared memory object, and then I copy the binary data from my global char array into the shared memory object. So if my main application is 4.5 megabytes, then it will take up 9MB of RAM before my main program has made any allocations on the heap. Ideally I would only like to have my program in memory once. It's not the end of the world though if I take up another 4 or 5 more megabytes of RAM considering that my main application overall uses about 5 - 10 megabytes of RAM when running.
Bonita Montero <Bonita.Montero@gmail.com>: Feb 13 05:22PM +0100

You can give a thread admin-rights by LogonUser with admin
-credentials and then do ImpersonateLoggedOnUser give the
therad the access-rigts of the newly created token.
Jorgen Grahn <grahn+nntp@snipabacken.se>: Feb 13 07:38PM

On Thu, 2020-02-13, Frederick Gotham wrote:
...
> When it comes to Linux, I don't think it's possible to elevate a
> process to be owned by 'root'. Please correct me if I'm wrong on
> this.
 
You're wrong; there's at least one standard Unix way of doing it, and
maybe some Linux-specific ones, too.
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Frederick Gotham <cauldwell.thomas@gmail.com>: Feb 13 12:24PM -0800

> You're wrong; there's at least one
> standard Unix way of doing it, and
> maybe some Linux-specific ones, too.
 
Kindly illuminate me.
Frederick Gotham <cauldwell.thomas@gmail.com>: Feb 13 12:27PM -0800

By the way, after thinking about it for a minute... my main application is actually in memory three times. There's the first one when the global data of the 'starter' program is loaded. There's the second one when I copy it into the shared memory object, and there's the third one when I execute "/dev/shm/prog_binary".
Ike Naar <ike@sdf.lonestar.org>: Feb 13 11:22PM

>> standard Unix way of doing it, and
>> maybe some Linux-specific ones, too.
 
> Kindly illuminate me.
 
man setuid?
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Feb 12 04:48PM -0800

Can anybody else get this to compile:
_______________________
#include <iostream>
#include <memory>
#include <atomic>
 
 
struct foo
{
int m_a;
int m_b;
};
 
 
//static std::shared_ptr<foo> g_bar;
static std::atomic<std::shared_ptr<foo>> g_bar;
 
int main()
{
{
std::shared_ptr<foo> local = g_bar;
std::cout << local << "\n";
}
 
std::cout << "\n\nFin!\n";
 
std::cout.flush();
std::cin.get();
 
return 0;
}
_______________________
 
 
;^o
Ian Collins <ian-news@hotmail.com>: Feb 13 02:01PM +1300

On 13/02/2020 13:48, Chris M. Thomasson wrote:
> };
 
> //static std::shared_ptr<foo> g_bar;
> static std::atomic<std::shared_ptr<foo>> g_bar;
 
I'm not sure if any tools support this C++20 feature yet!
 
--
Ian
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Feb 13 01:31AM

On Thu, 13 Feb 2020 14:01:48 +1300
 
> > //static std::shared_ptr<foo> g_bar;
> > static std::atomic<std::shared_ptr<foo>> g_bar;
 
> I'm not sure if any tools support this C++20 feature yet!
 
std::shared_ptr atomics have been available since C++11 (but not in
this form). You can lead a horse to water, but you cannot make it
drink.
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Feb 12 05:42PM -0800

On 2/12/2020 5:31 PM, Chris Vine wrote:
 
> std::shared_ptr atomics have been available since C++11 (but not in
> this form). You can lead a horse to water, but you cannot make it
> drink.
 
I have never used it before! Consider it learning. Reading 20.8.2.6 from:
 
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Feb 13 03:34PM +0100

On 13.02.2020 01:48, Chris M. Thomasson wrote:
> }
> _______________________
 
> ;^o
 
That's a C++20 feature.
 
But depending on your use case it may not be necessary. Quoting
cppreference, <url: https://en.cppreference.com/w/cpp/memory/shared_ptr
>:
 
"All member functions (including copy constructor and copy assignment)
can be called by multiple threads on different instances of shared_ptr
without additional synchronization even if these instances are copies
and share ownership of the same object. If multiple threads of execution
access the same shared_ptr without synchronization and any of those
accesses uses a non-const member function of shared_ptr then a data race
will occur; the shared_ptr overloads of atomic functions can be used to
prevent the data race."
 
The "overloads of atomic functions" are, from the same page,
 
 
std::atomic_is_lock_free(std::shared_ptr)
std::atomic_load(std::shared_ptr)
std::atomic_load_explicit(std::shared_ptr)
std::atomic_store(std::shared_ptr)
std::atomic_store_explicit(std::shared_ptr)
std::atomic_exchange(std::shared_ptr)
std::atomic_exchange_explicit(std::shared_ptr)
std::atomic_compare_exchange_weak(std::shared_ptr)
std::atomic_compare_exchange_strong(std::shared_ptr)
std::atomic_compare_exchange_weak_explicit(std::shared_ptr)
std::atomic_compare_exchange_strong_explicit(std::shared_ptr)
 
- Alf
Manfred <noname@add.invalid>: Feb 13 08:43PM +0100

On 2/13/2020 3:34 PM, Alf P. Steinbach wrote:
 
> But depending on your use case it may not be necessary. Quoting
> cppreference, <url: https://en.cppreference.com/w/cpp/memory/shared_ptr
> >:
 
Which means it should be changed into the following, right?
 
_______________________
#include <iostream>
#include <memory>
#include <atomic>
 
struct foo
{
int m_a;
int m_b;
};
 
static std::shared_ptr<foo> g_bar;
// static std::atomic<std::shared_ptr<foo>> g_bar;
 
int main()
{
{
std::shared_ptr<foo> local = std::atomic_load(&g_bar);
std::cout << local << "\n";
}
 
std::cout << "\n\nFin!\n";
 
std::cout.flush();
std::cin.get();
 
return 0;
}
_______________________
 
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Feb 12 04:15PM -0800

On 2/12/2020 7:01 AM, Chris Vine wrote:
> the shared_ptr atomic functions in a case where they are necessary: of
> course in that case your code does not work. You need to use the right
> tool for the job - try reading §20.8.2.6 of C++14.
 
I did not know that one could wrap shared_ptr<bar> in atomic<>. So the
following should be Kosher?
______________________________________
static atomic<shared_ptr<bar>> g_bar; // nullptr
 
void multiple_threads()
{
for (;;)
{
shared_ptr<bar> local = g_bar;
if (! local) continue;
 
local->foobar();
}
}
 
void single_thread()
{
shared_ptr<bar> local(new bar());
g_bar = local;
}
______________________________________
 
The default loads and stores wrt atomic should be seq_cst. I apologize
for my ignorance wrt never using atomic<shared_ptr<T>>.
 
Shi% happens.
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Feb 13 01:28AM

On Wed, 12 Feb 2020 16:15:52 -0800
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wrote:
[snip]
 
> The default loads and stores wrt atomic should be seq_cst. I apologize
> for my ignorance wrt never using atomic<shared_ptr<T>>.
 
> Shi% happens.
 
It would be great if you could read §20.8.2.6 of C++14, as I have
suggested before. Are you having trouble finding it?
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Feb 12 05:34PM -0800

On 2/12/2020 5:28 PM, Chris Vine wrote:
>> following should be Kosher?
>> ______________________________________
>> static atomic<shared_ptr<bar>> g_bar; // nullptr
[...]
 
>> Shi% happens.
 
> It would be great if you could read §20.8.2.6 of C++14, as I have
> suggested before. Are you having trouble finding it?
 
I can reading it right now:
 
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf
 
Snippet:
_________________
20.8.2.6 shared_ptr atomic access [util.smartptr.shared.atomic]
1 Concurrent access to a shared_ptr object from multiple threads does
not introduce a data race if the access
is done exclusively via the functions in this section and the instance
is passed as their first argument.
2 The meaning of the arguments of type memory_order is explained in 29.3.
template<class T>
bool atomic_is_lock_free(const shared_ptr<T>* p);
3 Requires: p shall not be null.
4 Returns: true if atomic access to *p is lock-free, false otherwise.
5 Throws: Nothing.
template<class T>
shared_ptr<T> atomic_load(const shared_ptr<T>* p);
6 Requires: p shall not be null.
7 Returns: atomic_load_explicit(p, me
_________________
 
Okay! Thanks for your patience.
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Feb 12 05:36PM -0800

On 2/12/2020 5:34 PM, Chris M. Thomasson wrote:
> On 2/12/2020 5:28 PM, Chris Vine wrote:
>> On Wed, 12 Feb 2020 16:15:52 -0800
>> "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wrote:
[...]
>> It would be great if you could read §20.8.2.6 of C++14, as I have
>> suggested before.  Are you having trouble finding it?
 
> I can reading it right now:
^^^^
 
I _am_ reading it.
 
 
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf
[...]
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: