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