/
githubmirror
/
lsof
Обзор
Документация
Войти
/
githubmirror
/
lsof
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
lib/dialects/darwin/dfile.c
617 строк
18 KB
Jiajie Chen
Fix potential double free for Lf->fsdir and mp->dir
31 мар 2026, 17:13
31 мар 2026, 17:13
53539a9
Код
Авторство
О чём код?
/* * dfile.c -- Darwin file processing functions for libproc-based lsof */ /* * Portions Copyright 2005-2007 Apple Inc. All rights reserved. * * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana * 47907. All rights reserved. * * Written by Allan Nathanson, Apple Inc., and Victor A. Abell, Purdue * University. * * This software is not subject to any license of the American Telephone * and Telegraph Company or the Regents of the University of California. * * Permission is granted to anyone to use this software for any purpose on * any computer system, and to alter it and redistribute it freely, subject * to the following restrictions: * * 1. Neither the authors, nor Apple Inc. nor Purdue University are * responsible for any consequences of the use of this software. * * 2. The origin of this software must not be misrepresented, either * by explicit claim or by omission. Credit to the authors, Apple * Inc. and Purdue University must appear in documentation and sources. * * 3. Altered versions must be plainly marked as such, and must not be * misrepresented as being the original software. * * 4. This notice may not be removed or altered. */ #ifndef lint static char copyright[] = "@(#) Copyright 2005-2007 Apple Inc. and Purdue " "Research Foundation.\nAll rights reserved.\n"; #endif #include "common.h" /* * enter_file_info() -- enter file information */ void enter_file_info( struct lsof_context *ctx, /* context */ struct proc_fileinfo *pfi) /* pointer to process file info */ { int f; /* * Construct access code */ f = pfi->fi_openflags & (FREAD | FWRITE); if (f == FREAD) Lf->access = LSOF_FILE_ACCESS_READ; else if (f == FWRITE) Lf->access = LSOF_FILE_ACCESS_WRITE; else if (f == (FREAD | FWRITE)) Lf->access = LSOF_FILE_ACCESS_READ_WRITE; /* * Save the offset / size */ Lf->off = (SZOFFTYPE)pfi->fi_offset; Lf->off_def = 1; /* * Save file structure information as requested. */ Lf->ffg = (long)pfi->fi_openflags; Lf->fsv |= FSV_FG; #if defined(PROC_FP_GUARDED) if (pfi->fi_status & PROC_FP_GUARDED) { Lf->guardflags = pfi->fi_guardflags; } #endif /* defined(PROC_FP_GUARDED) */ Lf->pof = (long)pfi->fi_status; } /* * enter_vnode_info() -- enter vnode information */ void enter_vnode_info( struct lsof_context *ctx, /* context */ struct vnode_info_path *vip) /* pointer to vnode info with path */ { char buf[32]; enum lsof_file_type type; uint32_t unknown_file_type_number = 0; dev_t dev = 0; int devs = 0; struct mounts *mp; /* * Derive file type. */ switch ((int)(vip->vip_vi.vi_stat.vst_mode & S_IFMT)) { case S_IFIFO: type = LSOF_FILE_FIFO; Ntype = N_FIFO; break; case S_IFCHR: type = LSOF_FILE_CHAR; Ntype = N_CHR; break; case S_IFDIR: type = LSOF_FILE_DIR; Ntype = N_REGLR; break; case S_IFBLK: type = LSOF_FILE_BLOCK; Ntype = N_BLK; break; #if defined(S_IFLNK) case S_IFLNK: type = LSOF_FILE_LINK; Ntype = N_REGLR; break; #endif /* defined(S_IFLNK) */ case S_IFREG: type = LSOF_FILE_REGULAR; Ntype = N_REGLR; break; default: type = LSOF_FILE_UNKNOWN_RAW; unknown_file_type_number = (vip->vip_vi.vi_stat.vst_mode & S_IFMT) >> 12; Ntype = N_REGLR; } if (Lf->type == LSOF_FILE_NONE) { Lf->type = type; Lf->unknown_file_type_number = unknown_file_type_number; } Lf->ntype = Ntype; /* * Save device number and path */ switch (Ntype) { case N_FIFO: break; case N_CHR: case N_BLK: Lf->rdev = vip->vip_vi.vi_stat.vst_rdev; Lf->rdev_def = 1; /* fall through */ default: Lf->dev = dev = vip->vip_vi.vi_stat.vst_dev; Lf->dev_def = devs = 1; } /* * Save path name. */ vip->vip_path[sizeof(vip->vip_path) - 1] = '\0'; if (vip->vip_path[0] != '\0') { enter_nm(ctx, vip->vip_path); } /* * Save node number. */ Lf->inode = (INODETYPE)vip->vip_vi.vi_stat.vst_ino; Lf->inp_ty = 1; /* * Save link count, as requested. */ Lf->nlink = vip->vip_vi.vi_stat.vst_nlink; Lf->nlink_def = 1; if (Nlink && (Lf->nlink < Nlink)) Lf->sf |= SELNLINK; /* * If a device number is defined, locate file system and save its identity. */ if (devs) { for (mp = readmnt(ctx); mp; mp = mp->next) { if (dev == mp->dev) { Lf->fsdir = mkstrcpy(mp->dir, (MALLOC_S *)NULL); Lf->fsdev = mkstrcpy(mp->fsname, (MALLOC_S *)NULL); if (mp->is_nfs && Fnfs) Lf->sf |= SELNFS; break; } } } /* * Save the file size. */ switch (Ntype) { case N_CHR: case N_FIFO: break; default: Lf->sz = (SZOFFTYPE)vip->vip_vi.vi_stat.vst_size; Lf->sz_def = 1; } /* * Test for specified file. */ if (Sfile && is_file_named(ctx, NULL, ((Ntype == N_CHR) || (Ntype == N_BLK) ? 1 : 0))) { Lf->sf |= SELNM; } /* * Enter name characters. */ if (!Lf->nm && Namech[0]) enter_nm(ctx, Namech); } /* * err2nm() -- convert errno to a message in Namech */ void err2nm(struct lsof_context *ctx, /* context */ char *pfx) /* Namech message prefix */ { char *sfx; switch (errno) { case EBADF: /* * The file descriptor is no longer available. */ sfx = "FD unavailable"; break; case ESRCH: /* * The process is no longer available. */ sfx = "process unavailable"; break; default: /* * All other errors are reported with strerror() information. */ sfx = strerror(errno); } (void)snpf(Namech, Namechl, "%s: %s", pfx, sfx); enter_nm(ctx, Namech); } /* * process_atalk() -- process an Apple Talk file */ void process_atalk(struct lsof_context *ctx, /* context */ int pid, /* PID */ int32_t fd) /* FD */ { Lf->type = LSOF_FILE_APPLETALK; return; } /* * process_fsevents() -- process a file system events file */ void process_fsevents(struct lsof_context *ctx, /* context */ int pid, /* PID */ int32_t fd) /* FD */ { Lf->type = LSOF_FILE_FSEVENTS; } /* * * process_fsevents() -- process a network policy file * see also - https://github.com/apple-opensource/lsof/blob/da09c8c6436286e5bd8c400b42e86b54404f12a7/lsof/dialects/darwin/libproc/dnetpolicy.c */ void process_netpolicy(struct lsof_context *ctx, /* context */ int pid, /* PID */ int32_t fp) /* fd */ { Lf->type = LSOF_FILE_NPOLICY; } /* * process_kqueue() -- process a kernel queue file */ void process_kqueue(struct lsof_context *ctx, /* context */ int pid, /* PID */ int32_t fd) /* FD */ { struct kqueue_fdinfo kq; int nb; /* * Get the kernel queue file information. */ Lf->type = LSOF_FILE_KQUEUE; nb = proc_pidfdinfo(pid, fd, PROC_PIDFDKQUEUEINFO, &kq, sizeof(kq)); if (nb <= 0) { (void)err2nm(ctx, "kqueue"); return; } else if (nb < sizeof(kq)) { (void)fprintf( stderr, "%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDKQUEUEINFO);\n", Pn, pid, fd); (void)fprintf(stderr, " too few bytes; expected %ld, got %d\n", sizeof(kq), nb); Error(ctx); } /* * Enter the kernel queue file information. */ enter_file_info(ctx, &kq.pfi); /* * Enter queue counts as NAME column information. */ (void)snpf(Namech, Namechl, "count=%" SZOFFPSPEC "u, state=%#x", (SZOFFTYPE)kq.kqueueinfo.kq_stat.vst_size, kq.kqueueinfo.kq_state); enter_nm(ctx, Namech); } /* * process_pipe() -- process pipe file */ static void process_pipe_common(struct lsof_context *ctx, struct pipe_fdinfo *pi) { char dev_ch[32], *ep; size_t sz; Lf->type = LSOF_FILE_PIPE; /* * Enter the pipe handle as the device. */ (void)snpf(dev_ch, sizeof(dev_ch), "%s", print_kptr((KA_T)pi->pipeinfo.pipe_handle, (char *)NULL, 0)); enter_dev_ch(ctx, dev_ch); /* * Enable offset or size reporting. */ Lf->sz = (SZOFFTYPE)pi->pipeinfo.pipe_stat.vst_blksize; Lf->sz_def = 1; /* * If there is a peer handle, enter it in as NAME column information. */ if (pi->pipeinfo.pipe_peerhandle) { (void)snpf( Namech, Namechl, "->%s", print_kptr((KA_T)pi->pipeinfo.pipe_peerhandle, (char *)NULL, 0)); enter_nm(ctx, Namech); } else Namech[0] = '\0'; /* * If the pipe has a count, add it to the NAME column. */ if (pi->pipeinfo.pipe_stat.vst_size) { ep = endnm(ctx, &sz); (void)snpf(ep, sz, ", cnt=%" SZOFFPSPEC "u", (SZOFFTYPE)pi->pipeinfo.pipe_stat.vst_size); } } void process_pipe(struct lsof_context *ctx, /* context */ int pid, /* PID */ int32_t fd) /* FD */ { int nb; struct pipe_fdinfo pi; /* * Get pipe file information. */ nb = proc_pidfdinfo(pid, fd, PROC_PIDFDPIPEINFO, &pi, sizeof(pi)); if (nb <= 0) { (void)err2nm(ctx, "pipe"); return; } else if (nb < sizeof(pi)) { (void)fprintf( stderr, "%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDPIPEINFO);\n", Pn, pid, fd); (void)fprintf(stderr, " too few bytes; expected %ld, got %d\n", sizeof(pi), nb); Error(ctx); } process_pipe_common(ctx, &pi); } #if defined(PROC_PIDLISTFILEPORTS) void process_fileport_pipe(struct lsof_context *ctx, /* context */ int pid, /* PID */ uint32_t fp) /* FILEPORT */ { int nb; struct pipe_fdinfo pi; /* * Get pipe file information. */ nb = proc_pidfileportinfo(pid, fp, PROC_PIDFILEPORTPIPEINFO, &pi, sizeof(pi)); if (nb <= 0) { (void)err2nm(ctx, "pipe"); return; } else if (nb < sizeof(pi)) { (void)fprintf(stderr, "%s: PID %d, FILEPORT %u; " "proc_pidfileportinfo(PROC_PIDFILEPORTPIPEINFO);\n", Pn, pid, fp); (void)fprintf(stderr, " too few bytes; expected %ld, got %d\n", sizeof(pi), nb); Error(ctx); } process_pipe_common(ctx, &pi); } #endif /* PROC_PIDLISTFILEPORTS */ /* * process_psem() -- process a POSIX semaphore file */ void process_psem(struct lsof_context *ctx, /* context */ int pid, /* PID */ int32_t fd) /* FD */ { int nb; struct psem_fdinfo ps; /* * Get the semaphore file information. */ Lf->type = LSOF_FILE_POSIX_SEMA; nb = proc_pidfdinfo(pid, fd, PROC_PIDFDPSEMINFO, &ps, sizeof(ps)); if (nb <= 0) { (void)err2nm(ctx, "semaphore"); return; } else if (nb < sizeof(ps)) { (void)fprintf( stderr, "%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDPSEMINFO);\n", Pn, pid, fd); (void)fprintf(stderr, " too few bytes; expected %ld, got %d\n", sizeof(ps), nb); Error(ctx); } /* * Enter the semaphore file information. */ enter_file_info(ctx, &ps.pfi); /* * If there is a semaphore file name, enter it. */ if (ps.pseminfo.psem_name[0]) { ps.pseminfo.psem_name[sizeof(ps.pseminfo.psem_name) - 1] = '\0'; (void)snpf(Namech, Namechl, "%s", ps.pseminfo.psem_name); enter_nm(ctx, Namech); } } /* * process_pshm() -- process POSIX shared memory file */ static void process_pshm_common(struct lsof_context *ctx, struct pshm_fdinfo *ps) { Lf->type = LSOF_FILE_POSIX_SHM; /* * Enter the POSIX shared memory file information. */ enter_file_info(ctx, &ps->pfi); /* * If the POSIX shared memory file has a path name, enter it; otherwise, * if it has a mapping address, enter that. */ if (ps->pshminfo.pshm_name[0]) { ps->pshminfo.pshm_name[sizeof(ps->pshminfo.pshm_name) - 1] = '\0'; (void)snpf(Namech, Namechl, "%s", ps->pshminfo.pshm_name); enter_nm(ctx, Namech); } else if (ps->pshminfo.pshm_mappaddr) { (void)snpf( Namech, Namechl, "obj=%s", print_kptr((KA_T)ps->pshminfo.pshm_mappaddr, (char *)NULL, 0)); enter_nm(ctx, Namech); } /* * Enable offset or size reporting. */ Lf->sz = (SZOFFTYPE)ps->pshminfo.pshm_stat.vst_size; Lf->sz_def = 1; } void process_pshm(struct lsof_context *ctx, /* context */ int pid, /* PID */ int32_t fd) /* FD */ { int nb; struct pshm_fdinfo ps; /* * Get the POSIX shared memory file information. */ nb = proc_pidfdinfo(pid, fd, PROC_PIDFDPSHMINFO, &ps, sizeof(ps)); if (nb <= 0) { (void)err2nm(ctx, "POSIX shared memory"); return; } else if (nb < sizeof(ps)) { (void)fprintf( stderr, "%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDPSHMINFO);\n", Pn, pid, fd); (void)fprintf(stderr, " too few bytes; expected %ld, got %d\n", sizeof(ps), nb); Error(ctx); } process_pshm_common(ctx, &ps); } #if defined(PROC_PIDLISTFILEPORTS) void process_fileport_pshm(struct lsof_context *ctx, /* context */ int pid, /* PID */ uint32_t fp) /* FILEPORT */ { int nb; struct pshm_fdinfo ps; /* * Get the POSIX shared memory file information. */ nb = proc_pidfileportinfo(pid, fp, PROC_PIDFILEPORTPSHMINFO, &ps, sizeof(ps)); if (nb <= 0) { (void)err2nm(ctx, "POSIX shared memory"); return; } else if (nb < sizeof(ps)) { (void)fprintf(stderr, "%s: PID %d, FILEPORT %u; " "proc_pidfileportinfo(PROC_PIDFILEPORTPSHMINFO);\n", Pn, pid, fp); (void)fprintf(stderr, " too few bytes; expected %ld, got %d\n", sizeof(ps), nb); Error(ctx); } process_pshm_common(ctx, &ps); } #endif /* PROC_PIDLISTFILEPORTS */ /* * process_vnode() -- process a vnode file */ static void process_vnode_common(struct lsof_context *ctx, struct vnode_fdinfowithpath *vi) { /* * Enter the file and vnode information. */ enter_file_info(ctx, &vi->pfi); enter_vnode_info(ctx, &vi->pvip); } void process_vnode(struct lsof_context *ctx, /* context */ int pid, /* PID */ int32_t fd) /* FD */ { int nb; struct vnode_fdinfowithpath vi; nb = proc_pidfdinfo(pid, fd, PROC_PIDFDVNODEPATHINFO, &vi, sizeof(vi)); if (nb <= 0) { if (errno == ENOENT) { /* * The file descriptor's vnode may have been revoked. This is a * bit of a hack, since an ENOENT error might not always mean * the descriptor's vnode has been revoked. As the libproc API * matures, this code may need to be revisited. */ enter_nm(ctx, "(revoked)"); } else (void)err2nm(ctx, "vnode"); return; } else if (nb < sizeof(vi)) { (void)fprintf( stderr, "%s: PID %d, FD %d: proc_pidfdinfo(PROC_PIDFDVNODEPATHINFO);\n", Pn, pid, fd); (void)fprintf(stderr, " too few bytes; expected %ld, got %d\n", sizeof(vi), nb); Error(ctx); } process_vnode_common(ctx, &vi); } #if defined(PROC_PIDLISTFILEPORTS) void process_fileport_vnode(struct lsof_context *ctx, /* context */ int pid, /* PID */ uint32_t fp) /* FILEPORT */ { int nb; struct vnode_fdinfowithpath vi; nb = proc_pidfileportinfo(pid, fp, PROC_PIDFILEPORTVNODEPATHINFO, &vi, sizeof(vi)); if (nb <= 0) { if (errno == ENOENT) { /* * The file descriptor's vnode may have been revoked. This is a * bit of a hack, since an ENOENT error might not always mean * the descriptor's vnode has been revoked. As the libproc API * matures, this code may need to be revisited. */ enter_nm(ctx, "(revoked)"); } else (void)err2nm(ctx, "vnode"); return; } else if (nb < sizeof(vi)) { (void)fprintf(stderr, "%s: PID %d, FILEPORT %u: " "proc_pidfdinfo(PROC_PIDFDVNODEPATHINFO);\n", Pn, pid, fp); (void)fprintf(stderr, " too few bytes; expected %ld, got %d\n", sizeof(vi), nb); Error(ctx); } process_vnode_common(ctx, &vi); } #endif /* PROC_PIDLISTFILEPORTS */