xref: /aosp_15_r20/external/ltp/lib/tst_safe_file_at.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1*49cdfc7eSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-or-later
2*49cdfc7eSAndroid Build Coastguard Worker /*
3*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (c) 2021 SUSE LLC <[email protected]>
4*49cdfc7eSAndroid Build Coastguard Worker  */
5*49cdfc7eSAndroid Build Coastguard Worker 
6*49cdfc7eSAndroid Build Coastguard Worker #define _GNU_SOURCE
7*49cdfc7eSAndroid Build Coastguard Worker #include <stdio.h>
8*49cdfc7eSAndroid Build Coastguard Worker #include "lapi/fcntl.h"
9*49cdfc7eSAndroid Build Coastguard Worker #include "tst_safe_file_at.h"
10*49cdfc7eSAndroid Build Coastguard Worker 
11*49cdfc7eSAndroid Build Coastguard Worker #define TST_NO_DEFAULT_MAIN
12*49cdfc7eSAndroid Build Coastguard Worker #include "tst_test.h"
13*49cdfc7eSAndroid Build Coastguard Worker 
14*49cdfc7eSAndroid Build Coastguard Worker static char fd_path[PATH_MAX];
15*49cdfc7eSAndroid Build Coastguard Worker 
tst_decode_fd(const int fd)16*49cdfc7eSAndroid Build Coastguard Worker const char *tst_decode_fd(const int fd)
17*49cdfc7eSAndroid Build Coastguard Worker {
18*49cdfc7eSAndroid Build Coastguard Worker 	ssize_t ret;
19*49cdfc7eSAndroid Build Coastguard Worker 	char proc_path[32];
20*49cdfc7eSAndroid Build Coastguard Worker 
21*49cdfc7eSAndroid Build Coastguard Worker 	if (fd < 0)
22*49cdfc7eSAndroid Build Coastguard Worker 		return "!";
23*49cdfc7eSAndroid Build Coastguard Worker 
24*49cdfc7eSAndroid Build Coastguard Worker 	sprintf(proc_path, "/proc/self/fd/%d", fd);
25*49cdfc7eSAndroid Build Coastguard Worker 	ret = readlink(proc_path, fd_path, sizeof(fd_path));
26*49cdfc7eSAndroid Build Coastguard Worker 
27*49cdfc7eSAndroid Build Coastguard Worker 	if (ret < 0)
28*49cdfc7eSAndroid Build Coastguard Worker 		return "?";
29*49cdfc7eSAndroid Build Coastguard Worker 
30*49cdfc7eSAndroid Build Coastguard Worker 	fd_path[ret] = '\0';
31*49cdfc7eSAndroid Build Coastguard Worker 
32*49cdfc7eSAndroid Build Coastguard Worker 	return fd_path;
33*49cdfc7eSAndroid Build Coastguard Worker }
34*49cdfc7eSAndroid Build Coastguard Worker 
safe_openat(const char * const file,const int lineno,const int dirfd,const char * const path,const int oflags,...)35*49cdfc7eSAndroid Build Coastguard Worker int safe_openat(const char *const file, const int lineno,
36*49cdfc7eSAndroid Build Coastguard Worker 		const int dirfd, const char *const path, const int oflags, ...)
37*49cdfc7eSAndroid Build Coastguard Worker {
38*49cdfc7eSAndroid Build Coastguard Worker 	int fd;
39*49cdfc7eSAndroid Build Coastguard Worker 	mode_t mode = 0;
40*49cdfc7eSAndroid Build Coastguard Worker 
41*49cdfc7eSAndroid Build Coastguard Worker 	if (TST_OPEN_NEEDS_MODE(oflags)) {
42*49cdfc7eSAndroid Build Coastguard Worker 		va_list ap;
43*49cdfc7eSAndroid Build Coastguard Worker 
44*49cdfc7eSAndroid Build Coastguard Worker 		va_start(ap, oflags);
45*49cdfc7eSAndroid Build Coastguard Worker 		mode = va_arg(ap, int);
46*49cdfc7eSAndroid Build Coastguard Worker 		va_end(ap);
47*49cdfc7eSAndroid Build Coastguard Worker 	}
48*49cdfc7eSAndroid Build Coastguard Worker 
49*49cdfc7eSAndroid Build Coastguard Worker 	fd = openat(dirfd, path, oflags, mode);
50*49cdfc7eSAndroid Build Coastguard Worker 	if (fd > -1)
51*49cdfc7eSAndroid Build Coastguard Worker 		return fd;
52*49cdfc7eSAndroid Build Coastguard Worker 
53*49cdfc7eSAndroid Build Coastguard Worker 	tst_brk_(file, lineno, TBROK | TERRNO,
54*49cdfc7eSAndroid Build Coastguard Worker 		 "openat(%d<%s>, '%s', %o, %o)",
55*49cdfc7eSAndroid Build Coastguard Worker 		 dirfd, tst_decode_fd(dirfd), path, oflags, mode);
56*49cdfc7eSAndroid Build Coastguard Worker 
57*49cdfc7eSAndroid Build Coastguard Worker 	return fd;
58*49cdfc7eSAndroid Build Coastguard Worker }
59*49cdfc7eSAndroid Build Coastguard Worker 
safe_file_readat(const char * const file,const int lineno,const int dirfd,const char * const path,char * const buf,const size_t nbyte)60*49cdfc7eSAndroid Build Coastguard Worker ssize_t safe_file_readat(const char *const file, const int lineno,
61*49cdfc7eSAndroid Build Coastguard Worker 			 const int dirfd, const char *const path,
62*49cdfc7eSAndroid Build Coastguard Worker 			 char *const buf, const size_t nbyte)
63*49cdfc7eSAndroid Build Coastguard Worker {
64*49cdfc7eSAndroid Build Coastguard Worker 	int fd = safe_openat(file, lineno, dirfd, path, O_RDONLY);
65*49cdfc7eSAndroid Build Coastguard Worker 	ssize_t rval;
66*49cdfc7eSAndroid Build Coastguard Worker 
67*49cdfc7eSAndroid Build Coastguard Worker 	if (fd < 0)
68*49cdfc7eSAndroid Build Coastguard Worker 		return -1;
69*49cdfc7eSAndroid Build Coastguard Worker 
70*49cdfc7eSAndroid Build Coastguard Worker 	rval = safe_read(file, lineno, NULL, 0, fd, buf, nbyte - 1);
71*49cdfc7eSAndroid Build Coastguard Worker 	if (rval < 0)
72*49cdfc7eSAndroid Build Coastguard Worker 		return -1;
73*49cdfc7eSAndroid Build Coastguard Worker 
74*49cdfc7eSAndroid Build Coastguard Worker 	close(fd);
75*49cdfc7eSAndroid Build Coastguard Worker 	buf[rval] = '\0';
76*49cdfc7eSAndroid Build Coastguard Worker 
77*49cdfc7eSAndroid Build Coastguard Worker 	if (rval >= (ssize_t)nbyte - 1) {
78*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk_(file, lineno, TBROK,
79*49cdfc7eSAndroid Build Coastguard Worker 			"Buffer length %zu too small to read %d<%s>/%s",
80*49cdfc7eSAndroid Build Coastguard Worker 			nbyte, dirfd, tst_decode_fd(dirfd), path);
81*49cdfc7eSAndroid Build Coastguard Worker 	}
82*49cdfc7eSAndroid Build Coastguard Worker 
83*49cdfc7eSAndroid Build Coastguard Worker 	return rval;
84*49cdfc7eSAndroid Build Coastguard Worker }
85*49cdfc7eSAndroid Build Coastguard Worker 
tst_file_vprintfat(const int dirfd,const char * const path,const char * const fmt,va_list va)86*49cdfc7eSAndroid Build Coastguard Worker int tst_file_vprintfat(const int dirfd, const char *const path,
87*49cdfc7eSAndroid Build Coastguard Worker 		       const char *const fmt, va_list va)
88*49cdfc7eSAndroid Build Coastguard Worker {
89*49cdfc7eSAndroid Build Coastguard Worker 	const int fd = openat(dirfd, path, O_WRONLY);
90*49cdfc7eSAndroid Build Coastguard Worker 	int ret, errno_cpy;
91*49cdfc7eSAndroid Build Coastguard Worker 
92*49cdfc7eSAndroid Build Coastguard Worker 	if (fd < 0)
93*49cdfc7eSAndroid Build Coastguard Worker 		return -1;
94*49cdfc7eSAndroid Build Coastguard Worker 
95*49cdfc7eSAndroid Build Coastguard Worker 	ret = vdprintf(fd, fmt, va);
96*49cdfc7eSAndroid Build Coastguard Worker 	errno_cpy = errno;
97*49cdfc7eSAndroid Build Coastguard Worker 	close(fd);
98*49cdfc7eSAndroid Build Coastguard Worker 
99*49cdfc7eSAndroid Build Coastguard Worker 	if (ret < 0) {
100*49cdfc7eSAndroid Build Coastguard Worker 		errno = errno_cpy;
101*49cdfc7eSAndroid Build Coastguard Worker 		return -2;
102*49cdfc7eSAndroid Build Coastguard Worker 	}
103*49cdfc7eSAndroid Build Coastguard Worker 
104*49cdfc7eSAndroid Build Coastguard Worker 	return ret;
105*49cdfc7eSAndroid Build Coastguard Worker }
106*49cdfc7eSAndroid Build Coastguard Worker 
tst_file_printfat(const int dirfd,const char * const path,const char * const fmt,...)107*49cdfc7eSAndroid Build Coastguard Worker int tst_file_printfat(const int dirfd, const char *const path,
108*49cdfc7eSAndroid Build Coastguard Worker 		      const char *const fmt, ...)
109*49cdfc7eSAndroid Build Coastguard Worker {
110*49cdfc7eSAndroid Build Coastguard Worker 	va_list va;
111*49cdfc7eSAndroid Build Coastguard Worker 	int rval;
112*49cdfc7eSAndroid Build Coastguard Worker 
113*49cdfc7eSAndroid Build Coastguard Worker 	va_start(va, fmt);
114*49cdfc7eSAndroid Build Coastguard Worker 	rval = tst_file_vprintfat(dirfd, path, fmt, va);
115*49cdfc7eSAndroid Build Coastguard Worker 	va_end(va);
116*49cdfc7eSAndroid Build Coastguard Worker 
117*49cdfc7eSAndroid Build Coastguard Worker 	return rval;
118*49cdfc7eSAndroid Build Coastguard Worker }
119*49cdfc7eSAndroid Build Coastguard Worker 
safe_file_vprintfat(const char * const file,const int lineno,const int dirfd,const char * const path,const char * const fmt,va_list va)120*49cdfc7eSAndroid Build Coastguard Worker int safe_file_vprintfat(const char *const file, const int lineno,
121*49cdfc7eSAndroid Build Coastguard Worker 			const int dirfd, const char *const path,
122*49cdfc7eSAndroid Build Coastguard Worker 			const char *const fmt, va_list va)
123*49cdfc7eSAndroid Build Coastguard Worker {
124*49cdfc7eSAndroid Build Coastguard Worker 	char buf[16];
125*49cdfc7eSAndroid Build Coastguard Worker 	va_list vac;
126*49cdfc7eSAndroid Build Coastguard Worker 	int rval, errno_cpy;
127*49cdfc7eSAndroid Build Coastguard Worker 
128*49cdfc7eSAndroid Build Coastguard Worker 	va_copy(vac, va);
129*49cdfc7eSAndroid Build Coastguard Worker 
130*49cdfc7eSAndroid Build Coastguard Worker 	rval = tst_file_vprintfat(dirfd, path, fmt, va);
131*49cdfc7eSAndroid Build Coastguard Worker 
132*49cdfc7eSAndroid Build Coastguard Worker 	if (rval == -2) {
133*49cdfc7eSAndroid Build Coastguard Worker 		errno_cpy = errno;
134*49cdfc7eSAndroid Build Coastguard Worker 		rval = vsnprintf(buf, sizeof(buf), fmt, vac);
135*49cdfc7eSAndroid Build Coastguard Worker 		va_end(vac);
136*49cdfc7eSAndroid Build Coastguard Worker 
137*49cdfc7eSAndroid Build Coastguard Worker 		if (rval >= (ssize_t)sizeof(buf))
138*49cdfc7eSAndroid Build Coastguard Worker 			strcpy(buf + sizeof(buf) - 5, "...");
139*49cdfc7eSAndroid Build Coastguard Worker 		else if (rval < 0)
140*49cdfc7eSAndroid Build Coastguard Worker 			buf[0] = '\0';
141*49cdfc7eSAndroid Build Coastguard Worker 
142*49cdfc7eSAndroid Build Coastguard Worker 		errno = errno_cpy;
143*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk_(file, lineno, TBROK | TERRNO,
144*49cdfc7eSAndroid Build Coastguard Worker 			 "vdprintf(%d<%s>, '%s', '%s'<%s>)",
145*49cdfc7eSAndroid Build Coastguard Worker 			 dirfd, tst_decode_fd(dirfd), path, fmt, buf);
146*49cdfc7eSAndroid Build Coastguard Worker 		return -1;
147*49cdfc7eSAndroid Build Coastguard Worker 	}
148*49cdfc7eSAndroid Build Coastguard Worker 
149*49cdfc7eSAndroid Build Coastguard Worker 	va_end(vac);
150*49cdfc7eSAndroid Build Coastguard Worker 
151*49cdfc7eSAndroid Build Coastguard Worker 	if (rval == -1) {
152*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk_(file, lineno, TBROK | TERRNO,
153*49cdfc7eSAndroid Build Coastguard Worker 			"openat(%d<%s>, '%s', O_WRONLY)",
154*49cdfc7eSAndroid Build Coastguard Worker 			dirfd, tst_decode_fd(dirfd), path);
155*49cdfc7eSAndroid Build Coastguard Worker 	}
156*49cdfc7eSAndroid Build Coastguard Worker 
157*49cdfc7eSAndroid Build Coastguard Worker 	return rval;
158*49cdfc7eSAndroid Build Coastguard Worker }
159*49cdfc7eSAndroid Build Coastguard Worker 
safe_file_printfat(const char * const file,const int lineno,const int dirfd,const char * const path,const char * const fmt,...)160*49cdfc7eSAndroid Build Coastguard Worker int safe_file_printfat(const char *const file, const int lineno,
161*49cdfc7eSAndroid Build Coastguard Worker 		       const int dirfd, const char *const path,
162*49cdfc7eSAndroid Build Coastguard Worker 		       const char *const fmt, ...)
163*49cdfc7eSAndroid Build Coastguard Worker {
164*49cdfc7eSAndroid Build Coastguard Worker 	va_list va;
165*49cdfc7eSAndroid Build Coastguard Worker 	int rval;
166*49cdfc7eSAndroid Build Coastguard Worker 
167*49cdfc7eSAndroid Build Coastguard Worker 	va_start(va, fmt);
168*49cdfc7eSAndroid Build Coastguard Worker 	rval = safe_file_vprintfat(file, lineno, dirfd, path, fmt, va);
169*49cdfc7eSAndroid Build Coastguard Worker 	va_end(va);
170*49cdfc7eSAndroid Build Coastguard Worker 
171*49cdfc7eSAndroid Build Coastguard Worker 	return rval;
172*49cdfc7eSAndroid Build Coastguard Worker }
173*49cdfc7eSAndroid Build Coastguard Worker 
safe_unlinkat(const char * const file,const int lineno,const int dirfd,const char * const path,const int flags)174*49cdfc7eSAndroid Build Coastguard Worker int safe_unlinkat(const char *const file, const int lineno,
175*49cdfc7eSAndroid Build Coastguard Worker 		  const int dirfd, const char *const path, const int flags)
176*49cdfc7eSAndroid Build Coastguard Worker {
177*49cdfc7eSAndroid Build Coastguard Worker 	const int rval = unlinkat(dirfd, path, flags);
178*49cdfc7eSAndroid Build Coastguard Worker 	const char *flags_sym;
179*49cdfc7eSAndroid Build Coastguard Worker 
180*49cdfc7eSAndroid Build Coastguard Worker 	if (!rval)
181*49cdfc7eSAndroid Build Coastguard Worker 		return rval;
182*49cdfc7eSAndroid Build Coastguard Worker 
183*49cdfc7eSAndroid Build Coastguard Worker 	switch(flags) {
184*49cdfc7eSAndroid Build Coastguard Worker 	case AT_REMOVEDIR:
185*49cdfc7eSAndroid Build Coastguard Worker 		flags_sym = "AT_REMOVEDIR";
186*49cdfc7eSAndroid Build Coastguard Worker 		break;
187*49cdfc7eSAndroid Build Coastguard Worker 	case 0:
188*49cdfc7eSAndroid Build Coastguard Worker 		flags_sym = "0";
189*49cdfc7eSAndroid Build Coastguard Worker 		break;
190*49cdfc7eSAndroid Build Coastguard Worker 	default:
191*49cdfc7eSAndroid Build Coastguard Worker 		flags_sym = "?";
192*49cdfc7eSAndroid Build Coastguard Worker 		break;
193*49cdfc7eSAndroid Build Coastguard Worker 	}
194*49cdfc7eSAndroid Build Coastguard Worker 
195*49cdfc7eSAndroid Build Coastguard Worker 	tst_brk_(file, lineno, TBROK | TERRNO,
196*49cdfc7eSAndroid Build Coastguard Worker 		 "unlinkat(%d<%s>, '%s', %s)",
197*49cdfc7eSAndroid Build Coastguard Worker 		 dirfd, tst_decode_fd(dirfd), path, flags_sym);
198*49cdfc7eSAndroid Build Coastguard Worker 
199*49cdfc7eSAndroid Build Coastguard Worker 	return rval;
200*49cdfc7eSAndroid Build Coastguard Worker }
201*49cdfc7eSAndroid Build Coastguard Worker 
safe_fchownat(const char * const file,const int lineno,const int dirfd,const char * const path,uid_t owner,gid_t group,int flags)202*49cdfc7eSAndroid Build Coastguard Worker int safe_fchownat(const char *const file, const int lineno,
203*49cdfc7eSAndroid Build Coastguard Worker 		  const int dirfd, const char *const path, uid_t owner, gid_t group, int flags)
204*49cdfc7eSAndroid Build Coastguard Worker {
205*49cdfc7eSAndroid Build Coastguard Worker 	int rval;
206*49cdfc7eSAndroid Build Coastguard Worker 
207*49cdfc7eSAndroid Build Coastguard Worker 	rval = fchownat(dirfd, path, owner, group, flags);
208*49cdfc7eSAndroid Build Coastguard Worker 
209*49cdfc7eSAndroid Build Coastguard Worker 	if (rval == -1) {
210*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk_(file, lineno, TBROK | TERRNO,
211*49cdfc7eSAndroid Build Coastguard Worker 			 "fchownat(%d<%s>, '%s', %d, %d, %d) failed", dirfd,
212*49cdfc7eSAndroid Build Coastguard Worker 			 tst_decode_fd(dirfd), path, owner, group, flags);
213*49cdfc7eSAndroid Build Coastguard Worker 	} else if (rval) {
214*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk_(file, lineno, TBROK | TERRNO,
215*49cdfc7eSAndroid Build Coastguard Worker 			 "Invalid fchownat(%d<%s>, '%s', %d, %d, %d) return value %d",
216*49cdfc7eSAndroid Build Coastguard Worker 			 dirfd, tst_decode_fd(dirfd), path, owner, group, flags, rval);
217*49cdfc7eSAndroid Build Coastguard Worker 	}
218*49cdfc7eSAndroid Build Coastguard Worker 
219*49cdfc7eSAndroid Build Coastguard Worker 	return rval;
220*49cdfc7eSAndroid Build Coastguard Worker }
221*49cdfc7eSAndroid Build Coastguard Worker 
safe_fstatat(const char * const file,const int lineno,const int dirfd,const char * const path,struct stat * statbuf,int flags)222*49cdfc7eSAndroid Build Coastguard Worker int safe_fstatat(const char *const file, const int lineno,
223*49cdfc7eSAndroid Build Coastguard Worker 		 const int dirfd, const char *const path, struct stat *statbuf, int flags)
224*49cdfc7eSAndroid Build Coastguard Worker {
225*49cdfc7eSAndroid Build Coastguard Worker 	int rval;
226*49cdfc7eSAndroid Build Coastguard Worker 
227*49cdfc7eSAndroid Build Coastguard Worker 	rval = fstatat(dirfd, path, statbuf, flags);
228*49cdfc7eSAndroid Build Coastguard Worker 
229*49cdfc7eSAndroid Build Coastguard Worker 	if (rval == -1) {
230*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk_(file, lineno, TBROK | TERRNO,
231*49cdfc7eSAndroid Build Coastguard Worker 			 "fstatat(%d<%s>, '%s', %p, %d) failed", dirfd,
232*49cdfc7eSAndroid Build Coastguard Worker 			 tst_decode_fd(dirfd), path, statbuf, flags);
233*49cdfc7eSAndroid Build Coastguard Worker 	} else if (rval) {
234*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk_(file, lineno, TBROK | TERRNO,
235*49cdfc7eSAndroid Build Coastguard Worker 			 "Invalid fstatat(%d<%s>, '%s', %p, %d) return value %d",
236*49cdfc7eSAndroid Build Coastguard Worker 			 dirfd, tst_decode_fd(dirfd), path, statbuf, flags, rval);
237*49cdfc7eSAndroid Build Coastguard Worker 	}
238*49cdfc7eSAndroid Build Coastguard Worker 
239*49cdfc7eSAndroid Build Coastguard Worker 	return rval;
240*49cdfc7eSAndroid Build Coastguard Worker }
241