linux-stable/tools/testing/selftests/nsfs/pidns.c
Gustavo A. R. Silva d8238f9eb6 tools/testing: Replace zero-length array with flexible-array
The current codebase makes use of the zero-length array language
extension to the C90 standard, but the preferred mechanism to declare
variable-length types such as these ones is a flexible array member[1][2],
introduced in C99:

struct foo {
        int stuff;
        struct boo array[];
};

By making use of the mechanism above, we will get a compiler warning
in case the flexible array does not occur last in the structure, which
will help us prevent some kind of undefined behavior bugs from being
inadvertently introduced[3] to the codebase from now on.

Also, notice that, dynamic memory allocations won't be affected by
this change:

"Flexible array members have incomplete type, and so the sizeof operator
may not be applied. As a quirk of the original implementation of
zero-length arrays, sizeof evaluates to zero."[1]

sizeof(flexible-array-member) triggers a warning because flexible array
members have incomplete type[1]. There are some instances of code in
which the sizeof operator is being incorrectly/erroneously applied to
zero-length arrays and the result is zero. Such instances may be hiding
some bugs. So, this work (flexible-array member conversions) will also
help to get completely rid of those sorts of issues.

This issue was found with the help of Coccinelle.

[1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
[2] https://github.com/KSPP/linux/issues/21
[3] commit 7649773293 ("cxgb3/l2t: Fix undefined behaviour")

Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
2020-05-08 09:42:14 -06:00

79 lines
1.8 KiB
C

// SPDX-License-Identifier: GPL-2.0
#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#define pr_err(fmt, ...) \
({ \
fprintf(stderr, "%s:%d:" fmt ": %m\n", \
__func__, __LINE__, ##__VA_ARGS__); \
1; \
})
#define NSIO 0xb7
#define NS_GET_USERNS _IO(NSIO, 0x1)
#define NS_GET_PARENT _IO(NSIO, 0x2)
#define __stack_aligned__ __attribute__((aligned(16)))
struct cr_clone_arg {
char stack[128] __stack_aligned__;
char stack_ptr[];
};
static int child(void *args)
{
prctl(PR_SET_PDEATHSIG, SIGKILL);
while (1)
sleep(1);
exit(0);
}
int main(int argc, char *argv[])
{
char *ns_strs[] = {"pid", "user"};
char path[] = "/proc/0123456789/ns/pid";
struct cr_clone_arg ca;
struct stat st1, st2;
int ns, pns, i;
pid_t pid;
pid = clone(child, ca.stack_ptr, CLONE_NEWUSER | CLONE_NEWPID | SIGCHLD, NULL);
if (pid < 0)
return pr_err("clone");
for (i = 0; i < 2; i++) {
snprintf(path, sizeof(path), "/proc/%d/ns/%s", pid, ns_strs[i]);
ns = open(path, O_RDONLY);
if (ns < 0)
return pr_err("Unable to open %s", path);
pns = ioctl(ns, NS_GET_PARENT);
if (pns < 0)
return pr_err("Unable to get a parent pidns");
snprintf(path, sizeof(path), "/proc/self/ns/%s", ns_strs[i]);
if (stat(path, &st2))
return pr_err("Unable to stat %s", path);
if (fstat(pns, &st1))
return pr_err("Unable to stat the parent pidns");
if (st1.st_ino != st2.st_ino)
return pr_err("NS_GET_PARENT returned a wrong namespace");
if (ioctl(pns, NS_GET_PARENT) >= 0 || errno != EPERM)
return pr_err("Don't get EPERM");
}
kill(pid, SIGKILL);
wait(NULL);
return 0;
}