Cannot access EFS file programmatically with 32bits executable (on a 64bits OS) - c

I've got a problem accessing files programmatically on an Amazon EFS filesystem : the same C program will work with a 64 bits executable, but not with a 32bits executable.
Mount point is /EFS, the program below will list both EFS directory (/EFS/data) and local directory (/home/centos) :
Here is the test program :
#include <stdio.h>
#include <dirent.h>
int main(void) {
struct dirent *d;
char efs_dir[] = "/EFS/data";
char local_dir[] = "/home/centos";
printf("EFS dir : %s\n",efs_dir);
DIR *dirEFS = opendir(efs_dir);
if (dirEFS == NULL) {
printf("Could not open current directory");
return 1;
}
while ((d = readdir(dirEFS)) != NULL)
printf("%s\n", d->d_name);
closedir(dirEFS);
printf("\nlocal filesystem dir : %s\n",local_dir);
DIR *dirLOCAL = opendir(local_dir);
if (dirLOCAL == NULL) {
printf("Could not open current directory");
return 1;
}
while ((d = readdir(dirLOCAL)) != NULL)
printf("%s\n", d->d_name);
closedir(dirLOCAL);
return 0;
}
Unix view :
[centos#ec2-instance ~]$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p1 20G 3.4G 16G 19% /
tmpfs 3.7G 0 3.7G 0% /dev/shm
/dev/nvme1n1p1 94G 6.1G 83G 7% /opt/data
fs-XXXXXXXX.eu-west-3.amazonaws.com:/
8.0E 5.3G 8.0E 1% /EFS
[centos#ec2-instance ~]$]$ ls -l /EFS/data
-rw-r--r-- 1 centos centos 2796 Sep 15 12:18 efs_file1.txt
-rw-r--r-- 1 centos centos 2812 Sep 15 12:18 efs_file2.txt
-rw-r--r-- 1 centos centos 3625 Sep 15 12:18 efs_file3.txt
-rw-r--r-- 1 centos centos 2768 Sep 15 12:18 efs_file4.txt
[centos#ec2-instance ~]$]$ ls -l /home/centos
-rw-rw-r-- 1 centos centos 2796 Sep 15 14:15 local_file1.txt
-rw-rw-r-- 1 centos centos 2812 Sep 15 14:15 local_file2.txt
-rw-rw-r-- 1 centos centos 3625 Sep 15 14:15 local_file3.txt
-rw-rw-r-- 1 centos centos 2768 Sep 15 14:15 local_file4.txt
-rw-r--r-- 1 centos centos 792 Sep 15 14:21 test_dir.c
-rwxrwxr-x 1 centos centos 7392 Sep 15 14:22 test_dir
When I compile test_dir.c in 32 bits compatibility mode, no results for the EFS directory :
[centos#ec2-instance ~]$ gcc test_dir.c -o test_dir -m32
[centos#ec2-instance ~]$ ./test_dir
EFS dir : /EFS/data
local filesystem dir : /home/centos
test_dir
.
..
local_file1.txt
local_file2.txt
local_file3.txt
local_file4.txt
test_dir.c
But for 64 bits executable it is fine :
[centos#ec2-instance ~]$ gcc test_dir.c -o test_dir
[centos#ec2-instance ~]$ ./test_dir
EFS dir : /EFS/data
.
..
efs_file1.txt
efs_file2.txt
efs_file3.txt
efs_file4.txt
local filesystem dir : /home/centos
test_dir
.
..
local_file1.txt
local_file2.txt
local_file3.txt
local_file4.txt
test_dir.c
Anyone has an idea of what is happening here ?
Thanks.
edit (solution) : compress the 64 bits inodes number to 32 bits with the kernel option nfs.enable_ino64=0
[root#eai ~]# cat /etc/modprobe.d/nfs.conf
options nfs enable_ino64=0
[root#eai ~]# reboot
and it's done ! Thanks DNT.

Function readdir returns an inode. In your 32bit build it expects to find 32bit inodes. But with a file system with 64bit inodes it will fail if the particular inode number cannot be expressed in 32bits.
To see the inode numbers you may want to use ls -li /EFS/data/efs_file1.txt. The leftmost number is the inode number and if it exceeds 4294967295 then it is 64bit and 32bit readdir cannot handle it.

Related

Why does the return value -1 become 4294967295 when return type is int64_t?

In this code, I have a function whose return value is -1, but when assigned to int64_t type, the value obtained is 4294967295 instead of -1, but when assigned to int32_t type, it is -1. The return value of that zip_name_locate is of type int (4 bytes on my system). why is that?
#include <inttypes.h>
#include <stdio.h>
#include <zip.h>
int main() {
const char * path = "/home/www/api/default/current/public/static/doc/test.xlsx";
int error = ZIP_ER_NOENT;
zip_t* zip = zip_open(path, ZIP_RDONLY, &error);
int32_t n = zip_name_locate(zip, "xl/worksheets/_rels/sheet2.xml.rels", ZIP_FL_NODIR);
printf("%d\n", n);
int64_t j = zip_name_locate(zip, "xl/worksheets/_rels/sheet2.xml.rels", ZIP_FL_NODIR);
printf("%" PRId64 "\n", j);
return 0;
}
output:
-1
4294967295
This is my system information:
➜ ~ uname -r
3.10.0-1062.12.1.el7.x86_64
➜ ~ cat /etc/redhat-release
CentOS Linux release 7.7.1908 (Core)
➜ ~ gcc --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Thanks for answering, here are some answers to your questions:
About libzip, Because this is related to a bug I encountered in the process, so I need to use zip
My system is 64bit CentOS 7.7
zip_name_locate does return zip_int64_t type
I printed n and j in gdb, n is -1, j is 4196160, it seems that gdb cannot print integers of type int64_t, but this output indicates that j should not be -1
Because we used an old version of libzip in a certain environment and caused a bug, so we wanted to find the most fundamental reason, we used the built-in version 0.11
PRId64 is ld on my system
int64_t j = -1; and int64_t j = (int64_t)((zip_int64_t)-1); successful conversion
sizeof(long) is 8
I made a mistake. On my system, I have an old version of libzip and a new version of libzip, but when I tried to introduce the old version of libzip with the -L flag, the new version was actually introduced. The method I compiled is
gcc -L /usr/lib64 -lzip test1.c -o test and /usr/lib64 is where the old version of libzip dynamic shared library is located.
In my system, there are some libzip library files under /usr/lib64 and /usr/local/lib64, the old version under /usr/lib64, and the new version under /usr/local/lib64:
ls -lh /usr/local/lib64/libzip.so*
lrwxrwxrwx 1 root root 11 Jun 1 22:21 /usr/local/lib64/libzip.so -> libzip.so.5
lrwxrwxrwx 1 root root 13 Jun 1 22:21 /usr/local/lib64/libzip.so.5 -> libzip.so.5.3
-rwxr-xr-x 1 root root 162K Jun 1 23:18 /usr/local/lib64/libzip.so.5.3
ls -lh /usr/lib64/libzip.so*
-rwxr-xr-x 1 root root 57K Jun 2 00:02 /usr/lib64/libzip.so
lrwxrwxrwx 1 root root 11 Jun 2 00:07 /usr/lib64/libzip.so.2 -> libzip.so.5
-rwxr-xr-x 1 root root 57K Jun 2 00:02 /usr/lib64/libzip.so.2.1.0
-rwxr-xr-x 1 root root 57K Jun 2 00:02 /usr/lib64/libzip.so.5
I learned that the objdump command can check which shared libraries are dependent, so I checked it out and the following is the output:
objdump -p test | grep so
NEEDED libzip.so.2
NEEDED libc.so.6
required from libc.so.6:
Then I checked through ldconfig and found that libzip.so.2 points to the new version:
ldconfig -v | grep libzip
libzip.so.5 -> libzip.so.5.3
libzip.so.2 -> libzip.so.5
So in my question, it was based on a wrong judgment from the beginning, leading to incomprehensible imagination. If you are using a new version of libzip, the return value of zip_name_locate of libzip in the new version is zip_int64_t. This type is int64_t type on my system. When the 4294967295 return value of this type is assigned to int32_t, it causes overflow, so would be -1, and j would be 4294967295.

Cannot use function cpuset_create from shared C library <cpuset.h>

I am trying to port a C project from a CentOS 7 (Core) to an Ubuntu 20.04.1 LTS (Focal Fossa) system. The program compiles and runs without problem on CentOS and also compiles without error on the Ubuntu system. However, when I try to execute the program on Ubuntu, I encounter the following error:
ERROR aff_prog_alloc #aff-executor.c:299 => cpuset_create: No such file or directory
The function cpuset_create is part of the <cpuset.h> library and the flag -lcpuset is included when compiling. The following is the output from the ldd command, showing the path for the <cpuset.h> library on our Ubuntu system:
$ ldd ./aff-executor
linux-vdso.so.1 (0x00007ffed97eb000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f8c179d5000)
libcpuset.so.1 => /lib/x86_64-linux-gnu/libcpuset.so.1 (0x00007f8c177c8000)
libbitmask.so.1 => /lib/x86_64-linux-gnu/libbitmask.so.1 (0x00007f8c175c4000)
libnuma.so.1 => /lib/x86_64-linux-gnu/libnuma.so.1 (0x00007f8c175b7000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f8c175ac000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8c173ba000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8c17a22000)
I verified that the library actually exists at this location:
$ll /lib/x86_64-linux-gnu/libcpuset.*
-rw-r--r-- 1 root root 67952 Nov 21 2016 /lib/x86_64-linux-gnu/libcpuset.a
lrwxrwxrwx 1 root root 18 Nov 21 2016 /lib/x86_64-linux-gnu/libcpuset.so -> libcpuset.so.1.1.0
lrwxrwxrwx 1 root root 18 Nov 21 2016 /lib/x86_64-linux-gnu/libcpuset.so.1 -> libcpuset.so.1.1.0
-rw-r--r-- 1 root root 52232 Nov 21 2016 /lib/x86_64-linux-gnu/libcpuset.so.1.1.0
Can anyone help with identifying why cpuset_create does not work on this system despite it having the correct syntax and inputs?
==================================
Update/Additional Info
The following code is what I need to use for my project. Everything works fine until the cpuset_create function which has been returning -1. I checked this program on a different Ubuntu (16.04.5 LTS (Xenial Xerus)) and it executed without problem on it, with cpuset_create returning the expected 0.
#define _GNU_SOURCE
#include<stdio.h>
#include <bitmask.h>
#include <cpuset.h>
#include <errno.h>
#include<numa.h>
typedef struct cpuset cpuset_t;
struct bitmask * get_mems_all(void);
/* return a bitmask describing all the available memory nodes */
struct bitmask * get_mems_all(void)
{
struct bitmask *ret;
if (numa_available() != -1){
printf("NUMA is available\n");
return numa_get_mems_allowed();
}
ret = bitmask_alloc(cpuset_mems_nbits());
printf("ret: %p\n",ret );
if (!ret)
printf("bitmask_alloc err");
bitmask_setbit(ret,0);
return ret;
}
int main(){
int err;
struct bitmask *mem_bm;
mem_bm=get_mems_all();
printf("mem_bm: %p\n",mem_bm );
numa_bitmask_clearbit(mem_bm, 1);
numa_bitmask_setbit(mem_bm,0);
char buff[256];
bitmask_displaylist(buff, sizeof(buff), mem_bm);
printf("buff: %s\n",buff );
printf("mem_bm: %p\n",mem_bm );
printf("cpuset lib version: %d\n",cpuset_version() );
cpuset_t *cpuset=cpuset_alloc();
printf("cpuset: %p\n",cpuset );
err = cpuset_setmems(cpuset,mem_bm);
printf("err cpuset_setmems: %d\n", err);
char* path="/AFF_1000/";
err = cpuset_create(path, cpuset);
printf("err cpuset_create: %d\n", err);
return 0;
}
Compilation:
gcc -Wall -O2 -std=gnu99 test.c -o test -lcpuset -lbitmask -lnuma
Output on Ubuntu 20.04.1 LTS (Focal Fossa):
$./test
NUMA is available
mem_bm: 0x55a34b2ac120
buff: 0
mem_bm: 0x55a34b2ac120
cpuset lib version: 3
cpuset: 0x55a34b2ac1d0
err cpuset_setmems: 0
err cpuset_create: -1
Expected output (this is from Ubuntu 16.04LTS (Xenial Xerus)):
$./test
NUMA is available
mem_bm: 0x1c39670
buff: 0
mem_bm: 0x1c39670
cpuset lib version: 3
cpuset: 0x1c396b0
err cpuset_setmems: 0
err cpuset_create: 0
$cset set -l
cset:
Name CPUs-X MEMs-X Tasks Subs Path
------------ ---------- - ------- - ----- ---- ----------
root 0-63 y 0-1 y 500 2 /
AFF_1000 ***** n 0 n 0 0 /AFF_1000
system 0-63 n 0 n 349 0 /system
However, I am unable to run the same program as root on Ubuntu 16.04 as well. I get the following error:
sudo ./test
./test: error while loading shared libraries: libcpuset.so.1: cannot open shared object file: No such file or directory
Does anyone know why this is happening? I do not know if this last problem is related to why my program won't run on the Ubuntu 20.04.

Is there a way to increase the maximum amount of messages that can be contained in a SysV message queue?

I just switched from POSIX to SysV because the limit is much higher on SysV (1024 vs 10). But I still need an higher limit. The limit should be changed at runtime, because it depends on the data the user chooses.
Using POSIX, it was possible to increase the limit but it was necessary to run the code as root every time and I cannot do that.
Is there a way to increase the limit in SysV?
As SYSV IPC are considered deprecated, it is a pity to design brand new applications with thoses old fashioned services.
POSIX message queues are based on a file system. It is usually mounted on /dev/mqueue:
$ ls -la /dev/mqueue
total 0
drwxrwxrwt 2 root root 40 dec. 25 21:02 .
drwxr-xr-x 20 root root 4600 dec. 25 20:51 ..
A message queue is created with mq_open(). The attr parameter provides the ability to set some attributes:
struct mq_attr {
long mq_flags; /* Flags (ignored for mq_open()) */
long mq_maxmsg; /* Max. # of messages on queue */
long mq_msgsize; /* Max. message size (bytes) */
long mq_curmsgs; /* # of messages currently in queue (ignored for mq_open()) */
};
According to the documentation, the /proc/sys/fs/mqueue/msg_max file defines the ceiling value for the maximum number of messages in a queue. In Linux 5.4, its default value is DFLT_MSGMAX (10) and its upper limit is HARD_MSGMAX (65536).
The defaults values are defined in the Linux source code (cf. /include/linux/ipc_namespace.h):
#define DFLT_QUEUESMAX 256
#define MIN_MSGMAX 1
#define DFLT_MSG 10U
#define DFLT_MSGMAX 10
#define HARD_MSGMAX 65536
#define MIN_MSGSIZEMAX 128
#define DFLT_MSGSIZE 8192U
#define DFLT_MSGSIZEMAX 8192
#define HARD_MSGSIZEMAX (16*1024*1024)
Here is an example program which creates a message queue. It receives as parameters the message queue name and the maximum number of messages in the queue:
#include <errno.h>
#include <pthread.h>
#include <mqueue.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
mqd_t mqdes;
struct mq_attr attr;
if (argc != 3) {
fprintf(stderr, "Usage: %s <mq-name> <msg_max>\n", argv[0]);
exit(EXIT_FAILURE);
}
attr.mq_flags = 0;
attr.mq_maxmsg = atoi(argv[2]);
attr.mq_msgsize = 2048;
attr.mq_curmsgs = 0;
mqdes = mq_open(argv[1], O_CREAT | O_RDWR, 0777, &attr);
if (mqdes == (mqd_t) -1) {
perror("mq_open");
return 1;
}
return 0;
}
At execution time we can verify that, by default, we can't go above 10 messages for the queue:
$ gcc mq.c -o mq -lrt
$ ./mq
Usage: ./mq <mq-name> <msg_max>
$ ./mq /q0 5
$ ls -la /dev/mqueue/
total 0
drwxrwxrwt 2 root root 60 dec. 25 21:09 .
drwxr-xr-x 20 root root 4600 dec. 25 20:51 ..
-rwxrwxr-x 1 xxxx xxxx 80 dec. 25 21:09 q0
$ ./mq /q1 9
$ ./mq /q2 10
$ ./mq /q3 11
mq_open: Invalid argument
$ ls -la /dev/mqueue/
total 0
drwxrwxrwt 2 root root 100 dec. 25 21:10 .
drwxr-xr-x 20 root root 4600 dec. 25 20:51 ..
-rwxrwxr-x 1 xxxx xxxx 80 dec. 25 21:09 q0
-rwxrwxr-x 1 xxxx xxxx 80 dec. 25 21:10 q1
-rwxrwxr-x 1 xxxx xxxx 80 dec. 25 21:10 q2
Let's change the ceiling value from 10 to 256 for msg_max:
$ cat /proc/sys/fs/mqueue/msg_max
10
$ sudo sh -c "echo 256 > /proc/sys/fs/mqueue/msg_max"
$ cat /proc/sys/fs/mqueue/msg_max
256
Now it is possible to create message queues with up to 256 messages:
$ ./mq /q3 11
$ ./mq /q4 256
$ ./mq /q5 257
mq_open: Invalid argument
$ ls -la /dev/mqueue/
total 0
drwxrwxrwt 2 root root 140 dec. 25 21:16 .
drwxr-xr-x 20 root root 4600 dec. 25 20:51 ..
-rwxrwxr-x 1 xxxx xxxx 80 dec. 25 21:09 q0
-rwxrwxr-x 1 xxxx xxxx 80 dec. 25 21:10 q1
-rwxrwxr-x 1 xxxx xxxx 80 dec. 25 21:10 q2
-rwxrwxr-x 1 xxxx xxxx 80 dec. 25 21:15 q3
-rwxrwxr-x 1 xxxx xxxx 80 dec. 25 21:16 q4
But as you say, increasing the ceiling value requires super user rights. It could be possible to create a "setuid helper" which increases the ceiling value. For example, the following program sets the ceiling value passed as parameter:
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
int fd;
int rc;
int msg_max;
if (argc != 2) {
fprintf(stderr, "Usage: %s <msg_max>\n", argv[0]);
return 1;
}
fd = open("/proc/sys/fs/mqueue/msg_max", O_RDWR);
if (fd < 0) {
perror("open()");
return 1;
}
rc = write(fd, argv[1], strlen(argv[1]));
if (rc != strlen(argv[1])) {
if (rc >= 0) {
errno = EIO;
}
perror("write()");
return 1;
}
close(fd);
return 0;
}
We can build it, change its owner/group to root and add the setuid bit:
$ gcc mq_helper.c -o mq_helper
$ sudo chown root mq_helper
$ sudo chgrp root mq_helper
$ sudo chmod 4555 mq_helper
$ ls -l mq_helper
-r-sr-xr-x 1 root root 17016 dec. 25 21:45 mq_helper
Then, it is possible to run this program from a non super user account to change the ceiling value of msg_max:
$ cat /proc/sys/fs/mqueue/msg_max
256
$ ./mq_helper 98
$ cat /proc/sys/fs/mqueue/msg_max
98

Why can't I read /proc/pid/mem when I have read permission?

I would like to read the content of the memory file associated to one of my process (with PID 2614). I started to write a very small C program to check I can open it:
#include <stdio.h>
#include <errno.h>
int main() {
FILE* f = fopen("/proc/2614/mem", "rb");
if(!f) {
printf("Error %d\n", errno);
return -1;
}
fclose(f);
return 0;
}
When I run it I get a permission denied error:
$ gcc -o read read.c && ./read
Error 13
However, I have read permission:
$ whoami
pierre
$ ll /proc/2614/mem
-rw------- 1 pierre pierre 0 août 18 19:44 /proc/2614/mem
What's going on?
I know it is possible to read the file because I am able to do it on another system (and some other SO answers already did that). Here is information about my system:
$ uname -a
Linux pierre-computer 4.15.0-112-generic #113~16.04.1-Ubuntu SMP Fri Jul 10 04:37:08 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
And the information for the system on which I can read it:
$ uname -a
Linux not-pierre-computer 3.2.0-4-686-pae #1 SMP Debian 3.2.89-2 i686 GNU/Linux
Are there restrictions on some systems?

Compiling against gpsd on OpenWRT - linking fails

I'm trying to compile a tool that uses gps.h, but my compilation seems to fail each time when it tries to link to libgps. The error message I receive is:
/opt/openwrt-sdk/staging_dir/toolchain-arm_cortex-a9+vfpv3_gcc-7.3.0_musl_eabi/bin/../lib/gcc/arm-openwrt-linux-muslgnueabi/7.3.0/../../../../arm-openwrt-linux-muslgnueabi/bin/ld: cannot find -lgps
This is the command I'm compiling with:
arm-openwrt-linux-gcc -o ./bin/eagle src/main.c -I./src -I/opt/openwrt-sdk/staging_dir/target-arm_cortex-a9+vfpv3_musl_eabi/usr/include -static -L/opt/openwrt-sdk/staging_dir/target-arm_cortex-a9+vfpv3_musl_eabi/usr/lib -lpthread -lgps
Basic code for reference:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <gps.h>
int main(void)
{
int rc;
struct gps_data_t gps_data;
if ((rc = gps_open("localhost", "2947", &gps_data)) == -1)
{
printf("code: %d, reason: %s\n", rc, gps_errstr(rc));
return 1;
}
gps_stream(&gps_data, WATCH_ENABLE | WATCH_JSON, NULL);
return 0;
}
And some directory listings in my toolchain - as far as I can tell, libgps has compiled successfully:
# ls -lah /opt/openwrt-sdk/staging_dir/target-arm_cortex-a9+vfpv3_musl_eabi/usr/include/ | grep gps
-rw-rw-r-- 1 root root 80K Sep 7 2017 gps.h
# ls -lah /opt/openwrt-sdk/staging_dir/target-arm_cortex-a9+vfpv3_musl_eabi/usr/lib/ | grep gps
lrwxrwxrwx 1 root root 16 Oct 17 18:46 libgps.so -> libgps.so.23.0.0
lrwxrwxrwx 1 root root 16 Oct 17 18:46 libgps.so.23 -> libgps.so.23.0.0
-rwxr-xr-x 1 root root 101K Oct 17 18:46 libgps.so.23.0.0
Many thanks in advance for any help.
Your link command line contains '-static', which prevents linking against *.so shared libraries (aka shared objects, hence 'so'), but still permits linking against *.a static-link libraries (aka archives).
See: https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html
In the directory whose contents you listed, and which the link command line is directed towards using the '-L' flag, there is a shared object libgps.so, but there is no static-link library libgps.a .
This leaves the linker no way to satisfy the link-time dependency on libgps. The only way to satisfy it, using libgps.so, has been disabled using '-static'.
To fix, either:
Modify the tool's compile recipe, so as to remove '-static' from the link command line, so as to enable use of the shared object, or
Modify gpsd's compile recipe, so as to cause a static-link library libgps.a to built, either in addition to or instead of libgps.so.

Resources