From d7c75c7a20590cab729c3d653aaa91a4960d6165 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Wed, 6 May 2009 16:57:44 -0700 Subject: [PATCH] fstest regression fixes - POSIX error codes. Deal with most of the issues found by FreeBSD's fstest regression test: * Limit path components to 255 characters. Return ENAMETOOLONG if the limit is exceeded. * Return EEXIST, EINVAL, and ENOTEMPTY as appropriate when the user attempts to create, delete, or rename "." or "..", instead of EINVAL. * Return EISDIR if an attempt is made to open a directory for writing, instead of EINVAL. * Return EACCES if an attempt is made to open a file O_TRUNC without O_RDWR or O_WRONLY, instead of silently dropping the O_TRUNC. * Implement O_NOFOLLOW semantics generally instead of just with O_EXCL. Not dealt with: * DragonFly clears SGID AND SUID on uid or gid change, if not root. If root is doing the operation SGID/SUID is not cleared. * HAMMER cannot modify the ctime without rolling a new inode, which is very expensive, and does not do so when entries are added or removed from a directory. mtime is modified. --- sys/kern/vfs_helper.c | 6 ++++++ sys/kern/vfs_nlookup.c | 23 ++++++++++++++++++++--- sys/kern/vfs_vnops.c | 10 ++++++++-- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/sys/kern/vfs_helper.c b/sys/kern/vfs_helper.c index 531fd3e28d..1b2f6a53a2 100644 --- a/sys/kern/vfs_helper.c +++ b/sys/kern/vfs_helper.c @@ -247,6 +247,12 @@ vop_helper_chown(struct vnode *vp, uid_t new_uid, gid_t new_gid, *cur_uidp = new_uid; *cur_gidp = new_gid; /* XXX QUOTA CODE */ + + /* + * DragonFly clears both SUID and SGID if either the owner or + * group is changed and root isn't doing it. If root is doing + * it we do not clear SUID/SGID. + */ if (cred->cr_uid != 0 && (ouid != new_uid || ogid != new_gid)) *cur_modep &= ~(S_ISUID | S_ISGID); return(0); diff --git a/sys/kern/vfs_nlookup.c b/sys/kern/vfs_nlookup.c index ab783b8333..09758a6c19 100644 --- a/sys/kern/vfs_nlookup.c +++ b/sys/kern/vfs_nlookup.c @@ -375,12 +375,17 @@ nlookup(struct nlookupdata *nd) break; /* - * Extract the path component + * Extract the path component. Path components are limited to + * 255 characters. */ nlc.nlc_nameptr = ptr; while (*ptr && *ptr != '/') ++ptr; nlc.nlc_namelen = ptr - nlc.nlc_nameptr; + if (nlc.nlc_namelen >= 256) { + error = ENAMETOOLONG; + break; + } /* * Lookup the path component in the cache, creating an unresolved @@ -424,7 +429,7 @@ nlookup(struct nlookupdata *nd) KKASSERT(nch.ncp != NULL); cache_get(&nch, &nch); } - wasdotordotdot = 1; + wasdotordotdot = 2; } else { nch = cache_nlookup(&nd->nl_nch, &nlc); while ((error = cache_resolve(&nch, nd->nl_cred)) == EAGAIN) { @@ -496,7 +501,15 @@ nlookup(struct nlookupdata *nd) if (error == 0 && wasdotordotdot && (nd->nl_flags & (NLC_CREATE | NLC_DELETE | NLC_RENAME_SRC | NLC_RENAME_DST))) { - error = EINVAL; + /* + * POSIX junk + */ + if (nd->nl_flags & NLC_CREATE) + error = EEXIST; + else if (nd->nl_flags & NLC_DELETE) + error = (wasdotordotdot == 1) ? EINVAL : ENOTEMPTY; + else + error = EINVAL; } } @@ -854,6 +867,9 @@ naccess(struct nchandle *nch, int nflags, struct ucred *cred, int *nflagsp) case VCHR: case VBLK: break; + case VDIR: + error = EISDIR; + break; default: error = EINVAL; break; @@ -943,6 +959,7 @@ naccess_va(struct vattr *va, int nflags, struct ucred *cred) if (nflags & (NLC_WRITE | NLC_TRUNCATE)) { switch(va->va_type) { case VDIR: + return (EISDIR); case VLNK: case VREG: case VDATABASE: diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 4bdf93396f..89c30f8962 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -133,6 +133,12 @@ vn_open(struct nlookupdata *nd, struct file *fp, int fmode, int cmode) struct vattr *vap = &vat; int error; + /* + * Certain combinations are illegal + */ + if ((fmode & (FWRITE | O_TRUNC)) == O_TRUNC) + return(EACCES); + /* * Lookup the path and create or obtain the vnode. After a * successful lookup a locked nd->nl_nch will be returned. @@ -151,6 +157,8 @@ vn_open(struct nlookupdata *nd, struct file *fp, int fmode, int cmode) nd->nl_flags |= NLC_READ; if (fmode & FWRITE) nd->nl_flags |= NLC_WRITE; + if ((fmode & O_EXCL) == 0 && (fmode & O_NOFOLLOW) == 0) + nd->nl_flags |= NLC_FOLLOW; if (fmode & O_CREAT) { /* @@ -163,8 +171,6 @@ vn_open(struct nlookupdata *nd, struct file *fp, int fmode, int cmode) * write permission on the governing directory or EPERM * is returned. */ - if ((fmode & O_EXCL) == 0 && (fmode & O_NOFOLLOW) == 0) - nd->nl_flags |= NLC_FOLLOW; nd->nl_flags |= NLC_CREATE; nd->nl_flags |= NLC_REFDVP; bwillinode(1); -- 2.41.0