1 /*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 * of conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "fs/file.h"
33 #include "los_process_pri.h"
34 #include "fs/fd_table.h"
35 #include "mqueue.h"
36 #ifdef LOSCFG_NET_LWIP_SACK
37 #include "lwip/sockets.h"
38 #endif
39
FileTableLock(struct fd_table_s * fdt)40 void FileTableLock(struct fd_table_s *fdt)
41 {
42 /* Take the semaphore (perhaps waiting) */
43 while (sem_wait(&fdt->ft_sem) != 0) {
44 /*
45 * The only case that an error should occur here is if the wait was
46 * awakened by a signal.
47 */
48 LOS_ASSERT(errno == EINTR);
49 }
50 }
51
FileTableUnLock(struct fd_table_s * fdt)52 void FileTableUnLock(struct fd_table_s *fdt)
53 {
54 int ret = sem_post(&fdt->ft_sem);
55 if (ret == -1) {
56 PRINTK("sem_post error, errno %d \n", get_errno());
57 }
58 }
59
AssignProcessFd(const struct fd_table_s * fdt,int minFd)60 static int AssignProcessFd(const struct fd_table_s *fdt, int minFd)
61 {
62 if (minFd >= fdt->max_fds) {
63 set_errno(EINVAL);
64 return VFS_ERROR;
65 }
66
67 /* search unused fd from table */
68 for (int i = minFd; i < fdt->max_fds; i++) {
69 if (!FD_ISSET(i, fdt->proc_fds)) {
70 return i;
71 }
72 }
73 set_errno(EMFILE);
74 return VFS_ERROR;
75 }
76
GetFdTable(void)77 struct fd_table_s *GetFdTable(void)
78 {
79 struct fd_table_s *fdt = NULL;
80 struct files_struct *procFiles = OsCurrProcessGet()->files;
81
82 if (procFiles == NULL) {
83 return NULL;
84 }
85
86 fdt = procFiles->fdt;
87 if ((fdt == NULL) || (fdt->ft_fds == NULL)) {
88 return NULL;
89 }
90
91 return fdt;
92 }
93
IsValidProcessFd(struct fd_table_s * fdt,int procFd)94 static bool IsValidProcessFd(struct fd_table_s *fdt, int procFd)
95 {
96 if (fdt == NULL) {
97 return false;
98 }
99 if ((procFd < 0) || (procFd >= fdt->max_fds)) {
100 return false;
101 }
102 return true;
103 }
104
AssociateSystemFd(int procFd,int sysFd)105 void AssociateSystemFd(int procFd, int sysFd)
106 {
107 struct fd_table_s *fdt = GetFdTable();
108
109 if (!IsValidProcessFd(fdt, procFd)) {
110 return;
111 }
112
113 if (sysFd < 0) {
114 return;
115 }
116
117 FileTableLock(fdt);
118 fdt->ft_fds[procFd].sysFd = sysFd;
119 FileTableUnLock(fdt);
120 }
121
CheckProcessFd(int procFd)122 int CheckProcessFd(int procFd)
123 {
124 struct fd_table_s *fdt = GetFdTable();
125
126 if (!IsValidProcessFd(fdt, procFd)) {
127 return VFS_ERROR;
128 }
129
130 return OK;
131 }
132
GetAssociatedSystemFd(int procFd)133 int GetAssociatedSystemFd(int procFd)
134 {
135 struct fd_table_s *fdt = GetFdTable();
136
137 if (!IsValidProcessFd(fdt, procFd)) {
138 return VFS_ERROR;
139 }
140
141 FileTableLock(fdt);
142 if (fdt->ft_fds[procFd].sysFd < 0) {
143 FileTableUnLock(fdt);
144 return VFS_ERROR;
145 }
146 int sysFd = fdt->ft_fds[procFd].sysFd;
147 FileTableUnLock(fdt);
148
149 return sysFd;
150 }
151
152 /* Occupy the procFd, there are three circumstances:
153 * 1.procFd is already associated, we need disassociate procFd with relevant sysfd.
154 * 2.procFd is not allocated, we occupy it immediately.
155 * 3.procFd is in open(), close(), dup() process, we return EBUSY immediately.
156 */
AllocSpecifiedProcessFd(int procFd)157 int AllocSpecifiedProcessFd(int procFd)
158 {
159 struct fd_table_s *fdt = GetFdTable();
160
161 if (!IsValidProcessFd(fdt, procFd)) {
162 return -EBADF;
163 }
164
165 FileTableLock(fdt);
166 if (fdt->ft_fds[procFd].sysFd >= 0) {
167 /* Disassociate procFd */
168 fdt->ft_fds[procFd].sysFd = -1;
169 FileTableUnLock(fdt);
170 return OK;
171 }
172
173 if (FD_ISSET(procFd, fdt->proc_fds)) {
174 /* procFd in race condition */
175 FileTableUnLock(fdt);
176 return -EBUSY;
177 } else {
178 /* Unused procFd */
179 FD_SET(procFd, fdt->proc_fds);
180 }
181
182 FileTableUnLock(fdt);
183 return OK;
184 }
185
FreeProcessFd(int procFd)186 void FreeProcessFd(int procFd)
187 {
188 struct fd_table_s *fdt = GetFdTable();
189
190 if (!IsValidProcessFd(fdt, procFd)) {
191 return;
192 }
193
194 FileTableLock(fdt);
195 FD_CLR(procFd, fdt->proc_fds);
196 FD_CLR(procFd, fdt->cloexec_fds);
197 fdt->ft_fds[procFd].sysFd = -1;
198 FileTableUnLock(fdt);
199 }
200
DisassociateProcessFd(int procFd)201 int DisassociateProcessFd(int procFd)
202 {
203 struct fd_table_s *fdt = GetFdTable();
204
205 if (!IsValidProcessFd(fdt, procFd)) {
206 return VFS_ERROR;
207 }
208
209 FileTableLock(fdt);
210 if (fdt->ft_fds[procFd].sysFd < 0) {
211 FileTableUnLock(fdt);
212 return VFS_ERROR;
213 }
214 int sysFd = fdt->ft_fds[procFd].sysFd;
215 if (procFd >= MIN_START_FD) {
216 fdt->ft_fds[procFd].sysFd = -1;
217 }
218 FileTableUnLock(fdt);
219
220 return sysFd;
221 }
222
AllocProcessFd(void)223 int AllocProcessFd(void)
224 {
225 return AllocLowestProcessFd(MIN_START_FD);
226 }
227
AllocLowestProcessFd(int minFd)228 int AllocLowestProcessFd(int minFd)
229 {
230 struct fd_table_s *fdt = GetFdTable();
231
232 if (fdt == NULL) {
233 return VFS_ERROR;
234 }
235
236 /* minFd should be a positive number,and 0,1,2 had be distributed to stdin,stdout,stderr */
237 if (minFd < MIN_START_FD) {
238 minFd = MIN_START_FD;
239 }
240
241 FileTableLock(fdt);
242
243 int procFd = AssignProcessFd(fdt, minFd);
244 if (procFd == VFS_ERROR) {
245 FileTableUnLock(fdt);
246 return VFS_ERROR;
247 }
248
249 /* occupy the fd set */
250 FD_SET(procFd, fdt->proc_fds);
251 FileTableUnLock(fdt);
252
253 return procFd;
254 }
255
AllocAndAssocProcessFd(int sysFd,int minFd)256 int AllocAndAssocProcessFd(int sysFd, int minFd)
257 {
258 struct fd_table_s *fdt = GetFdTable();
259
260 if (fdt == NULL) {
261 return VFS_ERROR;
262 }
263
264 /* minFd should be a positive number,and 0,1,2 had be distributed to stdin,stdout,stderr */
265 if (minFd < MIN_START_FD) {
266 minFd = MIN_START_FD;
267 }
268
269 FileTableLock(fdt);
270
271 int procFd = AssignProcessFd(fdt, minFd);
272 if (procFd == VFS_ERROR) {
273 FileTableUnLock(fdt);
274 return VFS_ERROR;
275 }
276
277 /* occupy the fd set */
278 FD_SET(procFd, fdt->proc_fds);
279 fdt->ft_fds[procFd].sysFd = sysFd;
280 FileTableUnLock(fdt);
281
282 return procFd;
283 }
284
AllocAndAssocSystemFd(int procFd,int minFd)285 int AllocAndAssocSystemFd(int procFd, int minFd)
286 {
287 struct fd_table_s *fdt = GetFdTable();
288
289 if (!IsValidProcessFd(fdt, procFd)) {
290 return VFS_ERROR;
291 }
292
293 int sysFd = alloc_fd(minFd);
294 if (sysFd < 0) {
295 return VFS_ERROR;
296 }
297
298 FileTableLock(fdt);
299 fdt->ft_fds[procFd].sysFd = sysFd;
300 FileTableUnLock(fdt);
301
302 return sysFd;
303 }
304
FdRefer(int sysFd)305 static void FdRefer(int sysFd)
306 {
307 if ((sysFd > STDERR_FILENO) && (sysFd < CONFIG_NFILE_DESCRIPTORS)) {
308 files_refer(sysFd);
309 }
310 #if defined(LOSCFG_NET_LWIP_SACK)
311 if ((sysFd >= CONFIG_NFILE_DESCRIPTORS) && (sysFd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS))) {
312 socks_refer(sysFd);
313 }
314 #endif
315 #if defined(LOSCFG_COMPAT_POSIX)
316 if ((sysFd >= MQUEUE_FD_OFFSET) && (sysFd < (MQUEUE_FD_OFFSET + CONFIG_NQUEUE_DESCRIPTORS))) {
317 MqueueRefer(sysFd);
318 }
319 #endif
320 }
321
FdClose(int sysFd,unsigned int targetPid)322 static void FdClose(int sysFd, unsigned int targetPid)
323 {
324 UINT32 intSave;
325
326 if ((sysFd > STDERR_FILENO) && (sysFd < CONFIG_NFILE_DESCRIPTORS)) {
327 LosProcessCB *processCB = OS_PCB_FROM_PID(targetPid);
328 SCHEDULER_LOCK(intSave);
329 if (OsProcessIsInactive(processCB)) {
330 SCHEDULER_UNLOCK(intSave);
331 return;
332 }
333 SCHEDULER_UNLOCK(intSave);
334
335 files_close_internal(sysFd, processCB);
336 }
337 #if defined(LOSCFG_NET_LWIP_SACK)
338 if ((sysFd >= CONFIG_NFILE_DESCRIPTORS) && (sysFd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS))) {
339 socks_close(sysFd);
340 }
341 #endif
342 #if defined(LOSCFG_COMPAT_POSIX)
343 if ((sysFd >= MQUEUE_FD_OFFSET) && (sysFd < (MQUEUE_FD_OFFSET + CONFIG_NQUEUE_DESCRIPTORS))) {
344 mq_close((mqd_t)sysFd);
345 }
346 #endif
347 }
348
GetProcessFTable(unsigned int pid,sem_t * semId)349 static struct fd_table_s *GetProcessFTable(unsigned int pid, sem_t *semId)
350 {
351 UINT32 intSave;
352 struct files_struct *procFiles = NULL;
353 LosProcessCB *processCB = OS_PCB_FROM_PID(pid);
354
355 SCHEDULER_LOCK(intSave);
356 if (OsProcessIsInactive(processCB)) {
357 SCHEDULER_UNLOCK(intSave);
358 return NULL;
359 }
360
361 procFiles = processCB->files;
362 if (procFiles == NULL || procFiles->fdt == NULL) {
363 SCHEDULER_UNLOCK(intSave);
364 return NULL;
365 }
366
367 *semId = procFiles->fdt->ft_sem;
368 SCHEDULER_UNLOCK(intSave);
369
370 return procFiles->fdt;
371 }
372
CopyFdToProc(int fd,unsigned int targetPid)373 int CopyFdToProc(int fd, unsigned int targetPid)
374 {
375 #if !defined(LOSCFG_NET_LWIP_SACK) && !defined(LOSCFG_COMPAT_POSIX) && !defined(LOSCFG_FS_VFS)
376 return -ENOSYS;
377 #else
378 int sysFd;
379 struct fd_table_s *fdt = NULL;
380 int procFd;
381 sem_t semId;
382
383 if (OS_PID_CHECK_INVALID(targetPid)) {
384 return -EINVAL;
385 }
386
387 sysFd = GetAssociatedSystemFd(fd);
388 if (sysFd < 0) {
389 return -EBADF;
390 }
391
392 FdRefer(sysFd);
393 fdt = GetProcessFTable(targetPid, &semId);
394 if (fdt == NULL || fdt->ft_fds == NULL) {
395 FdClose(sysFd, targetPid);
396 return -EPERM;
397 }
398
399 /* Take the semaphore (perhaps waiting) */
400 if (sem_wait(&semId) != 0) {
401 /* Target process changed */
402 FdClose(sysFd, targetPid);
403 return -ESRCH;
404 }
405
406 procFd = AssignProcessFd(fdt, 3); // minfd is 3
407 if (procFd < 0) {
408 if (sem_post(&semId) == -1) {
409 PRINT_ERR("sem_post error, errno %d \n", get_errno());
410 }
411 FdClose(sysFd, targetPid);
412 return -EPERM;
413 }
414
415 /* occupy the fd set */
416 FD_SET(procFd, fdt->proc_fds);
417 fdt->ft_fds[procFd].sysFd = sysFd;
418 if (sem_post(&semId) == -1) {
419 PRINTK("sem_post error, errno %d \n", get_errno());
420 }
421
422 return procFd;
423 #endif
424 }
425
CloseProcFd(int procFd,unsigned int targetPid)426 int CloseProcFd(int procFd, unsigned int targetPid)
427 {
428 #if !defined(LOSCFG_NET_LWIP_SACK) && !defined(LOSCFG_COMPAT_POSIX) && !defined(LOSCFG_FS_VFS)
429 return -ENOSYS;
430 #else
431 int sysFd;
432 struct fd_table_s *fdt = NULL;
433 sem_t semId;
434
435 if (OS_PID_CHECK_INVALID(targetPid)) {
436 return -EINVAL;
437 }
438
439 fdt = GetProcessFTable(targetPid, &semId);
440 if (fdt == NULL || fdt->ft_fds == NULL) {
441 return -EPERM;
442 }
443
444 /* Take the semaphore (perhaps waiting) */
445 if (sem_wait(&semId) != 0) {
446 /* Target process changed */
447 return -ESRCH;
448 }
449
450 if (!IsValidProcessFd(fdt, procFd)) {
451 if (sem_post(&semId) == -1) {
452 PRINTK("sem_post error, errno %d \n", get_errno());
453 }
454 return -EPERM;
455 }
456
457 sysFd = fdt->ft_fds[procFd].sysFd;
458 if (sysFd < 0) {
459 if (sem_post(&semId) == -1) {
460 PRINTK("sem_post error, errno %d \n", get_errno());
461 }
462 return -EPERM;
463 }
464
465 /* clean the fd set */
466 FD_CLR(procFd, fdt->proc_fds);
467 FD_CLR(procFd, fdt->cloexec_fds);
468 fdt->ft_fds[procFd].sysFd = -1;
469 if (sem_post(&semId) == -1) {
470 PRINTK("sem_post error, errno %d \n", get_errno());
471 }
472 FdClose(sysFd, targetPid);
473
474 return 0;
475 #endif
476 }
477