open /dev/mem fail even with root and without SELINUX - linux

Just show my code.
root#MSI:/tmp# cat main.c
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
int fd = open("/dev/mem", O_RDONLY);
printf("Result: %d\n", fd);
if (fd != -1) {
close(fd);
} else {
perror("Failed:");
}
}
root#MSI:/tmp# gcc main.c
root#MSI:/tmp# ./a.out
Result: -1
Failed:: Operation not permitted
Root, without SELINUX, /dev/mem with crw-r----- permission, but open failed.
kernel version 5.4.0-49-generic #53-Ubuntu.

Related

ioctl() and file open mode

I wonder if I should open a file using mode O_RDONLY, O_WRONLY or O_RDWR before calling ioctl.
There are reading and writing ioctls. For example _IOC_DIR(VIDIOC_QUERYCAP) will return _IOC_READ.
So I thought when I am calling this ioctl I have to open the file O_RDONLY.
But surprisingly I can open the file with mode=0 and it's still working:
#include <stdio.h> // for printf()
#include <linux/videodev2.h> // for struct v4l2_capability
#include <fcntl.h> // for open()
#include <sys/ioctl.h> // for ioctl()
#include <unistd.h> // for close()
int main(int argc, char** argv)
{
int fd = open("/dev/video0", 0); // mode set to 0
if (fd == -1)
{
printf("open failed\n");
return 1;
}
struct v4l2_capability cap;
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1)
{
printf("ioctl failed\n");
close(fd);
return 1;
}
printf("%s\n", cap.card);
return 0;
}
So my question is how to set the mode properly. Maybe someone got a link to an official documentation.

LINUX_VERSION_CODE where the value from?

I just make a mistake about the macro LINUX_VERSION_CODE.
Here is what I want to do,when execute the code,the code run different branch due to the machine ,which is running.
I just realized,the result is not change,since I compile my code always in the same server.For example I compile the belw code in kernel version of 2.6.18,then the LINUX_VERSION_CODE marco is always 132626 .
If there is any way ,let the run different branch due to the version of which it runs?
#include <stdio.h>
#include <linux/version.h>
int main()
{
printf("kernel version(2.6.32) = %d\n",KERNEL_VERSION(2,6,32));
printf("LINUX_VERSION_CODE = %d\n",LINUX_VERSION_CODE);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
printf("Hello,world.\n");
#else
printf("Fine,thank you.\n");
#endif
return 0;
}
So you want to run a different code depending on kernel version. But you don't want to decide on that using a compile time constant - you want that at runtime.
Nothing simpler, but a call to uname:
#include <sys/utsname.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
struct utsname name;
if (uname(&name)) {
fprintf(stderr, "Uname failed!\n");
exit(-1);
}
printf("%s\n", name.release);
if (!memcmp(&name.release, "4.18.9-", sizeof("4.18.9-") - 1)) {
printf("Och, kernel 4.18.9 found!\n");
} else {
printf("Och, you've got a different kernel...\n");
}
}
On my machine:
$ cat 1.c | gcc -xc - && ./a.out
4.18.9-arch1-1-ARCH
Och, kernel 4.18.9 found!
On my friends machine:
cat 1.c | ssh friend 'gcc -xc - && ./a.out'
4.12.14-lp150.11-default
Och, you've got a different kernel...
I will leave it to the OP, to call strtoll or sscanf(&name.release, "%d.%d.%d-", &major, &minor, &release) to get the kernel version as integer number.
But you can get way more hardcore than that. On runtime, you can just do anything, so just read the content of /usr/include/linux/version.h file:
#define _GNU_SOURCE 1
#include <linux/version.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
FILE *f;
f = fopen("/usr/include/linux/version.h", "r");
if (f == NULL) return -__LINE__;
char *line = NULL;
size_t linelen = 0;
char *found = NULL;
while (getline(&line, &linelen, f) > 0) {
if ((found = strstr(line, "LINUX_VERSION_CODE")) != NULL) {
break;
}
}
if (found == NULL) return -__LINE__;
fclose(f);
found += sizeof("LINUX_VERSION_CODE") - 1;
errno = 0;
const long long kv = strtoll(found, NULL, 10);
if (errno) return -__LINE__;
free(line);
printf("%ld.%ld.%ld\n", kv>>16&0xff, kv>>8&0xff, kv&0xff);
if (kv > KERNEL_VERSION(4,17,0)) {
printf("Och, kernel api greater then 4.17.0 found!\n");
} else {
printf("Och, kernel api below 4.17.0 found!\n");
}
}
And on my machine this outputs:
$ cat 1.c | gcc -xc - && ./a.out
4.17.11
Och, kernel api greater then 4.17.0 found!
And on my friends:
$ cat 1.c | ssh friend 'gcc -xc - && ./a.out'
4.15.0
Och, kernel api below 4.17.0 found!
We can also see, that uname -a != grep "LINUX_VERSION_CODE" /usr/include/linux/version.h.

Memory mapped files failing in ecryptfs directory

On a regular ubuntu machine, the following test succeeds unless I run it in my home directory, in which case it crashes with a bus error. All I can think of is that it's because the home directory is encrypted. (I find Private and .ecryptfs links there.)
// Make with g++ -mcmodel=large -fPIC -g -O0 -o checkmm checkmm.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#define TALLIES "tallies.bin"
#define NUM_TALLIES (550588000/sizeof(int))
typedef struct { int tallies[NUM_TALLIES]; } World;
World* world;
void loadWorld() {
int fd = open(TALLIES, O_RDWR | O_CREAT);
if (fd == -1) { printf("Can't open tallies file %s\n", TALLIES); exit(0); }
fallocate(fd, 0, 0, sizeof(World));
world = (World*) mmap(0, sizeof(World), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (world ==(World*) -1) { printf("Failed to map tallies file %s\n", TALLIES); exit(1); }
}
void unloadWorld() { munmap(world, sizeof(World)); }
void resetWorld() {
int i;
for (i=0;i<NUM_TALLIES;i++) world->tallies[i]=-1;
}
int main() {
loadWorld();
resetWorld();
unloadWorld();
}
Can anyone elucidate?
You should check the return codes for each system call. Particularly fallocate() and mmap().
fallocate() is supported on a handful of filesystems. You should use ftruncate() if fallocate() fails (with errno set to EOPNOTSUPP).

inotify_add_watch relative to O_PATH dirfd

I am trying to call inotify_add_watch to watch a file. I would like to specify the file relative to an O_PATH | O_DIRECTORY file descriptor, a la symlinkat, fstatat, or openat.
Is this possible? It doesn't look like it is. Anyone know of a workaround?
EDIT
The closest thing seems to be the "trick" described at man 2 open under "Rationale for openat". See the answer by user1643723 for an example.
You can use symlinks, provided by procfs to achieve the functionality of most *at calls. Open a directory descriptor and use /proc/self/fd/<dir descriptor>/filename instead of the full path to filename:
#define _GNU_SOURCE
#include <sys/stat.h>
#include <sys/inotify.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
int main() {
int inotify = inotify_init();
mkdir("tmp", 0777);
mknod("tmp/foo", 0777 | S_IFREG, 0);
int dirFd = open("tmp", O_DIRECTORY | O_PATH);
char buf[40] = { '\0' };
sprintf(buf, "/proc/self/fd/%d/foo", dirFd);
int watchd = inotify_add_watch(inotify, buf, IN_MOVE | IN_ATTRIB);
if (watchd < 0) {
printf("Failed: %s", strerror(errno));
} else {
printf("ok");
}
}
The program above prints "ok" on Linux 4.4.x.

Linux: unable to retrieve process name from pid via ioctl

I'm trying to retrieve retrieve process name from pid via ioctl, this is the C code:
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/signal.h>
#include <sys/syscall.h>
#include <sys/procfs.h>
#include <stdio.h>
#include <signal.h>
#include <elf.h>
#include <stdlib.h>
#include <errno.h>
int main(int argc, char **argv) {
char ProcID[50]="/proc/";
int fd;
prpsinfo_t ProcessInfo;
int ioctlResult;
if ( argc != 2 ) {
printf("usage: %s <pid>\n", argv[0]);
return 0;
}
strcat(ProcID,argv[1]);
fd = open(ProcID, O_RDONLY, 0);
if (fd == -1) {
printf("open error: [%d] [%s]\n",errno, strerror(errno));
return 0;
}
ioctlResult = ioctl(fd, NT_PRPSINFO, &ProcessInfo);
if (ioctlResult == -1)
{
printf("Error ioctl: [%d] [%s]\n",errno, strerror(errno));
} else {
printf("Process name: %s\n",ProcessInfo.pr_fname);
}
close(fd);
return 0;
}
When I try to execute it I obtain errno 25 (Inappropriate ioctl for device). I think the file descriptor open on "/proc/" isn't correct; is there another path to consider ?

Resources