lkml.org 
[lkml]   [1998]   [Nov]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Subject[PATCH] (That Works) Security patch for fs/nfsd
Date
From
>>> Linus Torvalds said:
> Note that I wasn't talking about your fixes - I was really pissed off
> becasue the last set of patches I tried to apply from this list (from
> Morris) didn't even pass through "patch" without patch complaining. And it
> wasn't the first time that had happened. When somethng like that keeps on
> happening, I just keep wondering..

Please accept my apologies! Below is a patch that will go through `patch'.

>>>"G. Allen Morris III" said:
Patch to linux 2.1.127 for fs/nfsd/

The sub-mount patch was overly restrictive. This one, I hope, acts
more like the local filesystems.

1. [SECURITY] It seems that knfsd does not test permissions correctly
for SETATTR. I think this has been fixed by adding:
err = inode_change_ok(inode, iap);

2. On root_squashed exports root could not mount subdirectories/files
that where in directories where `nobody' didn't have EXECUTE permition.
This was true even if other users would be able to access that
directory.

You can now get access through directories that are EXECUTABLE
by anyone other than root (or if you can become root).

3. All file capabilities are reset now unless access is by root.

Patch is also available at:
http://csua.berkeley.edu/~gam3/knfsd/

----------------------- nfsd-2.1.127-5.patch -------------------------------
Index: linux/fs/nfsd/auth.c
diff -u linux/fs/nfsd/auth.c:1.2 linux/fs/nfsd/auth.c:1.2.2.1
--- linux/fs/nfsd/auth.c:1.2 Sat Nov 7 16:43:38 1998
+++ linux/fs/nfsd/auth.c Tue Nov 10 10:31:46 1998
@@ -50,11 +50,10 @@
current->ngroups = i;

if ((cred->cr_uid)) {
- cap_lower(current->cap_effective, CAP_DAC_OVERRIDE);
- cap_lower(current->cap_effective, CAP_DAC_READ_SEARCH);
+ cap_t(current->cap_effective) &= ~CAP_FS_MASK;
} else {
- cap_raise(current->cap_effective, CAP_DAC_OVERRIDE);
- cap_raise(current->cap_effective, CAP_DAC_READ_SEARCH);
+ cap_t(current->cap_effective) |= (CAP_FS_MASK &
+ current->cap_permitted);
}

rqstp->rq_userset = 1;
Index: linux/fs/nfsd/nfsfh.c
diff -u linux/fs/nfsd/nfsfh.c:1.3 linux/fs/nfsd/nfsfh.c:1.3.2.4
--- linux/fs/nfsd/nfsfh.c:1.3 Sat Nov 7 16:43:38 1998
+++ linux/fs/nfsd/nfsfh.c Tue Nov 10 10:31:46 1998
@@ -1093,47 +1093,48 @@
/*
* Security: Check that the export is valid for dentry <gam3@acm.org>
*/
+ error = 0;
if (fh->fh_dev != fh->fh_xdev) {
printk("fh_verify: Security: export on other device"
" (%d, %d).\n", fh->fh_dev, fh->fh_xdev);
- goto out;
+ error = nfserr_stale;
} else if (exp->ex_dentry != dentry) {
struct dentry *tdentry = dentry;
- int err2 = 0;

- error = nfserr_stale;
do {
tdentry = tdentry->d_parent;
- if (exp->ex_dentry == tdentry) {
- error = 0;
+ if (exp->ex_dentry == tdentry)
break;
- }
- if ((err2 = nfsd_permission(exp, tdentry, MAY_READ))) {
- error = err2;
-#ifdef NFSD_PARANOIA
- goto out1;
-#else
- goto out;
-#endif
+ /* executable only by root and we can't be root */
+ if (current->fsuid &&
+ !(tdentry->d_inode->i_uid &&
+ (tdentry->d_inode->i_mode & S_IXUSR)) &&
+ !(tdentry->d_inode->i_gid &&
+ (tdentry->d_inode->i_mode & S_IXGRP)) &&
+ !(tdentry->d_inode->i_mode & S_IXOTH) &&
+ (exp->ex_flags & NFSEXP_ROOTSQUASH)) {
+ error = nfserr_stale;
+dprintk("fh_verify: no root_squashed access.\n");
}
} while ((tdentry != tdentry->d_parent));
- if (error) {
- printk("fh_verify: Security: %s/%s bad export.\n",
+ if (exp->ex_dentry != tdentry) {
+ error = nfserr_stale;
+ printk("nfsd Security: %s/%s bad export.\n",
dentry->d_parent->d_name.name,
dentry->d_name.name);
goto out;
}
}

/* Finally, check access permissions. */
- error = nfsd_permission(exp, dentry, access);
+ if (!error) {
+ error = nfsd_permission(exp, dentry, access);
+ }
#ifdef NFSD_PARANOIA
-out1:
if (error)
printk("fh_verify: %s/%s permission failure, acc=%x, error=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name, access, error);
#endif
-
out:
return error;
}
Index: linux/fs/nfsd/vfs.c
diff -u linux/fs/nfsd/vfs.c:1.5 linux/fs/nfsd/vfs.c:1.5.2.1
--- linux/fs/nfsd/vfs.c:1.5 Sat Nov 7 16:43:38 1998
+++ linux/fs/nfsd/vfs.c Tue Nov 10 10:31:46 1998
@@ -148,16 +148,18 @@
dprintk("nfsd: nfsd_lookup(fh %p, %s)\n", SVCFH_DENTRY(fhp), name);

/* Obtain dentry and export. */
- err = fh_verify(rqstp, fhp, S_IFDIR, MAY_NOP);
+ err = fh_verify(rqstp, fhp, S_IFDIR, MAY_EXEC);
if (err)
goto out;

dparent = fhp->fh_dentry;
exp = fhp->fh_export;

+#if 0
err = nfsd_permission(exp, dparent, MAY_EXEC);
if (err)
goto out;
+#endif
err = nfserr_noent;
if (fs_off_limits(dparent->d_sb))
goto out;
@@ -232,13 +234,17 @@
dentry = fhp->fh_dentry;
inode = dentry->d_inode;

+ err = inode_change_ok(inode, iap);
+ if (err)
+ goto out_nfserr;
+
/* The size case is special... */
if (iap->ia_valid & ATTR_SIZE) {
if (!S_ISREG(inode->i_mode))
printk("nfsd_setattr: size change??\n");
if (iap->ia_size < inode->i_size) {
err = nfsd_permission(fhp->fh_export, dentry, MAY_TRUNC);
- if (err != 0)
+ if (err)
goto out;
}
err = get_write_access(inode);
@@ -1228,8 +1234,7 @@

if (acc == MAY_NOP)
return 0;
-
- /*
+#if 0
dprintk("nfsd: permission 0x%x%s%s%s%s%s mode 0%o%s%s%s\n",
acc,
(acc & MAY_READ)? " read" : "",
@@ -1243,8 +1248,7 @@
IS_RDONLY(inode)? " ro" : "");
dprintk(" owner %d/%d user %d/%d\n",
inode->i_uid, inode->i_gid, current->fsuid, current->fsgid);
- */
-
+#endif
#ifndef CONFIG_NFSD_SUN
if (dentry->d_mounts != dentry) {
return nfserr_perm;
---------------------------------
G. Allen Morris III
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:45    [from the cache]
©2003-2011 Jasper Spaans