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 (fdt == NULL) {
63 return VFS_ERROR;
64 }
65
66 if (minFd >= fdt->max_fds) {
67 set_errno(EINVAL);
68 return VFS_ERROR;
69 }
70
71 /* search unused fd from table */
72 for (int i = minFd; i < fdt->max_fds; i++) {
73 if (!FD_ISSET(i, fdt->proc_fds)) {
74 return i;
75 }
76 }
77 set_errno(EMFILE);
78 return VFS_ERROR;
79 }
80
GetFdTable(void)81 struct fd_table_s *GetFdTable(void)
82 {
83 struct fd_table_s *fdt = NULL;
84 struct files_struct *procFiles = OsCurrProcessGet()->files;
85
86 if (procFiles == NULL) {
87 return NULL;
88 }
89
90 fdt = procFiles->fdt;
91 if ((fdt == NULL) || (fdt->ft_fds == NULL)) {
92 return NULL;
93 }
94
95 return fdt;
96 }
97
IsValidProcessFd(struct fd_table_s * fdt,int procFd)98 static bool IsValidProcessFd(struct fd_table_s *fdt, int procFd)
99 {
100 if (fdt == NULL) {
101 return false;
102 }
103 if ((procFd < 0) || (procFd >= fdt->max_fds)) {
104 return false;
105 }
106 return true;
107 }
108
AssociateSystemFd(int procFd,int sysFd)109 void AssociateSystemFd(int procFd, int sysFd)
110 {
111 struct fd_table_s *fdt = GetFdTable();
112
113 if (!IsValidProcessFd(fdt, procFd)) {
114 return;
115 }
116
117 if (sysFd < 0) {
118 return;
119 }
120
121 FileTableLock(fdt);
122 fdt->ft_fds[procFd].sysFd = sysFd;
123 FileTableUnLock(fdt);
124 }
125
CheckProcessFd(int procFd)126 int CheckProcessFd(int procFd)
127 {
128 struct fd_table_s *fdt = GetFdTable();
129
130 if (!IsValidProcessFd(fdt, procFd)) {
131 return VFS_ERROR;
132 }
133
134 return OK;
135 }
136
GetAssociatedSystemFd(int procFd)137 int GetAssociatedSystemFd(int procFd)
138 {
139 struct fd_table_s *fdt = GetFdTable();
140
141 if (!IsValidProcessFd(fdt, procFd)) {
142 return VFS_ERROR;
143 }
144
145 FileTableLock(fdt);
146 if (fdt->ft_fds[procFd].sysFd < 0) {
147 FileTableUnLock(fdt);
148 return VFS_ERROR;
149 }
150 int sysFd = fdt->ft_fds[procFd].sysFd;
151 FileTableUnLock(fdt);
152
153 return sysFd;
154 }
155
156 /* Occupy the procFd, there are three circumstances:
157 * 1.procFd is already associated, we need disassociate procFd with relevant sysfd.
158 * 2.procFd is not allocated, we occupy it immediately.
159 * 3.procFd is in open(), close(), dup() process, we return EBUSY immediately.
160 */
AllocSpecifiedProcessFd(int procFd)161 int AllocSpecifiedProcessFd(int procFd)
162 {
163 struct fd_table_s *fdt = GetFdTable();
164
165 if (!IsValidProcessFd(fdt, procFd)) {
166 return -EBADF;
167 }
168
169 FileTableLock(fdt);
170 if (fdt->ft_fds[procFd].sysFd >= 0) {
171 /* Disassociate procFd */
172 fdt->ft_fds[procFd].sysFd = -1;
173 FileTableUnLock(fdt);
174 return OK;
175 }
176
177 if (FD_ISSET(procFd, fdt->proc_fds)) {
178 /* procFd in race condition */
179 FileTableUnLock(fdt);
180 return -EBUSY;
181 } else {
182 /* Unused procFd */
183 FD_SET(procFd, fdt->proc_fds);
184 }
185
186 FileTableUnLock(fdt);
187 return OK;
188 }
189
FreeProcessFd(int procFd)190 void FreeProcessFd(int procFd)
191 {
192 struct fd_table_s *fdt = GetFdTable();
193
194 if (!IsValidProcessFd(fdt, procFd)) {
195 return;
196 }
197
198 FileTableLock(fdt);
199 FD_CLR(procFd, fdt->proc_fds);
200 FD_CLR(procFd, fdt->cloexec_fds);
201 fdt->ft_fds[procFd].sysFd = -1;
202 FileTableUnLock(fdt);
203 }
204
DisassociateProcessFd(int procFd)205 int DisassociateProcessFd(int procFd)
206 {
207 struct fd_table_s *fdt = GetFdTable();
208
209 if (!IsValidProcessFd(fdt, procFd)) {
210 return VFS_ERROR;
211 }
212
213 FileTableLock(fdt);
214 if (fdt->ft_fds[procFd].sysFd < 0) {
215 FileTableUnLock(fdt);
216 return VFS_ERROR;
217 }
218 int sysFd = fdt->ft_fds[procFd].sysFd;
219 if (procFd >= MIN_START_FD) {
220 fdt->ft_fds[procFd].sysFd = -1;
221 }
222 FileTableUnLock(fdt);
223
224 return sysFd;
225 }
226
AllocProcessFd(void)227 int AllocProcessFd(void)
228 {
229 return AllocLowestProcessFd(MIN_START_FD);
230 }
231
AllocLowestProcessFd(int minFd)232 int AllocLowestProcessFd(int minFd)
233 {
234 struct fd_table_s *fdt = GetFdTable();
235
236 if (fdt == NULL) {
237 return VFS_ERROR;
238 }
239
240 /* minFd should be a positive number,and 0,1,2 had be distributed to stdin,stdout,stderr */
241 if (minFd < MIN_START_FD) {
242 minFd = MIN_START_FD;
243 }
244
245 FileTableLock(fdt);
246
247 int procFd = AssignProcessFd(fdt, minFd);
248 if (procFd == VFS_ERROR) {
249 FileTableUnLock(fdt);
250 return VFS_ERROR;
251 }
252
253 /* occupy the fd set */
254 FD_SET(procFd, fdt->proc_fds);
255 FileTableUnLock(fdt);
256
257 return procFd;
258 }
259
AllocAndAssocProcessFd(int sysFd,int minFd)260 int AllocAndAssocProcessFd(int sysFd, int minFd)
261 {
262 struct fd_table_s *fdt = GetFdTable();
263
264 if (fdt == NULL) {
265 return VFS_ERROR;
266 }
267
268 /* minFd should be a positive number,and 0,1,2 had be distributed to stdin,stdout,stderr */
269 if (minFd < MIN_START_FD) {
270 minFd = MIN_START_FD;
271 }
272
273 FileTableLock(fdt);
274
275 int procFd = AssignProcessFd(fdt, minFd);
276 if (procFd == VFS_ERROR) {
277 FileTableUnLock(fdt);
278 return VFS_ERROR;
279 }
280
281 /* occupy the fd set */
282 FD_SET(procFd, fdt->proc_fds);
283 fdt->ft_fds[procFd].sysFd = sysFd;
284 FileTableUnLock(fdt);
285
286 return procFd;
287 }
288
AllocAndAssocSystemFd(int procFd,int minFd)289 int AllocAndAssocSystemFd(int procFd, int minFd)
290 {
291 struct fd_table_s *fdt = GetFdTable();
292
293 if (!IsValidProcessFd(fdt, procFd)) {
294 return VFS_ERROR;
295 }
296
297 int sysFd = alloc_fd(minFd);
298 if (sysFd < 0) {
299 return VFS_ERROR;
300 }
301
302 FileTableLock(fdt);
303 fdt->ft_fds[procFd].sysFd = sysFd;
304 FileTableUnLock(fdt);
305
306 return sysFd;
307 }
308
FdRefer(int sysFd)309 static void FdRefer(int sysFd)
310 {
311 if ((sysFd > STDERR_FILENO) && (sysFd < CONFIG_NFILE_DESCRIPTORS)) {
312 files_refer(sysFd);
313 }
314 #if defined(LOSCFG_NET_LWIP_SACK)
315 if ((sysFd >= CONFIG_NFILE_DESCRIPTORS) && (sysFd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS))) {
316 socks_refer(sysFd);
317 }
318 #endif
319 #if defined(LOSCFG_COMPAT_POSIX)
320 if ((sysFd >= MQUEUE_FD_OFFSET) && (sysFd < (MQUEUE_FD_OFFSET + CONFIG_NQUEUE_DESCRIPTORS))) {
321 MqueueRefer(sysFd);
322 }
323 #endif
324 }
325
FdClose(int sysFd,unsigned int targetPid)326 static void FdClose(int sysFd, unsigned int targetPid)
327 {
328 UINT32 intSave;
329
330 if ((sysFd > STDERR_FILENO) && (sysFd < CONFIG_NFILE_DESCRIPTORS)) {
331 LosProcessCB *processCB = OS_PCB_FROM_PID(targetPid);
332 SCHEDULER_LOCK(intSave);
333 if (OsProcessIsInactive(processCB)) {
334 SCHEDULER_UNLOCK(intSave);
335 return;
336 }
337 SCHEDULER_UNLOCK(intSave);
338
339 files_close_internal(sysFd, processCB);
340 }
341 #if defined(LOSCFG_NET_LWIP_SACK)
342 if ((sysFd >= CONFIG_NFILE_DESCRIPTORS) && (sysFd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS))) {
343 socks_close(sysFd);
344 }
345 #endif
346 #if defined(LOSCFG_COMPAT_POSIX)
347 if ((sysFd >= MQUEUE_FD_OFFSET) && (sysFd < (MQUEUE_FD_OFFSET + CONFIG_NQUEUE_DESCRIPTORS))) {
348 mq_close((mqd_t)sysFd);
349 }
350 #endif
351 }
352
GetProcessFTable(unsigned int pid,sem_t * semId)353 static struct fd_table_s *GetProcessFTable(unsigned int pid, sem_t *semId)
354 {
355 UINT32 intSave;
356 struct files_struct *procFiles = NULL;
357 LosProcessCB *processCB = OS_PCB_FROM_PID(pid);
358
359 SCHEDULER_LOCK(intSave);
360 if (OsProcessIsInactive(processCB)) {
361 SCHEDULER_UNLOCK(intSave);
362 return NULL;
363 }
364
365 procFiles = processCB->files;
366 if (procFiles == NULL || procFiles->fdt == NULL) {
367 SCHEDULER_UNLOCK(intSave);
368 return NULL;
369 }
370
371 *semId = procFiles->fdt->ft_sem;
372 SCHEDULER_UNLOCK(intSave);
373
374 return procFiles->fdt;
375 }
376
CopyFdToProc(int fd,unsigned int targetPid)377 int CopyFdToProc(int fd, unsigned int targetPid)
378 {
379 #if !defined(LOSCFG_NET_LWIP_SACK) && !defined(LOSCFG_COMPAT_POSIX) && !defined(LOSCFG_FS_VFS)
380 return -ENOSYS;
381 #else
382 int sysFd;
383 struct fd_table_s *fdt = NULL;
384 int procFd;
385 sem_t semId;
386
387 if (OS_PID_CHECK_INVALID(targetPid)) {
388 return -EINVAL;
389 }
390
391 sysFd = GetAssociatedSystemFd(fd);
392 if (sysFd < 0) {
393 return -EBADF;
394 }
395
396 FdRefer(sysFd);
397 fdt = GetProcessFTable(targetPid, &semId);
398 if (fdt == NULL || fdt->ft_fds == NULL) {
399 FdClose(sysFd, targetPid);
400 return -EPERM;
401 }
402
403 /* Take the semaphore (perhaps waiting) */
404 if (sem_wait(&semId) != 0) {
405 /* Target process changed */
406 FdClose(sysFd, targetPid);
407 return -ESRCH;
408 }
409
410 procFd = AssignProcessFd(fdt, 3); // minfd is 3
411 if (procFd < 0) {
412 if (sem_post(&semId) == -1) {
413 PRINT_ERR("sem_post error, errno %d \n", get_errno());
414 }
415 FdClose(sysFd, targetPid);
416 return -EPERM;
417 }
418
419 /* occupy the fd set */
420 FD_SET(procFd, fdt->proc_fds);
421 fdt->ft_fds[procFd].sysFd = sysFd;
422 if (sem_post(&semId) == -1) {
423 PRINTK("sem_post error, errno %d \n", get_errno());
424 }
425
426 return procFd;
427 #endif
428 }
429
CloseProcFd(int procFd,unsigned int targetPid)430 int CloseProcFd(int procFd, unsigned int targetPid)
431 {
432 #if !defined(LOSCFG_NET_LWIP_SACK) && !defined(LOSCFG_COMPAT_POSIX) && !defined(LOSCFG_FS_VFS)
433 return -ENOSYS;
434 #else
435 int sysFd;
436 struct fd_table_s *fdt = NULL;
437 sem_t semId;
438
439 if (OS_PID_CHECK_INVALID(targetPid)) {
440 return -EINVAL;
441 }
442
443 fdt = GetProcessFTable(targetPid, &semId);
444 if (fdt == NULL || fdt->ft_fds == NULL) {
445 return -EPERM;
446 }
447
448 /* Take the semaphore (perhaps waiting) */
449 if (sem_wait(&semId) != 0) {
450 /* Target process changed */
451 return -ESRCH;
452 }
453
454 if (!IsValidProcessFd(fdt, procFd)) {
455 if (sem_post(&semId) == -1) {
456 PRINTK("sem_post error, errno %d \n", get_errno());
457 }
458 return -EPERM;
459 }
460
461 sysFd = fdt->ft_fds[procFd].sysFd;
462 if (sysFd < 0) {
463 if (sem_post(&semId) == -1) {
464 PRINTK("sem_post error, errno %d \n", get_errno());
465 }
466 return -EPERM;
467 }
468
469 /* clean the fd set */
470 FD_CLR(procFd, fdt->proc_fds);
471 FD_CLR(procFd, fdt->cloexec_fds);
472 fdt->ft_fds[procFd].sysFd = -1;
473 if (sem_post(&semId) == -1) {
474 PRINTK("sem_post error, errno %d \n", get_errno());
475 }
476 FdClose(sysFd, targetPid);
477
478 return 0;
479 #endif
480 }
481