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 40void 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 52void 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 60static 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 77struct 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 94static 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 105void 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 122int 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 133int 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 */ 157int 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 186void 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 201int 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 223int AllocProcessFd(void) 224{ 225 return AllocLowestProcessFd(MIN_START_FD); 226} 227 228int 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 256int 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 285int 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 305static 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 322static 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 349static 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 373int 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 426int 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