Write to /dev/port as non-root user - linux-kernel

I am working on a rather complex C++ code which performs the following operation as standard user
fd = open("/dev/port",O_WRONLY);
...
lseek(fd, 0x2E,SEEK_SET);
...
write(fd,&buf,1);
I get a 'Operation not permitted' error on opening the file, despite having chmodded the file.
crwxrwxrwx 1 root kmem 1, 4 Sep 12 14:32 /dev/port
I know of security issues with chmodding /dev/port, but as far as we're concerned the system will run on a closed LAN.
To make it easier, this:
using namespace std;
int main(int argc, char *argv[])
{
int fd=-1;
// fd1=open("/dev/port",O_RDWR|O_NDELAY);
vector<string> fnames;
fnames.push_back("/dev/port");
fnames.push_back("/dev/tty0");
string fname;
for(int i=0;i<fnames.size();i++)
{
fname = fnames[i];
fd=open(fname.c_str(),O_RDWR | O_NDELAY);
if(fd<0)
{
cout << fname << " " << fd << endl;
cout << fname << " " << strerror(errno) << endl;
}
else
{
cout << "Open ok: " << fname << endl;
}
}
return 0;
}
returns this:
me#myPC:~/test$ ./main
/dev/port -1
/dev/port Operation not permitted
Open ok: /dev/tty0
with these permission rights
me#myPC:~/test$ ll /dev/tty /dev/port
crw-rw-rw- 1 root kmem 1, 4 Sep 12 14:32 /dev/port
crw-rw-rw- 1 root tty 5, 0 Sep 12 15:51 /dev/tty

To open /dev/port you need the capability CAP_SYS_RAWIO, in addition to permission to open the file.
drivers/char/mem.c:730
static int open_port(struct inode * inode, struct file * filp)
{
return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
}
You can either gain this by being root or by setting it for a single executable (similar to set-uid) using setcap.
http://linux.die.net/man/8/setcap

Related

Create-Delete directory in a loop - returns success but was not complete at that time

( reported here
https://superuser.com/questions/1511981/windows-10-creating-and-deleting-directory-in-remote-location-netapp-in-a-loop this time with some more data and example program )
I am working on an issue - Create and deletion of directory on a loop in a small window gets incorrect response from API - it says directory deleted (returns true) but it stays there for some more time(say 20-30 milliseconds).
What can cause? The program runs fine on Windows 7 (NetApp storage or local disk). Windows 10 passes with local disk; but fails with NetApp storage. Need to sleep get the API (DeleteDirectory correct )
Wrote a code to reproduce in windows , c program (because admins wanted that way to rule out java, powershell etc )
#include "pch.h"
#include <iostream>
#include <cstdlib>
#include <windows.h>
#include <direct.h>
using namespace std;
int main()
{
const char* sleepTimeAsString = std::getenv("SLEEP_TIME_MILLIS");
const char* remoteRoot = std::getenv("REMOTE_UNC_PATH");
if (sleepTimeAsString == NULL) {
std::cout << "env SLEEP_TIME_MILLIS needed: " << '\n';
}
if (remoteRoot == NULL) {
std::cout << "env REMOTE_UNC_PATH needed: " << '\n';
}
std::cout << "set REMOTE_UNC_PATH=" << remoteRoot << '\n';
std::cout << "set SLEEP_TIME_MILLIS=" << sleepTimeAsString << '\n';
CreateDirectory(remoteRoot,NULL);
std::cout << "version 0.10 " << '\n';
std::cout << "created " << remoteRoot << '\n';
string path = remoteRoot;
string mynode = "/childdirectory";
string path2 = path + mynode;
DWORD error= GetLastError();
std::cout << error << '\n';
long sleepTime = atol(sleepTimeAsString);
for (int i = 0; i < 1000; i++) {
std::cout << "loop "<< i << '\n';
if (!CreateDirectory( path2.c_str(), NULL)) {
DWORD errorlooped = GetLastError();
std::cout <<"failed to create " << errorlooped << '\n';
exit(-1);
}
else {
std::cout << "success created " << path2.c_str() << '\n';
}
Sleep(sleepTime);
if (!RemoveDirectory(path2.c_str())) {
DWORD errorlooped = GetLastError();
std::cout << "failed remove "<< errorlooped << '\n';
exit(-1);
}
else {
std::cout << "success deleted " << path2.c_str() << '\n';
}
Sleep(sleepTime);
}
}
Result table: Once I provide sufficient sleep between calls the test started passing on this NetApp directory.
OS Disk Sleep Time(ms) Result
Win7 Local 0 PASS
Win7 Remote 0 PASS
WIn10 Local 0 PASS
WIn10 Remote (NetApp) 0 FAIL
WIn10 Remote (NetApp) 10 FAIL
WIn10 Remote (NetApp) 20 FAIL
WIn10 Remote (NetApp) 40 PASS
What should I investigate more on this issue (before getting back to System administrators ) - Ideas welcome.

Full duplex named pipe lockup when written to

I'm trying to use one NamedPipe for bi-direction IPC. In my mind (and I can't find more information on MSDN), one full-duplex pipe would be sufficient. Here's my code.
//Compiled with these commands during my test:
//g++ -DCLIENT -o client.exe xxx.cpp
//g++ -DSERVER -o server.exe xxx.cpp
#include <iostream>
#include <windows.h>
using namespace std;
DWORD WINAPI ReadingThread(LPVOID a)
{
HANDLE pipe = (HANDLE)a;
BOOL result;
char buffer[256];
DWORD numBytesRead;
while (true)
{
result = ReadFile(pipe, buffer, sizeof(buffer) - 1, &numBytesRead, NULL);
if (result)
{
buffer[numBytesRead] = 0;
cout << "[Thread] Number of bytes read: " << numBytesRead << endl;
cout << "[Thread] Message: " << endl
<< buffer << endl
<< endl;
}
else
{
cout << "[Thread] Failed to read data from the pipe. err=" << GetLastError() << endl;
break;
}
}
return 0;
}
int main(int argc, const char **argv)
{
#ifdef CLIENT
cout << "[Main] Connecting to pipe..." << endl;
HANDLE pipe = CreateFileA("\\\\.\\pipe\\PipeTest", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
#else
cout << "[Main] Creating an instance of a named pipe..." << endl;
HANDLE pipe = CreateNamedPipeA("\\\\.\\pipe\\PipeTest", PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE, 1, 0, 0, 0, NULL);
#endif
if (pipe == NULL || pipe == INVALID_HANDLE_VALUE)
{
cout << "[Main] Failed to acquire pipe handle." << endl;
return 1;
}
#ifdef CLIENT
#else
cout << "[Server] Waiting for a client to connect to the pipe..." << endl;
BOOL result = ConnectNamedPipe(pipe, NULL);
if (!result)
{
cout << "[Server] Failed to make connection on named pipe." << endl;
CloseHandle(pipe);
return 1;
}
cout << "[Server] Client is here!" << endl;
{
const char *buf = "Hello pipe!\n";
WriteFile(pipe, buf, strnlen(buf, 30), 0, 0);
}
#endif
CreateThread(0, 0, ReadingThread, pipe, 0, 0);
cout << "[Main] Ready to send data." << endl;
while (true)
{
char buffer[128];
DWORD numBytesWritten = 0;
BOOL result;
cin >> buffer;
if (!strcmp(buffer, "q"))
{
break;
}
cout << "[Main] Writing data to pipe..." << endl;
result = WriteFile(pipe, buffer, strnlen(buffer, _countof(buffer)), &numBytesWritten, 0);
if (result)
{
cout << "[Main] Written " << numBytesWritten << " bytes to the pipe." << endl;
}
else
{
cout << "[Main] Failed to write data to the pipe. err=" << GetLastError() << endl;
}
}
CloseHandle(pipe);
cout << "[Main] Done." << endl;
return 0;
}
I can get the "Hello pipe!" message from server-side to client-side. And I'm expecting to type some string on either program's terminal and press enter, and see it on the other side.
However after the hello message, both program will stuck on the WriteFile call. Meanwhile the thread is stuck at the ReadFile call. How can I make it work, or did I left something out?
when file created for synchronous I/O (flag FO_SYNCHRONOUS_IO present in FILE_OBJECT ) all I/O operations on file is serialized - new operation will be wait in I/O manager before passed to driver, until current(if exist) not complete. in concurrent can execute only single I/O request. if we do blocked read in dedicated thread - all another I/O request on this file will be blocked until read not complete. this related not only to write. even query file name/attributes will block here. as result render reading in separate not help here - we block on first write attemp. solution here use asynchronous files - this let any count of I/O operation execute in concurrent.
Named Pipes in Windows are HALF DUPLEX. As demonstrated on Windows 10. The MSDN Documentation is Wrong. A request has been submitted to Microsoft to correct their documentation.
While a pipe can be opened on the client to be "Generic Read | Generic Write" you can NOT do both at the same time.
And Overlapped IO submitted after the First Overlapped IO will break the pipe.
You can submit overlapped io. Then Wait for it to finish. Then submit the next overlapped io. You can not simultaneously Submit overlapped Reads AND overlapped Writes.
This is by definition, "Half Duplex".

why does my code skip the if statement and go to the else when i open the file

my assignment asks me to open a file, but if it doesn't open you are given 3 tries, but when I input the correct file on my second and third try it still give me the error I wrote 'ERROR: File " << input_filename << " could not be opened for input"' and goes to my else statement
char input_filename[90];
ifstream input;
cout << "Type the name of the input file which will hold the simulation results : " << endl;
cin>> input_filename;
input.open(input_filename);
if (input.fail())//if the file doesn't open it will go to the do while loop error message
{
int i = 0;
int h = 0;
do
{
cout << "ERROR: File " << input_filename << " could not be opened for input" << endl;
cin >> input_filename;// allows user to reinput filename
input.open(input_filename);//opens file
if ( !input.fail())
{
cout << "if statement" << endl;
h++;// if h doesn't equal 1 it goes out of the loop
}
else
{
cout << "else statement" << endl;
i++;//post-decrement allows for 2 more tries to input file
}
if (i >= 2)
{
cout << "ERROR: You exceeded maximum number of tries allowed" << endl;
cout << "while entering the input file name" << endl;
return 1;// return 1 represents the error of the input not opening after the 3rd time of inputing
}
} while (i < 2 && h != 0);// do while because it need to be a post condition for two varibles
}
If you reach line 106, it implies your file input succeeded. At that line you should NOT increment h. In fact you should leave h at zero if you want to break out of the loop (Assuming the file input worked).

Reading Data from a Physical Hard Drive

I am trying to develop a program that goes and finds 2 connected unformatted physical drives and read bytes. The program currently runs in the administrator mode since that's the only way I guess the program can see unformatted hard drives. I am using visual studio 2015 and it runs in windows 7 machine.
The problem is that it can only read multiples of 512 (512 is the sector size). Currently the unformatted hard drives are located in disk 2 and 3 slots (they are both SSDs). It first reads 512 bytes (works without an issue) and doesn't do any more reads if it's a formatted hard drive. If it's an unformatted hard drive it goes ahead and read more bytes. If it's hard drive A it then reads the next 1024 bytes and it works (read_amount = 1024). If it's hard drive B it then reads the next 1025 bytes and it doesn't work (read_amount = 0). I am not sure why it can't read a multiple of a 512/sector sizes. My understanding is that when you call "CreateFile()" function with dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, I should be able to read sizes that are not multiples of sector sizes (if you use FILE_FLAG_NO_BUFFERING then you can only read multiples of 512 and I am NOT using that flag). See my code below.
// Hard_Drive_Read.cpp : Defines the entry point for the console application.
// This program assumes you have EXACTLY TWO unformatted hard drives connected to your computer.
#include <Windows.h>
#include <io.h>
#include <fcntl.h>
#include <fstream>
#include <iostream>
#include <iomanip>
using namespace std;
int main(int argc, char *argv[])
{
if (argc != 3)
{
cout << "Need to enter 2 arguments" << endl;
exit(0);
}
int frames_to_process = atoi(argv[2]);
if (frames_to_process < 1)
{
cout << "invalid argument 2" << endl;
exit(0);
}
//HANDLE hDisk_A;
//HANDLE hDisk_B;
LPCTSTR dsksrc = L"\\\\.\\PhysicalDrive";
wchar_t dsk[512] = L"";
bool channel_A_found = false;
bool channel_B_found = false;
char frame_header_A[1024];
char frame_header_B[1025];
HANDLE hDisk;
char buff_read[512];
DWORD read_amount = 0;
for (int i = 0; i < 4; i++)
{
swprintf(dsk, 511, L"%s%d", dsksrc, i);
hDisk = CreateFile(dsk, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hDisk == INVALID_HANDLE_VALUE)
{
printf("%s%d%s", "couldn't open the drive ", i, "\n");
CloseHandle(hDisk);
}
else
{
printf("%s%d%s", "successfully open the drive ", i, "\n");
BOOL read_success_1 = ReadFile(hDisk, buff_read, 512, &read_amount, NULL);
cout << "read amount 1 - " << read_amount << endl;
if ((read_success_1 == TRUE) && (read_amount == 512))
{
if ((buff_read[510] == (char)0x55) && (buff_read[511] == (char)0xAA)) // test for a formatted drive; is there other identifiers?
{
cout << i << " is a formatted drive" << endl;
}
else
{
cout << "Not a formatted drive, trying to find sync " << endl;
ofstream writeBinary_Test;
if (i == 2)
{
writeBinary_Test.open("file_A_test.bin", ofstream::out | ofstream::binary);
ReadFile(hDisk, frame_header_A, 1024, &read_amount, NULL);
cout << "read amount " << read_amount << endl;
writeBinary_Test.write(frame_header_A, 1024);
writeBinary_Test.close();
}
else if(i == 3)
{
writeBinary_Test.open("file_B_test.bin", ofstream::out | ofstream::binary);
ReadFile(hDisk, frame_header_B, 1025, &read_amount, NULL);
cout << "read amount " << read_amount << endl;
writeBinary_Test.write(frame_header_B, 1025);
writeBinary_Test.close();
}
LARGE_INTEGER distanceToMove;
SetFilePointerEx(hDisk, distanceToMove, NULL, FILE_BEGIN);
}
}
else
{
}
}
if (channel_A_found && channel_B_found)
{
cout << "both drives found" << endl;
break;
}
}
if ((channel_A_found == false) || (channel_B_found == false))
{
cout << "Couldn't Find Hard Drive A or Drive B or Both" << endl;
cout << "Exiting the program" << endl;
exit(0);
}
CloseHandle(hDisk);
return 0;
}
Eventually, I want to use SetFilePointerEx() to move around the hard drive and I the program has to work with and data size (not multiples of 512). Therefore, it's imperative I can read sizes that's not multiples of 512. Any ideas of how to fix this program? Am I using my flags properly?
Any help is much appreciated!
The documentation for CreateFile says:
Volume handles can be opened as noncached at the discretion of the particular file system, even when the noncached option is not specified in CreateFile. You should assume that all Microsoft file systems open volume handles as noncached. The restrictions on noncached I/O for files also apply to volumes.
Although it doesn't spell it out explicitly, this applies to drives as well as to volumes.
In practice, this isn't a problem. It is straightforward to write a helper function that returns an arbitrary amount of data from an arbitrary offset, while performing only aligned reads.
It's imperative I can read sizes that's not multiples of 512.
That is not possible. For direct access of a disk, you can only read and write multiples of the sector size. Furthermore, you must align your read and write operations. That is the file pointer must be at a multiple of the sector size.
If you want to present an interface that allows arbitrary seeking, reading and writing, then you will need to implement your own buffering on top of the aligned raw disk access.

std::cout seems to be printing out an extra "|" when called initially

I am working on a portion of my code that is suppose to output the error message correctly.
Please see below screenshot, I am using on bash
./myProgram < input3a.in | diff -a -y output3a.out -
Left hand side is what I want to get to.
For some reason an extra "|" is printed before the char array 'line' is printed. I suspected that maybe the char array 'line' is not null terminated. but it is initialize by cin.getline(); which should null terminate the char array.
Here i try to print the 'line' array in my main procedure, and it left the | sign on the line before it.
my question is. why does std::cout display this behaviour?
Thanks
EDIT,
Below is my code in question. Thanks for taking a look again.
#include "char_stack.h"
#include <iostream>
void printErrorLine(int errorSpot, int c_count, char line[]){
//Print the first line of error message char by char, at the
//same time replace char with \t or space
for(int x = 0; x <= errorSpot; x++){
std::cout << line[x];
if(line[x] != '\t'){
line[x] = ' ';
}
}
std::cout << std::endl;
//Print out the second line, if the first line does not have a
//errorSpot, then dont print it
if(errorSpot != c_count){
std::cout << line << std::endl;
}
}
char findCounterPart(char bracket){
//pass.
}
int main(int argc, char * argv[]){
char line[250]; // 250 because spec sheet detailed max 250 char per line.
char c;
int l_count = 0; // number of lines already read
int c_count; // character count in a line
char_stack S;
bool isError;
while(!std::cin.peek() == std::cin.eof()){
std::cin.getline(line, 250);
c_count = std::cin.gcount();
l_count +=1;
//std::cout<< c_count << std::endl << std::endl;
//loop through the line
for(int x = 0; x < c_count; x++){
c = line[x];
//std::cout << c << " stack size is " << S.size() << std::endl;
if (c == '(' ||
c == '{' ||
c == '['){
S.push(c);
}
else if(c == ')' ||
c == '}' ||
c == ']'){
if(S.empty()){
std::cout << "Error on line " << l_count << ": Too many " << c << std::endl;
isError = true;
}
else{
char l = S.pop();
if(l != findCounterPart(c)){
std::cout << "Error on line " << l_count << ": Read " << c <<
", expected " << findCounterPart(l) << std::endl;
isError = true;
}
}
}
if (isError){
printErrorLine(x, c_count ,line);
return 0;
}
}
}
if (!S.empty()){
c = S.pop();
std::cout << "Error on line " << l_count << ": Too many " << c << std::endl;
printErrorLine(c_count, c_count , line);
}
else{
std::cout <<"No Errors Found" << std::endl;
}
return 0;
}
Learning to be a software engineer is about breaking problems down into manageable chunks, and here we have a couple of doosies. Lets rephrase your question slightly:
I am getting unexpected characters displayed when diff the output of my program against a file containing output of a previous run. Currently I think this is because of some weird behavior of std::cout.
Well, that might be a reasonable assumption, we can't see your code so we can't know if you're doing anything peculiar.
But it would have to be: std::cout is used, well, all over the place. It just doesn't have this behavior unless your code is deliberately writing a | somewhere.
There are a number of steps we could take to resolve this:
Run the program a 3rd time in the debugger and step through until you have some ideas where the '|' is appearing,
Run the program a 3rd time to the console and observe the output,
View the output using a command like cat, less or more, instead of diff
3 is perhaps the most sensible place to start, since the file is already right there and after that #2 will give us a mk1eyeball check.
What we find is: the | does not appear in the file or the output. It's not coming from your program.
Lets create a couple of .txt files and diff them:
osmith#WOTSIT MINGW64 ~
$ echo -e 'First line\nSecond line' >test1.txt
osmith#WOTSIT MINGW64 ~
$ echo -e 'First line\nFile two line 2' >test2.txt
osmith#WOTSIT MINGW64 ~
$ diff -a -y test1.txt test2.txt
First line First line
Second line | File two line 2
When using the -y switch, between the two columns of output, diff has a line of special characters to indicate lines that changed, were inserted or deleted.

Resources