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>
		
	
			
		
			
				
	
	
		
			80 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			80 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;
 | |
| }
 |