Re: NFS question

H.J. Lu (hjl@lucon.org)
Tue, 29 Sep 1998 20:29:07 -0700 (PDT)


>
> Probably I've choosed a wrong person to complain - please, let me know if
> this is the case.
>
> I've exported one directory with ro,root_squash options. And I have one
> file with 711 modes on it, owned by root. Occasionally I've discovered,
> that root user on the machine that mounted that dir can read that file.
> With user-level nfsd (v29) this occurs only after first attempt to execute
> mentioned file. Even if file modes are 000, root is still able to read
> file contents.
>
> As I understand, this could be a difficult problem - in order to execute
> the file OS should read it, and if the kernel faked in some way, admin may
> gain access to any file. But it is true if it is exported to outside, which
> is not the common case. In our network we can control the kernels used, but
> root users on diskless machines are still able read such a files...
>
> Actually I have 2.1.123pre2 and your knfsd from 22.09
>
> Please, drop me a note if my report is accepted or give me a hint - what should
> I do.

Thanks for your bug report. Here is a patch. It is for Linux 2.1.123.
I think it should work for recent kernels also. Please let me know
if it fixes all the ro,root_squash bugs you have. If not, please
tell me how to recreate the bug. I am planning to make a new knfsd
soon.

H.J.
----
Index: fs/nfsd/vfs.c
===================================================================
RCS file: /home/work/cvs/linux/linux/fs/nfsd/vfs.c,v
retrieving revision 1.5
diff -u -r1.5 vfs.c
--- fs/nfsd/vfs.c 1998/09/29 14:33:26 1.5
+++ fs/nfsd/vfs.c 1998/09/30 03:17:21
@@ -267,9 +274,17 @@

/* Change the attributes. */
if (iap->ia_valid) {
+ kernel_cap_t saved_cap;
+
iap->ia_valid |= ATTR_CTIME;
iap->ia_ctime = CURRENT_TIME;
+ if (current->fsuid != 0) {
+ saved_cap = current->cap_effective;
+ cap_clear(current->cap_effective);
+ }
err = notify_change(dentry, iap);
+ if (current->fsuid != 0)
+ current->cap_effective = saved_cap;
if (err)
goto out_nfserr;
if (EX_ISSYNC(fhp->fh_export))
@@ -531,10 +546,17 @@
/* clear setuid/setgid flag after write */
if (err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) {
struct iattr ia;
+ kernel_cap_t saved_cap;

ia.ia_valid = ATTR_MODE;
ia.ia_mode = inode->i_mode & ~(S_ISUID | S_ISGID);
+ if (current->fsuid != 0) {
+ saved_cap = current->cap_effective;
+ cap_clear(current->cap_effective);
+ }
notify_change(dentry, &ia);
+ if (current->fsuid != 0)
+ current->cap_effective = saved_cap;
}

fh_unlock(fhp); /* unlock inode */
@@ -726,6 +748,7 @@
struct inode *inode;
struct iattr newattrs;
int err;
+ kernel_cap_t saved_cap;

err = fh_verify(rqstp, fhp, S_IFREG, MAY_WRITE | MAY_TRUNC);
if (err)
@@ -743,7 +766,13 @@
DQUOT_INIT(inode);
newattrs.ia_size = size;
newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
+ if (current->fsuid != 0) {
+ saved_cap = current->cap_effective;
+ cap_clear(current->cap_effective);
+ }
err = notify_change(dentry, &newattrs);
+ if (current->fsuid != 0)
+ current->cap_effective = saved_cap;
if (!err) {
vmtruncate(inode, size);
if (inode->i_op && inode->i_op->truncate)
@@ -1232,6 +1261,7 @@
{
struct inode *inode = dentry->d_inode;
int err;
+ kernel_cap_t saved_cap;

if (acc == MAY_NOP)
return 0;
@@ -1275,11 +1312,19 @@
if (inode->i_uid == current->fsuid /* && !(acc & MAY_TRUNC) */)
return 0;

+ if (current->fsuid != 0) {
+ saved_cap = current->cap_effective;
+ cap_clear(current->cap_effective);
+ }
+
err = permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC));

/* Allow read access to binaries even when mode 111 */
if (err == -EPERM && S_ISREG(inode->i_mode) && acc == MAY_READ)
err = permission(inode, MAY_EXEC);
+
+ if (current->fsuid != 0)
+ current->cap_effective = saved_cap;

return err? nfserrno(-err) : 0;
}

-
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/