PtInit() doesn't work from SUID root program

The screen grab saga continues…

I now have code that successfully grabs an image of the screen and
outputs it to a .phs file. However, I ran into a small snag when
incorporating the new code as a function in my main application… The
main application must be run SUID root for various reasons.

For some reason, my call to PtInit("/dev/photon") fails when the program
is SUID root. If I remove SUID permissions, PtInit("/dev/photon")
succeeds, the screen image is grabbed and written to disk. Too bad
nothing else works :frowning:

Does this happen even when you play games with setuid() and seteuid()? (In
QNX, a suid root program that calls setuid(0) changes the real as well as
the effective user id; those ids are of course different initially when a
nonprivileged user execs such a program, so I make this odd-sounding
suggestion on the premise that having them be the same might conceivably be
sufficient to make PtInit work for you.)

But in any case this sounds like it might be a most interesting bug. How
exactly does PtInit fail? (What error do you get?)

dB

“Mathew Kirsch” <mkirsch@ocdus.jnj.com> wrote in message
news:b30bak$j5p$1@inn.qnx.com

The screen grab saga continues…

I now have code that successfully grabs an image of the screen and
outputs it to a .phs file. However, I ran into a small snag when
incorporating the new code as a function in my main application… The
main application must be run SUID root for various reasons.

For some reason, my call to PtInit("/dev/photon") fails when the program
is SUID root. If I remove SUID permissions, PtInit("/dev/photon")
succeeds, the screen image is grabbed and written to disk. Too bad
nothing else works > :frowning:

David Bacon wrote:

Does this happen even when you play games with setuid() and seteuid()? (In
QNX, a suid root program that calls setuid(0) changes the real as well as
the effective user id; those ids are of course different initially when a
nonprivileged user execs such a program, so I make this odd-sounding
suggestion on the premise that having them be the same might conceivably be
sufficient to make PtInit work for you.)

But in any case this sounds like it might be a most interesting bug. How
exactly does PtInit fail? (What error do you get?)

PtInit() simply returns a -1. The documentation does not explain how to
get any further diagnostics out of the function.

Mathew Kirsch <mkirsch@ocdus.jnj.com> wrote:

David Bacon wrote:
Does this happen even when you play games with setuid() and seteuid()? (In
QNX, a suid root program that calls setuid(0) changes the real as well as
the effective user id; those ids are of course different initially when a
nonprivileged user execs such a program, so I make this odd-sounding
suggestion on the premise that having them be the same might conceivably be
sufficient to make PtInit work for you.)

But in any case this sounds like it might be a most interesting bug. How
exactly does PtInit fail? (What error do you get?)

PtInit() simply returns a -1. The documentation does not explain how to
get any further diagnostics out of the function.

Still, there’s a good chance that errno may give us a hint.

Is PtInit() one of the first things you call in your program?

Could you make a copy of ped or pterm, make it setuid root, and see if
it works on your system?

Wojtek Lerch wrote:

PtInit() simply returns a -1. The documentation does not explain how to
get any further diagnostics out of the function.

Still, there’s a good chance that errno may give us a hint.

errno does not appear to be set by PtInit: EOK

Is PtInit() one of the first things you call in your program?

It is now. I moved it up so that it’s the absolute first thing called
when the program starts. Okay, PtInit now seems to work, but when I call
for it to grab the screen, it doesn’t grab anything.

Could you make a copy of ped or pterm, make it setuid root, and see if
it works on your system?

Yes, and both work properly.

I also tried doing the same thing to snapshot. It works like a charm!
Frustrating…

Here’s the code that demonstrates the problem. As a normal user, it
works. But if I make the program SUID root (chmod 4755) it doesn’t work:

//qcc grabscreen.c -o grabscreen -lph -lphexlib

#include <iostream.h>
#include <stdio.h>
#include <Pt.h>

// make sure we include BMP support!
#define PX_IMAGE_MODULES
#define PX_PHIMAGE_SUPPORT
#define PX_BMP_SUPPORT
#include <photon/PxImage.h>

int print(PhImage_t *image)
{
int iErrCode = 0;
PhDrawContext_t pdc = 0;
PpPrintContext_t
mpPC;
PhPoint_t p = { 0, 0 };

mpPC = PpCreatePC();

if (mpPC)
{
// set up my context
if(!iErrCode)
{
PpSetPC(mpPC, Pp_PC_DRIVER, “/usr/bin/phs-to-ps”, 0);
PpSetPC(mpPC, Pp_PC_FILENAME, “grabscreen.phs”, 0);

Ph_rect xPrintArea;
xPrintArea.ul.x = 750;
xPrintArea.ul.y = 500;
xPrintArea.lr.x = 500;
xPrintArea.lr.y = 400;
PpSetPC(mpPC, Pp_PC_MARGINS, &xPrintArea, 0);

PhDim_t xPaperSize;
xPaperSize.w = 8500;
xPaperSize.h = 11000;
PpSetPC(mpPC, Pp_PC_PAPER_SIZE, &xPaperSize, 0);

PhDim_t xSourceSize;
xSourceSize.w = 1024;
xSourceSize.h = 768;
PpSetPC(mpPC, Pp_PC_SOURCE_SIZE, &xSourceSize, 0);

}

// initialize the print job
if(!iErrCode)
{
if(PpStartJob(mpPC))
iErrCode = 2;
}

// make the print context active
if(!iErrCode)
{
pdc = PpContinueJob(mpPC);
if(!pdc)
iErrCode = 3;
}

if (image == NULL)
{
cout << “ERROR: NULL image” << endl;
exit(1);
}

cout << "image size: " << image->size.w << “x” << image->size.h << endl;

PgSetPalette( image->palette, 0, 0, image->colors,
Pg_PALSET_SOFT, 0 );

iErrCode = PgDrawImage( image->image, image->type, &p,
&image->size, image->bpl, 0 );

cout << "iErrCode = " << iErrCode << endl;

PpEndJob(mpPC);
PpReleasePC(mpPC);
}

}

int snap(char *fname,PhRect_t rect)
{
int len;
char *mem;
PhImage_t *image;

// get the size of the shared memory you need for the image
if ((len=PgReadScreenSize(&rect))<=0) return -1;

// allocate shared memory to contain the image
if (!(mem=(char*)PgShmemCreate(len,NULL))) return -1;

// read the portion of the screen you’re interested in
if (image=PgReadScreen(&rect,mem))
{
// save the image to the file name given
PxWriteImage(fname,image,NULL,PX_IMAGE_BMP,0);

if ((image = PxLoadImage( fname, NULL )) == NULL) {
perror( “Unable to load image” );
return -1;
}

print(image);
}

// destroy the shared memory you used
PgShmemDestroy(mem);

return 0;
}

int main(int argc,char *argv[])
{
int i;
if (argc!=2)
{
printf("Usage: grab ");
exit(-1);
}

int iPtInit = PtInit("/dev/photon");

cout << "PtInit returned: " << iPtInit << endl;

// get a connection to Photon
if (iPtInit!=0)
{
perror(“Error: Could not connect to Photon.”);
exit(-1);
}

PhRect_t rect;
char fname[120];

//windows_rect(r,&rect);
rect.ul.x = 0;
rect.ul.y = 0;
rect.lr.x = 1023;
rect.lr.y = 767;
sprintf(fname,argv[1],i);
printf(“saving ‘%s’\n”,fname);
snap(fname,rect);

return 0;
}

Mathew Kirsch <mkirsch@ocdus.jnj.com> wrote:

Wojtek Lerch wrote:
PtInit() simply returns a -1. The documentation does not explain how to
get any further diagnostics out of the function.

Still, there’s a good chance that errno may give us a hint.

errno does not appear to be set by PtInit: EOK

Is PtInit() one of the first things you call in your program?

It is now. I moved it up so that it’s the absolute first thing called
when the program starts. Okay, PtInit now seems to work, but when I call
for it to grab the screen, it doesn’t grab anything.

If it didn’t work and you made a change and now it works, it sounds to
me like your problem is solved. But it sounds like your not satisfied.

Looking at your main(), what lines did you re-order? Did you just move
PtInit() above the cout? If so, that would bother me too. It tells me
that theres’ some kind of memory managent problem in the program that
just happened to get unmasked in the one scenerio but not the other.
It doesn’t sound to me like the problem is in fact solved.

QSSL, does a first call to cout leave anything is a less than virgin
state that might affect PtInit()?


Bill Caroselli – Q-TPS Consulting
1-(626) 824-7983
qtps@earthlink.net

Humour me.

Are you using Dinkum or GNU C++ Libs? Does the problem go away if you switch
to using GNU?

Rob Rutherford
Ruzz Technology

“Mathew Kirsch” <mkirsch@ocdus.jnj.com> wrote in message
news:b33f7p$7t5$1@inn.qnx.com

Wojtek Lerch wrote:
PtInit() simply returns a -1. The documentation does not explain how to
get any further diagnostics out of the function.

Still, there’s a good chance that errno may give us a hint.

errno does not appear to be set by PtInit: EOK

Is PtInit() one of the first things you call in your program?

It is now. I moved it up so that it’s the absolute first thing called
when the program starts. Okay, PtInit now seems to work, but when I call
for it to grab the screen, it doesn’t grab anything.

Could you make a copy of ped or pterm, make it setuid root, and see if
it works on your system?


Yes, and both work properly.

I also tried doing the same thing to snapshot. It works like a charm!
Frustrating…

Here’s the code that demonstrates the problem. As a normal user, it
works. But if I make the program SUID root (chmod 4755) it doesn’t work:

//qcc grabscreen.c -o grabscreen -lph -lphexlib

#include <iostream.h
#include <stdio.h
#include <Pt.h

// make sure we include BMP support!
#define PX_IMAGE_MODULES
#define PX_PHIMAGE_SUPPORT
#define PX_BMP_SUPPORT
#include <photon/PxImage.h

int print(PhImage_t *image)
{
int iErrCode = 0;
PhDrawContext_t pdc = 0;
PpPrintContext_t
mpPC;
PhPoint_t p = { 0, 0 };

mpPC = PpCreatePC();

if (mpPC)
{
// set up my context
if(!iErrCode)
{
PpSetPC(mpPC, Pp_PC_DRIVER, “/usr/bin/phs-to-ps”, 0);
PpSetPC(mpPC, Pp_PC_FILENAME, “grabscreen.phs”, 0);

Ph_rect xPrintArea;
xPrintArea.ul.x = 750;
xPrintArea.ul.y = 500;
xPrintArea.lr.x = 500;
xPrintArea.lr.y = 400;
PpSetPC(mpPC, Pp_PC_MARGINS, &xPrintArea, 0);

PhDim_t xPaperSize;
xPaperSize.w = 8500;
xPaperSize.h = 11000;
PpSetPC(mpPC, Pp_PC_PAPER_SIZE, &xPaperSize, 0);

PhDim_t xSourceSize;
xSourceSize.w = 1024;
xSourceSize.h = 768;
PpSetPC(mpPC, Pp_PC_SOURCE_SIZE, &xSourceSize, 0);

}

// initialize the print job
if(!iErrCode)
{
if(PpStartJob(mpPC))
iErrCode = 2;
}

// make the print context active
if(!iErrCode)
{
pdc = PpContinueJob(mpPC);
if(!pdc)
iErrCode = 3;
}

if (image == NULL)
{
cout << “ERROR: NULL image” << endl;
exit(1);
}

cout << "image size: " << image->size.w << “x” << image->size.h << endl;

PgSetPalette( image->palette, 0, 0, image->colors,
Pg_PALSET_SOFT, 0 );

iErrCode = PgDrawImage( image->image, image->type, &p,
&image->size, image->bpl, 0 );

cout << "iErrCode = " << iErrCode << endl;

PpEndJob(mpPC);
PpReleasePC(mpPC);
}

}

int snap(char *fname,PhRect_t rect)
{
int len;
char *mem;
PhImage_t *image;

// get the size of the shared memory you need for the image
if ((len=PgReadScreenSize(&rect))<=0) return -1;

// allocate shared memory to contain the image
if (!(mem=(char*)PgShmemCreate(len,NULL))) return -1;

// read the portion of the screen you’re interested in
if (image=PgReadScreen(&rect,mem))
{
// save the image to the file name given
PxWriteImage(fname,image,NULL,PX_IMAGE_BMP,0);

if ((image = PxLoadImage( fname, NULL )) == NULL) {
perror( “Unable to load image” );
return -1;
}

print(image);
}

// destroy the shared memory you used
PgShmemDestroy(mem);

return 0;
}

int main(int argc,char *argv[])
{
int i;
if (argc!=2)
{
printf("Usage: grab ");
exit(-1);
}

int iPtInit = PtInit("/dev/photon");

cout << "PtInit returned: " << iPtInit << endl;

// get a connection to Photon
if (iPtInit!=0)
{
perror(“Error: Could not connect to Photon.”);
exit(-1);
}

PhRect_t rect;
char fname[120];

//windows_rect(r,&rect);
rect.ul.x = 0;
rect.ul.y = 0;
rect.lr.x = 1023;
rect.lr.y = 767;
sprintf(fname,argv[1],i);
printf(“saving ‘%s’\n”,fname);
snap(fname,rect);

return 0;
}

Robert Rutherford wrote:

Humour me.

Okay, a priest, a minister, and a rabbi walk into a bar…

Are you using Dinkum or GNU C++ Libs? Does the problem go away if you switch
to using GNU?

I’m using the GNU libs, AFAIK. How do you tell?

Bill Caroselli wrote:

If it didn’t work and you made a change and now it works, it sounds to
me like your problem is solved. But it sounds like your not satisfied.

PART of the problem is solved. The code still does not function properly
when the program is given SUID root privileges.

Looking at your main(), what lines did you re-order? Did you just move
PtInit() above the cout? If so, that would bother me too. It tells me
that theres’ some kind of memory managent problem in the program that
just happened to get unmasked in the one scenerio but not the other.
It doesn’t sound to me like the problem is in fact solved.

Actually, I didn’t re-order anything in the example code. The example
code shows the problem I’m running into right now. I guess it’s a
different issue at this point, and I should start a new thread.

It puzzles me that if PtInit is not the ABSOLUTE FIRST thing called in
the program, it’s a crap shoot whether or not it will work. To my way of
thinking, it shouldn’t make a difference.

QSSL, does a first call to cout leave anything is a less than virgin
state that might affect PtInit()?

“Mathew Kirsch” <mkirsch@ocdus.jnj.com> wrote in message
news:b358dc$9el$1@inn.qnx.com

Are you using Dinkum or GNU C++ Libs? Does the problem go away if you
switch
to using GNU?

I’m using the GNU libs, AFAIK. How do you tell?

If you have the NC version you are using GNU by default. If you have the SE
or PE version you are using Dinkum by default.

To verify,
$ objdump -x | grep NEEDED

If you see libcpp.so.* in the list then you are using Dinkum. If you see
libstdc++.so* then you are using GNU.

To switch to the alternate, use the -V option to QCC.

Rob Rutherford