opt
/
kaspersky
/
kav4fs
/
src
/
kernel
/
module.freebsd
➕ New
📤 Upload
✎ Editing:
files.c
← Back
/* * This source file is a part of a Kaspersky Antivirus Monitor. * Copyright (C) Kaspersky Lab, 1997-2010 * See License.txt for details * */ #include "module.h" #include <ufs/ufs/dir.h> /* XXX only for DIRBLKSIZ */ #define DIRENT_MINSIZE (sizeof(struct dirent) - (MAXNAMLEN+1) + 4) int vnode_info(struct thread *thr, struct vnode *vp, file_info *info, file_info_ex *info_ex); extern int vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir, char *buf, char **retbuf, u_int buflen) __attribute__((regparm(3))); #if defined (__FreeBSD_version) && __FreeBSD_version < 800000 #define COMPAT_FULLPATH_LOCK(fdp) FILEDESC_SLOCK(fdp) #define COMPAT_FULLPATH_UNLOCK(fdp) FILEDESC_SUNLOCK(fdp) #define COMPAT_VOP_GETATTR(vn, attr, ucred, thr) VOP_GETATTR(vn, attr, ucred, thr) #define COMPAT_VN_LOCK(vn, flags, thr) vn_lock(vn, flags, thr) #define COMPAT_VOP_UNLOCK(vn, flags, thr) VOP_UNLOCK(vn, flags, thr) #else #define COMPAT_FULLPATH_LOCK(fdp) #define COMPAT_FULLPATH_UNLOCK(fdp) #define COMPAT_VOP_GETATTR(vn, attr, ucred, thr) VOP_GETATTR(vn, attr, ucred) #define COMPAT_VN_LOCK(vn, flags, thr) vn_lock(vn, flags) #define COMPAT_VOP_UNLOCK(vn, flags, thr) VOP_UNLOCK(vn, flags) #endif static char* get_fname_part(char *buf, char *bufend) { char *part, *res; int len; for(part = bufend - 50; part > buf && *part != '/'; --part); if(part != buf) { ++part; goto l_exit; } for(part = bufend - 50; part < bufend && *part != '/'; ++part); if(part != bufend) { return ++part; goto l_exit; } part = bufend - 50; l_exit: len = bufend - part; res = MEM_ALLOC(len); if(res) { memcpy(res, part, len); res[len-1] = 0; } return res; } static int my_vn_fullpath_global(struct thread *td, struct vnode *vn, char **retbuf, char **freebuf, char **fname_part) { char *buf; struct filedesc *fdp; int error; int bufsz = MAXPATHLEN; if (vn == NULL) return (EINVAL); while(1) { buf = MEM_ALLOC(bufsz); if(!buf) { error = ENOMEM; break; } fdp = td->td_proc->p_fd; COMPAT_FULLPATH_LOCK(fdp); error = vn_fullpath1(td, vn, rootvnode, buf, retbuf, bufsz); COMPAT_FULLPATH_UNLOCK(fdp); if(ENOMEM == error) { bufsz *= 2; if(bufsz > m_config.max_fname_len) { if(fname_part) *fname_part = get_fname_part(buf, buf + bufsz/2); error = ENAMETOOLONG; break; } MEM_FREE(buf); continue; } break; } if (!error) *freebuf = buf; else if(buf) MEM_FREE(buf); return (error); } static int my_vn_fullpath_global_reliable_scandir(struct vnode **lvpp, struct vnode **uvpp, char **bpp, char *bufp, struct thread *td) { int error = 0; int eofflag; off_t off; int tries; struct uio uio; struct iovec iov; char *dirbuf = NULL; int dirbuflen; ino_t fileno; struct vattr va; struct vnode *uvp = NULL; struct vnode *lvp = *lvpp; struct componentname cn; int len, reclen; tries = 0; /* * If we want the filename, get some info we need while the * current directory is still locked. */ if (bufp != NULL) { error = COMPAT_VOP_GETATTR(lvp, &va, td->td_ucred, td); if (error) { vput(lvp); *lvpp = NULL; *uvpp = NULL; return error; } } /* * Ok, we have to do it the hard way.. * Next, get parent vnode using lookup of .. */ cn.cn_nameiop = LOOKUP; cn.cn_flags = ISLASTCN | ISDOTDOT | RDONLY; cn.cn_thread = td; cn.cn_cred = td->td_ucred; cn.cn_pnbuf = NULL; cn.cn_nameptr = ".."; cn.cn_namelen = 2; cn.cn_consume = 0; cn.cn_lkflags = LK_SHARED; /* * At this point, lvp is locked and will be unlocked by the lookup. * On successful return, *uvpp will be locked */ error = VOP_LOOKUP(lvp, uvpp, &cn); if (error) { vput(lvp); *lvpp = NULL; *uvpp = NULL; return error; } uvp = *uvpp; /* If we don't care about the pathname, we're done */ if (bufp == NULL) { vput(lvp); *lvpp = NULL; return 0; } fileno = va.va_fileid; dirbuflen = DIRBLKSIZ; if (dirbuflen < va.va_blocksize) dirbuflen = va.va_blocksize; dirbuf = (char *)malloc(dirbuflen, M_TEMP, M_WAITOK); off = 0; do { /* call VOP_READDIR of parent */ iov.iov_base = dirbuf; iov.iov_len = dirbuflen; uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_offset = off; uio.uio_resid = dirbuflen; uio.uio_segflg = UIO_SYSSPACE; uio.uio_rw = UIO_READ; uio.uio_td = td; eofflag = 0; error = VOP_READDIR(uvp, &uio, td->td_ucred, &eofflag, 0, 0); off = uio.uio_offset; /* * Try again if NFS tosses its cookies. * XXX this can still loop forever if the directory is busted * such that the second or subsequent page of it always * returns EINVAL */ if ((error == EINVAL) && (tries < 3)) { off = 0; tries++; continue; /* once more, with feeling */ } if (!error) { char *cpos; struct dirent *dp; cpos = dirbuf; tries = 0; /* scan directory page looking for matching vnode */ for (len = (dirbuflen - uio.uio_resid); len > 0; len -= reclen) { dp = (struct dirent *) cpos; reclen = dp->d_reclen; /* check for malformed directory.. */ if (reclen < DIRENT_MINSIZE) { error = EINVAL; goto out; } /* * XXX should perhaps do VOP_LOOKUP to * check that we got back to the right place, * but getting the locking games for that * right would be heinous. */ if ((dp->d_type != DT_WHT) && (dp->d_fileno == fileno)) { char *bp = *bpp; bp -= dp->d_namlen; if (bp <= bufp) { error = ENAMETOOLONG; goto out; } bcopy(dp->d_name, bp, dp->d_namlen); error = 0; *bpp = bp; goto out; } cpos += reclen; } } } while (!eofflag); error = ENOENT; out: vput(lvp); *lvpp = NULL; free(dirbuf, M_TEMP); return error; } static int my_vn_fullpath_global_reliable_impl(struct vnode *vn, char **bpp, char *bufp, int limit, struct thread *td) { struct vnode *uvp = NULL, *rvp = rootvnode, *lvp = vn; char *bp = NULL; int error; VREF(rvp); VREF(lvp); /* * Error handling invariant: * Before a `goto out': * lvp is either NULL, or locked and held. * uvp is either NULL, or locked and held. */ error = COMPAT_VN_LOCK(lvp, LK_EXCLUSIVE | LK_RETRY, td); if (error != 0) { PRN_ERR("KAVMOD: vn_lock LK_RETRY returned error %d", error); goto out; } if (bufp) bp = *bpp; /* * this loop will terminate when one of the following happens: * - we hit the root * - getdirentries or lookup fails * - we run out of space in the buffer. */ if (lvp == rvp) { if (bp) *(--bp) = '/'; goto out; } do { if (lvp->v_type != VDIR) { error = ENOTDIR; goto out; } /* * step up if we're a covered vnode.. */ while (lvp->v_vflag & VV_ROOT) { struct vnode *tvp; if (lvp == rvp) goto out; tvp = lvp; lvp = lvp->v_mount->mnt_vnodecovered; vput(tvp); /* * hodie natus est radici frater */ if (lvp == NULL) { error = ENOENT; goto out; } VREF(lvp); error = COMPAT_VN_LOCK(lvp, LK_EXCLUSIVE | LK_RETRY, td); if (error != 0) { PRN_ERR("KAVMOD: vn_lock LK_RETRY returned %d", error); goto out; } } error = my_vn_fullpath_global_reliable_scandir(&lvp, &uvp, &bp, bufp, td); if (error) goto out; if (bp) *(--bp) = '/'; lvp = uvp; uvp = NULL; limit--; } while ((lvp != rvp) && (limit > 0)); out: if (bpp) *bpp = bp; if (uvp) vput(uvp); if (lvp) vput(lvp); vrele(rvp); return error; } static int my_vn_fullpath_global_reliable(struct thread *thr, const char *u_filename, char **retbuf, char **freebuf, char **fname_part) { int res, bufsz = MAXPATHLEN*4; size_t fnamesz; char *buf, *buf_val, *dir_end, *fn_end; struct vnode *vn; buf = MEM_ALLOC(bufsz); if(!buf) return ENOMEM; res = copyinstr(u_filename, buf, MAXPATHLEN, &fnamesz); if(0 != res) goto l_err; if(fnamesz < 2) { res = ENOENT; goto l_err; } fn_end = buf + fnamesz; for(buf_val = fn_end-2; *buf_val != '/' && buf_val > buf; --buf_val); dir_end = buf_val; if(*buf_val == '/') ++buf_val; fnamesz = fn_end - buf_val; memcpy(buf + bufsz - fnamesz, buf_val, fnamesz); bufsz -= fnamesz; buf_val = buf + bufsz - 1; *buf_val = '/'; if(dir_end == buf) { if('/' == *dir_end) vn = thr->td_proc->p_fd->fd_rdir; else vn = thr->td_proc->p_fd->fd_cdir; } else { struct nameidata nd; *dir_end = 0; NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, thr); res = namei(&nd); if(0 != res) { NDFREE (&nd, 0); goto l_err; } vn = nd.ni_vp; NDFREE (&nd, 0); } mtx_lock(&Giant); res = my_vn_fullpath_global_reliable_impl(vn, &buf_val, buf, bufsz/2, thr); mtx_unlock(&Giant); if(0 != res) goto l_err; *freebuf = buf; *retbuf = buf_val; return 0; l_err: MEM_FREE(buf); return res; } int get_file_from_userspace (struct thread *thr, const char *u_filename, file_info *info, char **filename, file_info_ex *info_ex, char **fname_part) { struct proc *p = thr->td_proc; struct nameidata nd; struct vattr attr; char * retbuf, * buf, *freebuf; int res, strsz; int vfslocked; memset(info, 0, sizeof(*info)); NDINIT (&nd, LOOKUP, FOLLOW, UIO_USERSPACE, u_filename, thr); *filename = NULL; res = namei(&nd); if (0 != res) { NDFREE (&nd, 0); return res; } vfslocked = NDHASGIANT(&nd); COMPAT_VN_LOCK(nd.ni_vp, LK_SHARED | LK_RETRY, thr); res = COMPAT_VOP_GETATTR (nd.ni_vp, &attr, p->p_ucred, thr); COMPAT_VOP_UNLOCK(nd.ni_vp, 0, thr); if(0 == res && (attr.va_type != VREG || 0 == attr.va_size)) res = -1; if(0 != res) { NDFREE (&nd, 0); VFS_UNLOCK_GIANT(vfslocked); return res; } if (attr.va_fsid!=VNOVAL) info->dev = attr.va_fsid; else info->dev = nd.ni_vp->v_mount->mnt_stat.f_fsid.val[0]; info->ino = attr.va_fileid; info->m_time = attr.va_mtime; info->c_time = attr.va_ctime; info->n_links = attr.va_nlink; info->size = attr.va_size; if(info_ex) { info_ex->owner_uid = attr.va_uid; info_ex->file_mode = attr.va_mode; info_ex->fstypename = nd.ni_vp->v_tag; } res = my_vn_fullpath_global(thr, nd.ni_vp, &retbuf, &freebuf, fname_part); if(ENOENT == res) { res = my_vn_fullpath_global_reliable(thr, u_filename, &retbuf, &freebuf, fname_part); } if(0 != res) { NDFREE (&nd, 0); VFS_UNLOCK_GIANT(vfslocked); return res; } NDFREE (&nd, 0); VFS_UNLOCK_GIANT(vfslocked); strsz = strlen(retbuf)+1; buf = MEM_ALLOC(strsz); if(buf) { memcpy(buf, retbuf, strsz); MEM_FREE(freebuf); } else { memmove(freebuf, retbuf, strsz); } *filename = buf; return 0; } char * get_filename_by_file(struct thread *thr, struct file *fp, file_info *info, file_info_ex *info_ex) { char * retbuf, * buf, *freebuf; int strsz; if (vnode_info(thr, (struct vnode *)fp->f_data, info, info_ex)) return NULL; if(my_vn_fullpath_global(thr, (struct vnode *)fp->f_data, &retbuf, &freebuf, NULL)) { return NULL; } strsz = strlen(retbuf) + 1; buf = MEM_ALLOC(strsz); if(buf) { memcpy(buf, retbuf, strsz); MEM_FREE(freebuf); } else { memmove(freebuf, retbuf, strsz); buf = freebuf; } return buf; } int get_exec_info(struct thread * thr,file_info * info) { struct proc * p = thr->td_proc; struct vnode * vp = p->p_textvp; return vnode_info(thr,vp,info,NULL); } int vnode_info(struct thread *thr, struct vnode *vp, file_info *info, file_info_ex *info_ex) { struct proc *p = thr->td_proc; struct vattr attr; if (COMPAT_VOP_GETATTR (vp, &attr, p->p_ucred, thr)) return 1; if (attr.va_fsid!=VNOVAL) info->dev = attr.va_fsid; else info->dev = vp->v_mount->mnt_stat.f_fsid.val[0]; info->ino = attr.va_fileid; info->m_time = attr.va_mtime; info->c_time = attr.va_ctime; info->n_links = attr.va_nlink; info->size = attr.va_size; if(info_ex) { info_ex->owner_uid = attr.va_uid; info_ex->file_mode = attr.va_mode; info_ex->fstypename = vp->v_tag; } return 0; }
💾 Save Changes
Cancel
📤 Upload File
×
Select File
Upload
Cancel
➕ Create New
×
Type
📄 File
📁 Folder
Name
Create
Cancel
✎ Rename Item
×
Current Name
New Name
Rename
Cancel
🔐 Change Permissions
×
Target File
Permission (e.g., 0755, 0644)
0755
0644
0777
Apply
Cancel