Re: Patch 2.1.129ac2

David Woodhouse (David.Woodhouse@mvhi.com)
Fri, 20 Nov 1998 16:49:59 +0000


This is a multipart MIME message.

--==_Exmh_-5042329040
Content-Type: text/plain; charset=us-ascii

alan@lxorguk.ukuu.org.uk said:
> This is primarily a get in sync release with a few people.

Please also include HJ's nfsd patches, without which knfsd is so bugridden
it's virtually unusable.

The attached patch is an aggregate of all the relevant patches from his latest
knfsd package, along with the extra patch to list the current exports in
/proc/fs/nfs/exports

As these patches have been part of the knfsd package for some time, and they
have been part of the installation procedure for knfsd, the bugs they fix have
not been reported much recently. However, that doesn't make the patches any
less important.

--==_Exmh_-5042329040
Content-Type: text/plain; name="nfs-all-patches-2.1.129"; charset=us-ascii
Content-Description: nfs-all-patches-2.1.129
Content-Disposition: attachment; filename="nfs-all-patches-2.1.129"

Index: fs/lockd/clntproc.c
===================================================================
RCS file: /cvs/linux/fs/lockd/clntproc.c,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 clntproc.c
--- fs/lockd/clntproc.c 1998/11/04 20:00:06 1.1.1.3
+++ fs/lockd/clntproc.c 1998/11/20 15:05:27
@@ -125,7 +125,8 @@

/* If we're cleaning up locks because the process is exiting,
* perform the RPC call asynchronously. */
- if (cmd == F_SETLK && fl->fl_type == F_UNLCK
+ if ((cmd == F_SETLK || cmd == F_SETLKW)
+ && fl->fl_type == F_UNLCK
&& (current->flags & PF_EXITING)) {
sigfillset(&current->blocked); /* Mask all signals */
recalc_sigpending(current);
@@ -144,7 +145,8 @@

if (cmd == F_GETLK) {
status = nlmclnt_test(call, fl);
- } else if (cmd == F_SETLK && fl->fl_type == F_UNLCK) {
+ } else if ((cmd == F_SETLK || cmd == F_SETLKW)
+ && fl->fl_type == F_UNLCK) {
status = nlmclnt_unlock(call, fl);
} else if (cmd == F_SETLK || cmd == F_SETLKW) {
call->a_args.block = (cmd == F_SETLKW)? 1 : 0;
Index: fs/lockd/host.c
===================================================================
RCS file: /cvs/linux/fs/lockd/host.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 host.c
--- fs/lockd/host.c 1998/10/28 21:23:42 1.1.1.1
+++ fs/lockd/host.c 1998/11/20 15:05:27
@@ -180,12 +180,15 @@
host->h_nextrebind - jiffies);
}
} else {
- uid_t saved_euid = current->euid;
+ uid_t saved_fsuid = current->fsuid;
+ kernel_cap_t saved_cap = current->cap_effective;

/* Create RPC socket as root user so we get a priv port */
- current->euid = 0;
+ current->fsuid = 0;
+ cap_raise (current->cap_effective, CAP_NET_BIND_SERVICE);
xprt = xprt_create_proto(host->h_proto, &host->h_addr, NULL);
- current->euid = saved_euid;
+ current->fsuid = saved_fsuid;
+ current->cap_effective = saved_cap;
if (xprt == NULL)
goto forgetit;

Index: fs/lockd/svcproc.c
===================================================================
RCS file: /cvs/linux/fs/lockd/svcproc.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 svcproc.c
--- fs/lockd/svcproc.c 1998/10/28 21:23:42 1.1.1.1
+++ fs/lockd/svcproc.c 1998/11/20 15:05:27
@@ -499,15 +499,22 @@
/*
* NLM Server procedures.
*/
-#define nlmsvc_proc_none NULL
-#define nlmsvc_encode_norep NULL
-#define nlmsvc_decode_norep NULL
-#define nlmsvc_decode_testres NULL
-#define nlmsvc_proc_test_res NULL
-#define nlmsvc_proc_lock_res NULL
-#define nlmsvc_proc_cancel_res NULL
-#define nlmsvc_proc_unlock_res NULL
-#define nlmsvc_proc_granted_res NULL
+
+#define nlmsvc_encode_norep nlmsvc_encode_void
+#define nlmsvc_decode_norep nlmsvc_decode_void
+#define nlmsvc_decode_testres nlmsvc_decode_void
+#define nlmsvc_decode_lockres nlmsvc_decode_void
+#define nlmsvc_decode_unlockres nlmsvc_decode_void
+#define nlmsvc_decode_cancelres nlmsvc_decode_void
+#define nlmsvc_decode_grantedres nlmsvc_decode_void
+
+#define nlmsvc_proc_none nlmsvc_proc_null
+#define nlmsvc_proc_test_res nlmsvc_proc_null
+#define nlmsvc_proc_lock_res nlmsvc_proc_null
+#define nlmsvc_proc_cancel_res nlmsvc_proc_null
+#define nlmsvc_proc_unlock_res nlmsvc_proc_null
+#define nlmsvc_proc_granted_res nlmsvc_proc_null
+
struct nlm_void { int dummy; };

#define PROC(name, xargt, xrest, argt, rest) \
@@ -533,10 +540,10 @@
PROC(unlock_msg, unlockargs, norep, args, void),
PROC(granted_msg, testargs, norep, args, void),
PROC(test_res, testres, norep, res, void),
- PROC(lock_res, res, norep, res, void),
- PROC(cancel_res, res, norep, res, void),
- PROC(unlock_res, res, norep, res, void),
- PROC(granted_res, res, norep, res, void),
+ PROC(lock_res, lockres, norep, res, void),
+ PROC(cancel_res, cancelres, norep, res, void),
+ PROC(unlock_res, unlockres, norep, res, void),
+ PROC(granted_res, grantedres, norep, res, void),
PROC(none, void, void, void, void),
PROC(none, void, void, void, void),
PROC(none, void, void, void, void),
Index: fs/lockd/svcsubs.c
===================================================================
RCS file: /cvs/linux/fs/lockd/svcsubs.c,v
retrieving revision 1.1.1.2
diff -u -r1.1.1.2 svcsubs.c
--- fs/lockd/svcsubs.c 1998/10/28 22:00:26 1.1.1.2
+++ fs/lockd/svcsubs.c 1998/11/20 15:05:27
@@ -52,6 +52,8 @@
struct nlm_file *file;
unsigned int hash;
u32 nfserr;
+ uid_t saved_cr_uid;
+ struct svc_cred *cred;

dprintk("lockd: nlm_file_lookup(%s/%u)\n",
kdevname(u32_to_kdev_t(fh->fh_dev)), fh->fh_ino);
@@ -80,11 +82,19 @@

/* Open the file. Note that this must not sleep for too long, else
* we would lock up lockd:-) So no NFS re-exports, folks.
+ *
+ * We have to make sure we have the right credential to open
+ * the file.
*/
+ cred = &rqstp->rq_cred;
+ saved_cr_uid = cred->cr_uid;
+ cred->cr_uid = 0;
if ((nfserr = nlmsvc_ops->fopen(rqstp, fh, &file->f_file)) != 0) {
dprintk("lockd: open failed (nfserr %ld)\n", ntohl(nfserr));
+ cred->cr_uid = saved_cr_uid;
goto out_free;
}
+ cred->cr_uid = saved_cr_uid;

file->f_next = nlm_files[hash];
nlm_files[hash] = file;
Index: fs/nfs/file.c
===================================================================
RCS file: /cvs/linux/fs/nfs/file.c,v
retrieving revision 1.1.1.5
diff -u -r1.1.1.5 file.c
--- fs/nfs/file.c 1998/11/16 13:22:28 1.1.1.5
+++ fs/nfs/file.c 1998/11/20 15:05:27
@@ -244,7 +244,7 @@

/* If unlocking a file region, flush dirty pages (unless we've
* been killed by a signal, that is). */
- if (cmd == F_SETLK && fl->fl_type == F_UNLCK
+ if ((cmd == F_SETLK || cmd == F_SETLKW) && fl->fl_type == F_UNLCK
&& !signal_pending(current)) {
status = nfs_wb_area(inode, /* current->pid ?*/
fl->fl_start, fl->fl_end == NLM_OFFSET_MAX? 0 :
Index: fs/nfsd/auth.c
===================================================================
RCS file: /cvs/linux/fs/nfsd/auth.c,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 auth.c
--- fs/nfsd/auth.c 1998/11/04 20:00:07 1.1.1.3
+++ fs/nfsd/auth.c 1998/11/20 15:05:27
@@ -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: fs/nfsd/export.c
===================================================================
RCS file: /cvs/linux/fs/nfsd/export.c,v
retrieving revision 1.1.1.4
diff -u -r1.1.1.4 export.c
--- fs/nfsd/export.c 1998/11/01 20:40:12 1.1.1.4
+++ fs/nfsd/export.c 1998/11/20 15:05:27
@@ -232,7 +232,10 @@
err = -EINVAL;
if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) ||
!exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
+ {
+ printk("Failed at line %d\n", __LINE__);
goto out;
+ }

dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n",
nxp->ex_client, nxp->ex_path,
@@ -242,13 +245,17 @@

/* Try to lock the export table for update */
if ((err = exp_writelock()) < 0)
+ {
+ printk("Failed at exp_writelock()\n");
goto out;
-
+}
/* Look up client info */
err = -EINVAL;
if (!(clp = exp_getclientbyname(nxp->ex_client)))
+{
+ printk("Failed at exp_getclientbyname()\n");
goto out_unlock;
-
+}
/*
* If there's already an export for this file, assume this
* is just a flag update.
@@ -265,15 +272,17 @@
err = -EINVAL;
dentry = lookup_dentry(nxp->ex_path, NULL, 0);
if (IS_ERR(dentry))
+ {
+ printk("Failed: IS_ERR(dentry)\n");
goto out_unlock;
-
+}
err = -ENOENT;
inode = dentry->d_inode;
if (!inode)
goto finish;
err = -EINVAL;
if (inode->i_dev != dev || inode->i_ino != nxp->ex_ino) {
- printk(KERN_DEBUG "exp_export: i_dev = %x, dev = %x\n",
+ printk("exp_export: i_dev = %x, dev = %x\n",
inode->i_dev, dev);
/* I'm just being paranoid... */
goto finish;
@@ -288,13 +297,13 @@

err = -EINVAL;
if ((parent = exp_child(clp, dev, dentry)) != NULL) {
- dprintk("exp_export: export not valid (Rule 3).\n");
+ printk("exp_export: export not valid (Rule 3).\n");
goto finish;
}
/* Is this is a sub-export, must be a proper subset of FS */
if ((parent = exp_parent(clp, dev, dentry)) != NULL) {
if (dev == parent->ex_dev) {
- dprintk("exp_export: sub-export not valid (Rule 2).\n");
+ printk("exp_export: sub-export not valid (Rule 2).\n");
goto finish;
}
}
@@ -613,6 +622,112 @@
return clp;
}
return NULL;
+}
+
+struct flags {
+ int flag;
+ char *name[2];
+} expflags[] = {
+ { NFSEXP_READONLY, {"ro", "rw"}},
+ { NFSEXP_INSECURE_PORT, {"insecure", ""}},
+ { NFSEXP_ROOTSQUASH, {"root_squash", "no_root_squash"}},
+ { NFSEXP_ALLSQUASH, {"all_squash", ""}},
+ { NFSEXP_ASYNC, {"async", ""}},
+ { NFSEXP_GATHERED_WRITES, {"wdelay", ""}},
+ { NFSEXP_UIDMAP, {"uidmap", ""}},
+ { NFSEXP_KERBEROS, { "kerberos", ""}},
+ { NFSEXP_SUNSECURE, { "sunsecure", ""}},
+ { NFSEXP_CROSSMNT, {"crossmnt", ""}},
+ { 0, {"", ""}}
+};
+
+static int
+exp_flags(char *buffer, int flag)
+{
+ int len = 0, first = 0;
+ struct flags *flg = expflags;
+
+ for (;flg->flag;flg++) {
+ int state = (flg->flag & flag)?0:1;
+ if (!flg->flag)
+ break;
+ if (*flg->name[state]) {
+ len += sprintf(buffer + len, "%s%s",
+ first++?",":"", flg->name[state]);
+ }
+ }
+ return len;
+}
+
+int
+exp_procfs_exports(char *buffer, char **start, off_t offset,
+ int length, int *eof, void *data)
+{
+ struct svc_clnthash **hp, **head, *tmp;
+ struct svc_client *clp;
+ svc_export *exp;
+ off_t pos = 0;
+ off_t begin = 0;
+ int len = 0;
+ int i,j;
+
+ len += sprintf(buffer, "# Version 1.0\n");
+ len += sprintf(buffer+len, "# Path Client(Flags) # IPs\n");
+
+ for (clp = clients; clp; clp = clp->cl_next) {
+ for (i = 0; i < NFSCLNT_EXPMAX; i++) {
+ exp = clp->cl_export[i];
+ while (exp) {
+ int first = 0;
+ len += sprintf(buffer+len, "%s\t", exp->ex_path);
+ len += sprintf(buffer+len, "%s", clp->cl_ident);
+ len += sprintf(buffer+len, "(");
+
+ len += exp_flags(buffer+len, exp->ex_flags);
+ len += sprintf(buffer+len, ") # ");
+ for (j = 0; j < clp->cl_naddr; j++) {
+ struct in_addr addr = clp->cl_addr[j];
+
+ head = &clnt_hash[CLIENT_HASH(addr.s_addr)];
+ for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) {
+ if (tmp->h_addr.s_addr == addr.s_addr) {
+ if (first++) len += sprintf(buffer+len, "%s", " ");
+ if (tmp->h_client != clp)
+ len += sprintf(buffer+len, "(");
+ len += sprintf(buffer+len, "%d.%d.%d.%d",
+ htonl(addr.s_addr) >> 24 & 0xff,
+ htonl(addr.s_addr) >> 16 & 0xff,
+ htonl(addr.s_addr) >> 8 & 0xff,
+ htonl(addr.s_addr) >> 0 & 0xff);
+ if (tmp->h_client != clp)
+ len += sprintf(buffer+len, ")");
+ break;
+ }
+ }
+ }
+ exp = exp->ex_next;
+
+ buffer[len++]='\n';
+
+ pos=begin+len;
+ if(pos<offset) {
+ len=0;
+ begin=pos;
+ }
+ if (pos > offset + length)
+ goto done;
+ }
+ }
+ }
+
+ *eof = 1;
+
+done:
+ *start = buffer + (offset - begin);
+ len -= (offset - begin);
+ if ( len > length )
+ len = length;
+ return len;
}

/*
Index: fs/nfsd/nfsctl.c
===================================================================
RCS file: /cvs/linux/fs/nfsd/nfsctl.c,v
retrieving revision 1.1.1.2
diff -u -r1.1.1.2 nfsctl.c
--- fs/nfsd/nfsctl.c 1998/10/29 00:05:39 1.1.1.2
+++ fs/nfsd/nfsctl.c 1998/11/20 15:05:27
@@ -21,6 +21,7 @@
#include <linux/version.h>
#include <linux/unistd.h>
#include <linux/malloc.h>
+#include <linux/proc_fs.h>

#include <linux/nfs.h>
#include <linux/sunrpc/svc.h>
@@ -53,6 +54,24 @@

static int initialized = 0;

+#ifdef CONFIG_PROC_FS
+
+int exp_procfs_exports(char *buffer, char **start, off_t offset,
+ int length, int *eof, void *data);
+
+void proc_export_init()
+{
+ struct proc_dir_entry *nfs_export_ent = NULL;
+
+ if (!(nfs_export_ent = create_proc_entry("fs/nfs", S_IFDIR, 0)))
+ return;
+ if (!(nfs_export_ent = create_proc_entry("fs/nfs/exports", 0, 0)))
+ return;
+ nfs_export_ent->read_proc = exp_procfs_exports;
+}
+
+#endif
+
/*
* Initialize nfsd
*/
@@ -68,6 +87,9 @@
nfsd_lockd_init(); /* lockd->nfsd callbacks */
nfsd_racache_init(); /* Readahead param cache */
nfsd_fh_init(); /* FH table */
+#ifdef CONFIG_PROC_FS
+ proc_export_init();
+#endif
initialized = 1;
}

@@ -290,6 +312,8 @@
nfsd_cache_shutdown();
nfsd_fh_free();
#ifdef CONFIG_PROC_FS
+ remove_proc_entry("fs/nfs/exports", NULL);
+ remove_proc_entry("fs/nfs", NULL);
nfsd_stat_shutdown();
#endif
nfsd_lockd_shutdown();
Index: fs/nfsd/nfsfh.c
===================================================================
RCS file: /cvs/linux/fs/nfsd/nfsfh.c,v
retrieving revision 1.1.1.7
diff -u -r1.1.1.7 nfsfh.c
--- fs/nfsd/nfsfh.c 1998/11/01 20:40:12 1.1.1.7
+++ fs/nfsd/nfsfh.c 1998/11/20 15:05:27
@@ -1093,32 +1093,33 @@
/*
* 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;
@@ -1126,14 +1127,14 @@
}

/* 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: fs/nfsd/nfssvc.c
===================================================================
RCS file: /cvs/linux/fs/nfsd/nfssvc.c,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 nfssvc.c
--- fs/nfsd/nfssvc.c 1998/11/04 20:00:07 1.1.1.3
+++ fs/nfsd/nfssvc.c 1998/11/20 15:05:27
@@ -93,6 +93,8 @@
exit_mm(current);
current->session = 1;
current->pgrp = 1;
+ /* Let svc_process check client's authentication. */
+ rqstp->rq_auth = 1;
sprintf(current->comm, "nfsd");

oldumask = current->fs->umask; /* Set umask to 0. */
@@ -127,22 +129,13 @@
* port probes on port 2049 by unauthorized clients.
*/
rqstp->rq_client = exp_getclient(&rqstp->rq_addr);
- if (!rqstp->rq_client) {
- printk(KERN_WARNING "nfsd: unauthenticated request "
- "from (%08lx:%d)\n",
- ntohl(rqstp->rq_addr.sin_addr.s_addr),
- ntohs(rqstp->rq_addr.sin_port));
- svc_drop(rqstp);
- serv->sv_stats->rpcbadclnt++;
- } else {
- /* Process request with signals blocked. */
- spin_lock_irq(&current->sigmask_lock);
- siginitsetinv(&current->blocked, ALLOWED_SIGS);
- recalc_sigpending(current);
- spin_unlock_irq(&current->sigmask_lock);
-
- svc_process(serv, rqstp);
- }
+ /* Process request with signals blocked. */
+ spin_lock_irq(&current->sigmask_lock);
+ siginitsetinv(&current->blocked, ALLOWED_SIGS);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ svc_process(serv, rqstp);

/* Unlock export hash tables */
exp_unlock();
Index: fs/nfsd/vfs.c
===================================================================
RCS file: /cvs/linux/fs/nfsd/vfs.c,v
retrieving revision 1.1.1.9
diff -u -r1.1.1.9 vfs.c
--- fs/nfsd/vfs.c 1998/11/07 20:25:58 1.1.1.9
+++ fs/nfsd/vfs.c 1998/11/20 15:05:27
@@ -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);
@@ -275,9 +281,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))
@@ -493,6 +507,9 @@
struct inode *inode;
mm_segment_t oldfs;
int err = 0;
+#ifdef CONFIG_QUOTA
+ uid_t saved_euid;
+#endif

if (!cnt)
goto out;
@@ -522,16 +539,31 @@

/* Write the data. */
oldfs = get_fs(); set_fs(KERNEL_DS);
+#ifdef CONFIG_QUOTA
+ /* This is for disk quota. */
+ saved_euid = current->euid;
+ current->euid = current->fsuid;
err = file.f_op->write(&file, buf, cnt, &file.f_pos);
+ current->euid = saved_euid;
+#else
+ err = file.f_op->write(&file, buf, cnt, &file.f_pos);
+#endif
set_fs(oldfs);

/* 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 */
@@ -662,6 +694,7 @@
case S_IFCHR:
case S_IFBLK:
case S_IFIFO:
+ case S_IFSOCK:
opfunc = dirp->i_op->mknod;
break;
}
@@ -719,6 +752,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)
@@ -736,7 +770,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)
@@ -1225,11 +1265,11 @@
{
struct inode *inode = dentry->d_inode;
int err;
+ kernel_cap_t saved_cap;

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 +1283,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;
@@ -1274,11 +1313,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)
+ if (err == -EACCES && 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;
}
Index: include/linux/sunrpc/sched.h
===================================================================
RCS file: /cvs/linux/include/linux/sunrpc/sched.h,v
retrieving revision 1.1.1.2
diff -u -r1.1.1.2 sched.h
--- include/linux/sunrpc/sched.h 1998/10/28 22:27:32 1.1.1.2
+++ include/linux/sunrpc/sched.h 1998/11/20 15:05:28
@@ -128,7 +128,7 @@
void rpc_execute(struct rpc_task *);
void rpc_run_child(struct rpc_task *parent, struct rpc_task *child,
rpc_action action);
-void rpc_add_wait_queue(struct rpc_wait_queue *, struct rpc_task *);
+int rpc_add_wait_queue(struct rpc_wait_queue *, struct rpc_task *);
void rpc_remove_wait_queue(struct rpc_task *);
void rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *,
rpc_action action, rpc_action timer);
Index: include/linux/sunrpc/svc.h
===================================================================
RCS file: /cvs/linux/include/linux/sunrpc/svc.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 svc.h
--- include/linux/sunrpc/svc.h 1998/10/28 21:23:47 1.1.1.1
+++ include/linux/sunrpc/svc.h 1998/11/20 15:05:28
@@ -106,7 +106,8 @@
u32 rq_prot; /* IP protocol */
unsigned short rq_verfed : 1, /* reply has verifier */
rq_userset : 1, /* auth->setuser OK */
- rq_secure : 1; /* secure port */
+ rq_secure : 1, /* secure port */
+ rq_auth : 1; /* check client */

void * rq_argp; /* decoded arguments */
void * rq_resp; /* xdr'd results */
Index: net/sunrpc/sched.c
===================================================================
RCS file: /cvs/linux/net/sunrpc/sched.c,v
retrieving revision 1.1.1.8
diff -u -r1.1.1.8 sched.c
--- net/sunrpc/sched.c 1998/11/04 20:01:16 1.1.1.8
+++ net/sunrpc/sched.c 1998/11/20 15:05:28
@@ -79,13 +79,16 @@
* improve overall performance.
* Everyone else gets appended to the queue to ensure proper FIFO behavior.
*/
-void
+int
rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task)
{
if (task->tk_rpcwait) {
if (task->tk_rpcwait != queue)
+ {
printk(KERN_WARNING "RPC: doubly enqueued task!\n");
- return;
+ return -EWOULDBLOCK;
+ }
+ return 0;
}
if (RPC_IS_SWAPPER(task))
rpc_insert_list(&queue->task, task);
@@ -95,6 +98,8 @@

dprintk("RPC: %4d added to queue %p \"%s\"\n",
task->tk_pid, queue, rpc_qname(queue));
+
+ return 0;
}

/*
@@ -168,7 +173,13 @@
return;
}
if (RPC_IS_ASYNC(task)) {
- rpc_add_wait_queue(&schedq, task);
+ int status;
+ status = rpc_add_wait_queue(&schedq, task);
+ if (status)
+ {
+ printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
+ task->tk_status = status;
+ }
wake_up(&rpciod_idle);
} else {
wake_up(&task->tk_wait);
@@ -202,6 +213,7 @@
rpc_action action, rpc_action timer)
{
unsigned long oldflags;
+ int status;

dprintk("RPC: %4d sleep_on(queue \"%s\" time %ld)\n", task->tk_pid,
rpc_qname(q), jiffies);
@@ -211,11 +223,20 @@
*/
save_flags(oldflags); cli();

- rpc_add_wait_queue(q, task);
- task->tk_callback = action;
- if (task->tk_timeout)
- rpc_add_timer(task, timer);
- task->tk_flags &= ~RPC_TASK_RUNNING;
+ status = rpc_add_wait_queue(q, task);
+ if (status)
+ {
+ printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
+ task->tk_status = status;
+ task->tk_flags |= RPC_TASK_RUNNING;
+ }
+ else
+ {
+ task->tk_callback = action;
+ if (task->tk_timeout)
+ rpc_add_timer(task, timer);
+ task->tk_flags &= ~RPC_TASK_RUNNING;
+ }

restore_flags(oldflags);
return;
Index: net/sunrpc/svc.c
===================================================================
RCS file: /cvs/linux/net/sunrpc/svc.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 svc.c
--- net/sunrpc/svc.c 1998/10/28 21:23:57 1.1.1.1
+++ net/sunrpc/svc.c 1998/11/20 15:05:28
@@ -244,6 +244,12 @@
argp->buf += 5;
argp->len -= 5;

+ /* Used by nfsd to only allow the NULL procedure for amd. */
+ if (rqstp->rq_auth && !rqstp->rq_client && proc) {
+ auth_stat = rpc_autherr_badcred;
+ goto err_bad_auth;
+ }
+
/*
* Decode auth data, and add verifier to reply buffer.
* We do this before anything else in order to get a decent
Index: net/sunrpc/xprt.c
===================================================================
RCS file: /cvs/linux/net/sunrpc/xprt.c,v
retrieving revision 1.1.1.7
diff -u -r1.1.1.7 xprt.c
--- net/sunrpc/xprt.c 1998/10/28 23:51:58 1.1.1.7
+++ net/sunrpc/xprt.c 1998/11/20 15:05:28
@@ -936,6 +936,7 @@
struct rpc_timeout *timeo;
struct rpc_rqst *req = task->tk_rqstp;
struct rpc_xprt *xprt = req->rq_xprt;
+ int status;

/*DEBUG*/int ac_debug=xprt->snd_sent;

@@ -993,9 +994,17 @@
* the pending list now:
*/
start_bh_atomic();
- rpc_add_wait_queue(&xprt->pending, task);
- task->tk_callback = NULL;
+ status = rpc_add_wait_queue(&xprt->pending, task);
+ if (!status)
+ task->tk_callback = NULL;
end_bh_atomic();
+
+ if (status)
+ {
+ printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
+ task->tk_status = status;
+ return;
+ }

/* Continue transmitting the packet/record. We must be careful
* to cope with writespace callbacks arriving _after_ we have

--==_Exmh_-5042329040
Content-Type: text/plain; charset=us-ascii

---- ---- ----
David Woodhouse David.Woodhouse@mvhi.com Office: (+44) 1223 810302
Project Leader, Process Information Systems Mobile: (+44) 976 658355
Axiom (Cambridge) Ltd., Swaffham Bulbeck, Cambridge, CB5 0NA, UK.
finger dwmw2@ferret.lmh.ox.ac.uk for PGP key.

--==_Exmh_-5042329040--

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