Wrong value of UID in stat() and wrong pr_pid in psinfo_t - c++

My function reads process list from /proc, then read process psinfo file into proper sturcture, as well as data about this file, and prints it.
The problem is, some of the data in those structures is wrong. As usual, the moment when program partially works, is the most confusing. It reads all data correct, except for PID (pr_pid), which is always 0, and UID of a file, which is also always 0. Why? Is it possible for data to load partially correctly? That shouldn't be possible.. 0 would be possible if we were talking about PPID, but solaris documentation clearly states pr_pid is the PID.
Links which I thought would have answers, but I couldn't find one:
http://docs.oracle.com/cd/E19963-01/html/821-1473/proc-4.html
http://linux.die.net/man/3/getpwnam
http://linux.die.net/man/2/stat
code:
void printProcessInformation(char pid[]){
//find full path name to your "stat" file
//DIR *dir;
//struct dirent *ent;
//Creating string with /proc/PID
char * s = malloc(snprintf(NULL, 0, "%s%s", "/proc/", pid) + 1);
sprintf(s, "%s%s", "/proc/", pid);
//Creating string with /proc/PID/psinfo (full path)
char * fullPath = malloc(snprintf(NULL, 0, "%s%s", s, "/psinfo") + 1);
sprintf(fullPath, "%s%s", s, "/psinfo");
free(s);
//printf("%s\n",fullPath);
//Reading data from file
FILE* file = fopen(fullPath, "r");
char* buffer;
buffer = (char*) malloc(sizeof(psinfo_t));
if(file == NULL)
{
perror("Error: Couldn't open file");
return;
}
fread((void *)buffer, sizeof(psinfo_t), 1, file);
psinfo_t* pData = (psinfo_t*) buffer;
free(buffer);
buffer = (char*) malloc(sizeof(stat));
stat(file,buffer);
struct stat* fileStat=(struct stat*) buffer;
printf("File owner id:%d\n",fileStat->st_uid);
free(buffer);
fclose(file);
struct passwd* pw=getpwuid(fileStat->st_uid);
//Loading data from structures
time_t sTime=pData->pr_start.tv_sec;
int pr_pid=pData->pr_pid;
char* fname=pData->pr_fname;
char* uid=pw->pw_name;
printf("%8s %5d %16s %.24s\n", uid, pr_pid, fname, ctime(&sTime));
}

Look at this:
psinfo_t* pData = (psinfo_t*) buffer;
free(buffer);
...
int pr_pid=pData->pr_pid;
You're setting pData to the contents of buffer in the first line and then freeing it. What pData points to is now lost to you, it may in fact be reused in the next malloc. When you try to use it in the last line above you're reading who knows what. You're freeing too agressively in this case. Don't free pData, (indirectly through buffer) until you're done using it.

Related

Can not "read" anything through the FUSE file system

I use fuse to build my own file system in MIT 6.824 lab, and the read operation is implemented in this function.
void
fuseserver_read(fuse_req_t req, fuse_ino_t ino, size_t size,
off_t off, struct fuse_file_info *fi)
{
std::string buf;
int r;
if ((r = yfs->read(ino, size, off, buf)) == yfs_client::OK) {
char* retbuf = (char *)malloc(buf.size());
memcpy(retbuf,buf.data(),buf.size());
//Print the information of the result.
printf("debug read in fuse: the content of %lu is %s, size %lu\n",ino,retbuf, buf.size());
fuse_reply_buf(req,retbuf,buf.size());
} else {
fuse_reply_err(req, ENOENT);
}
//global definition
//struct fuse_lowlevel_ops fuseserver_oper;
//In main()
// fuseserver_oper.read = fuseserver_read;
I print the information of the buf before it return.
The write operation is also implemented, of course.
Then I run a simple test to read out some words.
//test.c
int main(){
//./yfs1 is the mount point of my filesystem
int fd = open("./yfs1/test-file",O_RDWR | O_CREAT,0777);
char* buf = "123";
char* readout;
readout = (char *)malloc(3);
int writesize = write(fd,buf,3);
int readsize = read(fd,readout,3);
printf("%s,%d\n",buf,writesize);
printf("%s,%d\n",readout,readsize);
close(fd);
}
I can get nothing by read(fd,readout,3), but the information printed by the fuseserver_read shows that the buffer is read out successfully before fuse_reply_buf
$ ./test
123,3
,0
debug read in fuse: the content of 2 is 123, size 3
So why the read() in test.c can not read anything from my file system??
Firstly, I've made a mistake to write my test file. The file pointer will point to the end of the file after "write" and of course can read nothing later. So simply reopen the file can make the test work.
Secondly, before read() operation of FUSE, the FUSE will getattr() first and truncate the result of the read() operation with the "size" attribute of the file. So it must be very careful to manipulate the attribute of a file.
There is also a need to notify that you have finished reading by sending an empty buffer, as an "EOF". You can do that by using reply_buf_limited.
Take a look at hello_ll example in the fuse source tree:
static void tfs_read(fuse_req_t req, fuse_ino_t ino, size_t size,
off_t off, struct fuse_file_info *fi) {
(void) fi;
assert(ino == FILE_INO);
reply_buf_limited(req, file_contents, file_size, off, size);
}
static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize,
off_t off, size_t maxsize)
{
if (off < bufsize)
return fuse_reply_buf(req, buf + off,
min(bufsize - off, maxsize));
else
return fuse_reply_buf(req, NULL, 0);
}

_read function is returning obsolete values for file handle

The block of code here runs fine till the _read function is called, after that it changes the value of file handle variable 'fh' for no reason.
std::string& xLogFile;
std::string& xBuffer;
struct _stat& xStatBuffer)
char *buffer;
buffer = (char *)malloc(sizeof(char) * xStatBuffer.st_size);
#define _O_RDONLY 0x0000 /* open for reading only */
int fh = 0, read_bytes =0;
fh = _open(xLogFile.c_str(), _O_RDONLY); // ToDo function deprecated should be changed to fstream
if (fh ==1)
{
if (mWriteLog) IntPkgUtil::TraceLog("Error!! Couldn't open the log file");
return true;
}
read_bytes = _read(fh,&buffer,xStatBuffer.st_size);
_close(fh);
if (read_bytes <= 0)
{
if (mWriteLog) IntPkgUtil::TraceLog("Error!! Couldn't read the log file");
return true;
}
buffer[read_bytes] = '\0';
xBuffer = buffer;
This is a block of code i am using to read from a file into a buffer, but it is failing at the _read function, where the value of file handle 'fh' changes after the call to the function.
Fix the code as below, buffer and not &buffer. You are overwriting the stack.
read_bytes = _read(fh,buffer,xStatBuffer.st_size);

malloc and snprintf bus core dump

Function which worked previously, suddenly refuses cooperation. More precisely this snippet:
//If not, add to UIDS
printf("line 78\n");
free(s2);
printf("line 82\n");
char * ss = malloc(snprintf(NULL, 0, "%s:%d", myUIDs, userId) + 1);
printf("line 84\n");
sprintf(ss, "%s:%d", myUIDs, userId);
free(myUIDs);
myUIDs=ss;
free(buffer);
Program fails one line after "line 82" (no longer line 82, but it's only a debugging stop) with Segmentation Fault (core dumped).
If I change
char * ss = malloc(snprintf(NULL, 0, "%s:%d", myUIDs, userId) + 1); to
char * ss = malloc(snprintf(NULL, 0, "%s:%d", "", 1) + 1);
I get Bus Error: Code dumped instead. I'm working on this program for quite a long time, and I have a feeling it's something obvious, that I'm constantly overlooking because of exhaustion, but no programmer friends to ask for help at this time.
Whole function for context:
char* myUIDs; //string containing all UID-s, separated by colon
void printProcessInformation(char pid[],int isSetP, int isSetN, int isSetU){
//find full path name to your "stat" file
//DIR *dir;
//struct dirent *ent;
//Creating string with /proc/PID
char * s = malloc(snprintf(NULL, 0, "%s%s", "/proc/", pid) + 1);
sprintf(s, "%s%s", "/proc/", pid);
//Creating string with /proc/PID/psinfo (full path)
char * fullPath = malloc(snprintf(NULL, 0, "%s%s", s, "/psinfo") + 1);
sprintf(fullPath, "%s%s", s, "/psinfo");
free(s);
//printf("%s\n",fullPath);
//Reading data from file
FILE* file = fopen(fullPath, "r");
printf("line 37\n");
char* buffer;
buffer = (char*) malloc(sizeof(psinfo_t));
printf("line 40\n");
if(file == NULL)
{
//perror("Error: Couldn't open file");
return;
}
fread((void *)buffer, sizeof(psinfo_t), 1, file);
psinfo_t* pData = (psinfo_t*) buffer;
time_t sTime=pData->pr_start.tv_sec;
int pr_pid=pData->pr_pid;
char* fname=pData->pr_fname;
free(buffer);
buffer = (char*) malloc(sizeof(stat));
stat(fullPath,buffer);
struct stat* fileStat=(struct stat*) buffer;
fclose(file);
int userId=fileStat->st_uid;
struct passwd* pw=getpwuid(userId);
char* uid=pw->pw_name;
printf("line 58\n");
if(isSetU<0){
//Print results
printf("%8s", uid);
if(isSetP>0)
printf(" %5d",pr_pid);
printf(" %16s %.24s\n", fname, ctime(&sTime));
free(buffer);
}else{
//Or else, add UID to UIDS if it didn't appear before
//check if UID is in UIDS
printf("line 70\n");
char * s2 = malloc(snprintf(NULL, 0, "%s:%d", "", userId) + 1);
printf("line 72\n");
snprintf(s2, "%s:%d", "", userId);
if(strstr(myUIDs,s2)!=NULL){
free(s2);
free(buffer);
return;
}
//If not, add to UIDS
printf("line 78\n");
free(s2);
printf("line 82\n");
char * ss = malloc(snprintf(NULL, 0, "%s:%d", "", 1) + 1);
printf("line 84\n");
sprintf(ss, "%s:%d", myUIDs, userId);
free(myUIDs);
myUIDs=ss;
free(buffer);
}
}
There are several issues I see on further review...
In a nutshell, the error you are getting does not appear to be the result of the line you're executing, rather, a side effect of a previous corruption of memory.
Where do you initialize myUIDs? It looks like you could be accessing it when it has not been defined based on the code provided
You are assigning fname from pData which is a pointer to the dynamically allocated buffer... which you subsequently free on the next line of execution, which means that fname is now pointing to deallocated memory. Yet you attempt to read from it later in the code... which may well be leading you off on a random walk through memory.
There are multiple instances in the code where you are dynamically allocating memory, and then attempting to use it without ever validating that you actually got the allocation you requested.
You are calling malloc() based on the return value from snprintf() without ever validating that snprintf() returned you a non-negative value. Though, I doubt this is an issue, it's unwise.
To be sure, the symptoms you are describing are the result of the corruption of the heap. The question is where. I would strongly recommend the use of valgrind.
In addition, if it is available, have a look at asprintf() instead of the malloc( snprintf() ) work you are doing.

How to read pkcs#7 file properly

I have a file with detached pkcs#7 signature of size 267 bytes. I create it after executing
CryptSignMessage(
&SigParams,
TRUE,
1,
MessageArray,
MessageSizeArray,
pbSignedMessageBlob,
&cbSignedMessageBlob)
function and then I write content of pbSignedMessageBlob:
pbSignedMessageBlob[cbSignedMessageBlob] = '\0';
FILE *file;
file = fopen("c:\\path\\sign_pkcs7.pk7", "wb");
fwrite(pbSignedMessageBlob, sizeof(BYTE), cbSignedMessageBlob, file);
fclose(file);
Then I try to verify this signature and read this file:
BYTE *pkcsContent;
FILE *file3;
file3 = fopen("c:\\users\\timur\\desktop\\sign_pkcs7.pk7", "rb");
pkcsContent = MyReadFile(file3, cbArray);
BYTE* MyReadFile(FILE *f, DWORD &len)
{
size_t result;
BYTE *buffer;
if (f == NULL)
{
fputs ("File error", stderr);
exit (1);
}
fseek (f, 0, SEEK_END);
len = ftell (f);
rewind (f);
//buffer = (BYTE*) malloc (sizeof(char)*lSize);
buffer = new BYTE[len + 1];
if (buffer == NULL)
{
fputs ("Memory error", stderr);
exit (2);
}
result = fread (buffer, 1, len, f);
if (result != len)
{
fputs ("Reading error",stderr);
exit (3);
}
buffer[len] = '\0';
fclose (f);
return buffer;
}
But the file content I get into pkcsContent is only 37 bytes length.
I also tried to manage files using std::fstream, but result is the same. Maybe the way I'm writing file to disk is wrong?
Are you trying to compute the length of pkcsContent with strlen (this is my guess since you're null-terminating the buffer in MyReadFil)? You can't do that because PKCS#7 is binary data and it can contain 0 anywhere.

C++ fwrite doesn't write to text file, have no idea why?

I have this code that basically reads from file and creates new file and write the content from the source to the destination file. It reads the buffer and creates the file, but fwrite
doesn't write the content to the newly created file, I have no idea why.
here is the code. (I have to use only this with _sopen, its part of legacy code)
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <fcntl.h>
#include <string>
#include <share.h>
#include <sys\stat.h>
int main () {
std::string szSource = "H:\\cpp\\test1.txt";
FILE* pfFile;
int iFileId = _sopen(szSource.c_str(),_O_RDONLY, _SH_DENYNO, _S_IREAD);
if (iFileId >= 0)
pfFile = fdopen(iFileId, "r");
//read file content to buffer
char * buffer;
size_t result;
long lSize;
// obtain file size:
fseek (pfFile , 0 , SEEK_END);
lSize = ftell (pfFile);
fseek(pfFile, 0, SEEK_SET);
// buffer = (char*) malloc (sizeof(char)*lSize);
buffer = (char*) malloc (sizeof(char)*lSize);
if (buffer == NULL)
{
return false;
}
// copy the file into the buffer:
result = fread (buffer,lSize,1,pfFile);
std::string szdes = "H:\\cpp\\test_des.txt";
FILE* pDesfFile;
int iFileId2 = _sopen(szdes.c_str(),_O_CREAT,_SH_DENYNO,_S_IREAD | _S_IWRITE);
if (iFileId2 >= 0)
pDesfFile = fdopen(iFileId2, "w+");
size_t f = fwrite (buffer , 1, sizeof(buffer),pDesfFile );
printf("Error code: %d\n",ferror(pDesfFile));
fclose (pDesfFile);
return 0;
}
You can make main file and try it see if its working for you .
Thanks
Change your code to the following and then report your results:
int main () {
std::string szSource = "H:\\cpp\\test1.txt";
int iFileId = _sopen(szSource.c_str(),_O_RDONLY, _SH_DENYNO, _S_IREAD);
if (iFileId >= 0)
{
FILE* pfFile;
if ((pfFile = fdopen(iFileId, "r")) != (FILE *)NULL)
{
//read file content to buffer
char * buffer;
size_t result;
long lSize;
// obtain file size:
fseek (pfFile , 0 , SEEK_END);
lSize = ftell (pfFile);
fseek(pfFile, 0, SEEK_SET);
if ((buffer = (char*) malloc (lSize)) == NULL)
return false;
// copy the file into the buffer:
result = fread (buffer,(size_t)lSize,1,pfFile);
fclose(pfFile);
std::string szdes = "H:\\cpp\\test_des.txt";
FILE* pDesfFile;
int iFileId2 = _sopen(szdes.c_str(),_O_CREAT,_SH_DENYNO,_S_IREAD | _S_IWRITE);
if (iFileId2 >= 0)
{
if ((pDesfFile = fdopen(iFileId2, "w+")) != (FILE *)NULL)
{
size_t f = fwrite (buffer, (size_t)lSize, 1, pDesfFile);
printf ("elements written <%d>\n", f);
if (f == 0)
printf("Error code: %d\n",ferror(pDesfFile));
fclose (pDesfFile);
}
}
}
}
return 0;
}
[edit]
for other posters, to show the usage/results of fwrite - what is the output of the following?
#include <stdio.h>
int main (int argc, char **argv) {
FILE *fp = fopen ("f.kdt", "w+");
printf ("wrote %d\n", fwrite ("asdf", 4, 1, fp));
fclose (fp);
}
[/edit]
sizeof(buffer) is the size of the pointer, i.e. 4 and not the number of items in the buffer
If buffer is an array then sizeof(buffer) would potentially work as it returns the number of bytes in the array.
The third parameter to fwrite is sizeof(buffer) which is 4 bytes (a pointer). You need to pass in the number of bytes to write instead (lSize).
Update: It also looks like you're missing the flag indicating the file should be Read/Write: _O_RDWR
This is working for me...
std::string szdes = "C:\\temp\\test_des.txt";
FILE* pDesfFile;
int iFileId2;
err = _sopen_s(&iFileId2, szdes.c_str(), _O_CREAT|_O_BINARY|_O_RDWR, _SH_DENYNO, _S_IREAD | _S_IWRITE);
if (iFileId2 >= 0)
pDesfFile = _fdopen(iFileId2, "w+");
size_t f = fwrite (buffer , 1, lSize, pDesfFile );
fclose (pDesfFile);
Since I can't find info about _sopen, I can only look at man open. It reports:
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
Your call _sopen(szdes.c_str(),_O_CREAT,_SH_DENYNO,_S_IREAD | _S_IWRITE); doesn't match either one of those, you seem to have flags and 'something' and modes / what is SH_DENY?
What is the result of man _sopen?
Finally, shouldn't you close the file descriptor from _sopen after you fclose the file pointer?
Your final lines should look like this, btw :
if (iFileId2 >= 0)
{
pDesfFile = fdopen(iFileId2, "w+");
size_t f = fwrite (buffer , 1, sizeof(buffer),pDesfFile ); //<-- the f returns me 4
fclose (pDesfFile);
}
Since you currently write the file regardless of whether or not the fdopen after the O_CREAT succeeded. You also do the same thing at the top, you process the read (and the write) regardless of the success of the fdopen of the RDONLY file :(
You are using a mixture of C and C++. That is confusing.
The sizeof operator does not do what you expect it to do.
Looks like #PJL and #jschroedl found the real problem, but also in general:
Documentation for fwrite states:
fwrite returns the number of full items actually written, which may be less than count if an error occurs. Also, if an error occurs, the file-position indicator cannot be determined.
So if the return value is less than the count passed, use ferror to find out what happened.
The ferror routine (implemented both as a function and as a macro) tests for a reading or writing error on the file associated with stream. If an error has occurred, the error indicator for the stream remains set until the stream is closed or rewound, or until clearerr is called against it.