lkml.org 
[lkml]   [1998]   [Sep]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[PATCH] for knfsd (Please test!!!)
    Date
    From
    Attached is a patch for fs/nfsd.  It attempts to fix 4 problems:

    1) knfsd will allow multiple exports of a single partition. The mounts
    must be proper subsets of the partition.

    NOTE: It may be possible to access any file on a partition using
    the least restrictive export permissions.

    2) knfsd will allow mounts above the export point. That is if you
    export / and /usr is in the same partition you can mount /usr.

    3) You can now export and mount regular files. (It is not clear if
    they can be used for swap.)

    4) knfsd does not return EACCESS when you try to access a `covered'
    directory. Instead knfsd allows nfs to access these directories.
    (I believe that this is what SunOS 4 does.)

    In order for #2 above to work you must get a patched copy of
    mountd that used the net getfd system call.

    --
    Allen Morris <gam3@acm.org>

    --- linux/fs/nfsd/export.c 1998/09/04 01:44:30 1.1
    +++ linux/fs/nfsd/export.c 1998/09/10 06:43:24
    @@ -33,7 +33,7 @@
    typedef struct svc_export svc_export;

    static svc_export * exp_find(svc_client *clp, kdev_t dev);
    -static svc_export * exp_parent(svc_client *clp, kdev_t dev);
    +static svc_export * exp_parent(svc_client *clp, kdev_t dev, struct dentry *dentry);
    static void exp_unexport_all(svc_client *clp);
    static void exp_do_unexport(svc_export *unexp);
    static svc_client * exp_getclientbyname(char *name);
    @@ -90,8 +90,16 @@

    if (!clp)
    return NULL;
    - exp = exp_find(clp, dev);
    - return (exp && exp->ex_ino == ino)? exp : NULL;
    +
    + exp = clp->cl_export[EXPORT_HASH(dev)];
    + if (exp)
    + do {
    + if (exp->ex_ino == ino && exp->ex_dev == dev)
    + goto out;
    + } while (NULL != (exp = exp->ex_next));
    + exp = NULL;
    +out:
    + return exp;
    }

    /*
    @@ -129,19 +137,59 @@
    * Find the parent export entry for a given fs. This function is used
    * only by the export syscall to keep the export tree consistent.
    */
    +/*
    + * We can use this to find exports if we have it look at the first
    + * dentry. This makes it less efficient. <gam3@acm.org>
    + */
    static svc_export *
    -exp_parent(svc_client *clp, kdev_t dev)
    +exp_parent(svc_client *clp, kdev_t dev, struct dentry *dentry)
    {
    - svc_export *exp;
    + svc_export *exp;
    kdev_t xdev = dev;
    + struct dentry *xdentry = dentry;
    + struct dentry *ndentry = NULL;

    - do {
    - exp = exp_find(clp, xdev);
    - if (exp)
    - return exp;
    - } while (nfsd_parentdev(&xdev));
    + if (clp == NULL || dentry == NULL)
    + return NULL;

    - return NULL;
    + exp = clp->cl_export[EXPORT_HASH(dev)];
    + if (exp)
    + do {
    + ndentry = exp->ex_dentry;
    + if (ndentry)
    + while (ndentry = ndentry->d_parent) {
    + if (ndentry == xdentry) {
    +dprintk("nfsd: exp_parent mount under submount.\n");
    + goto out;
    + }
    + if (ndentry == ndentry->d_parent)
    + break;
    + }
    + } while (NULL != (exp = exp->ex_next));
    + do {
    + xdev = dev;
    + do {
    + exp = clp->cl_export[EXPORT_HASH(xdev)];
    + if (exp)
    + do {
    + ndentry = exp->ex_dentry;
    + if (ndentry == xdentry) {
    +if (dev == xdev)
    + dprintk("nfsd: exp_parent submount over mount.\n");
    +else
    + dprintk("nfsd: exp_parent found.\n");
    + goto out;
    + }
    + } while (NULL != (exp = exp->ex_next));
    + } while (nfsd_parentdev(&xdev));
    +/* It should be possible to move this to the top of this loop */
    + if (xdentry == xdentry->d_parent) {
    + break;
    + }
    + } while (xdentry = xdentry->d_parent);
    + exp = NULL;
    +out:
    + return exp;
    }

    /*
    @@ -160,9 +208,10 @@
    ino_t ino;

    /* Consistency check */
    + err = -EINVAL;
    if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) ||
    !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
    - return -EINVAL;
    + goto out;

    dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n",
    nxp->ex_client, nxp->ex_path,
    @@ -183,15 +232,11 @@
    * If there's already an export for this file, assume this
    * is just a flag update.
    */
    - if ((exp = exp_find(clp, dev)) != NULL) {
    - /* Ensure there's only one export per FS. */
    - err = -EPERM;
    - if (exp->ex_ino == ino) {
    - exp->ex_flags = nxp->ex_flags;
    - exp->ex_anon_uid = nxp->ex_anon_uid;
    - exp->ex_anon_gid = nxp->ex_anon_gid;
    - err = 0;
    - }
    + if ((exp = exp_get(clp, dev, ino)) != NULL) {
    + exp->ex_flags = nxp->ex_flags;
    + exp->ex_anon_uid = nxp->ex_anon_uid;
    + exp->ex_anon_gid = nxp->ex_anon_gid;
    + err = 0;
    goto out_unlock;
    }

    @@ -203,32 +248,29 @@

    err = -ENOENT;
    inode = dentry->d_inode;
    - if(!inode)
    + if (!inode)
    goto finish;
    err = -EINVAL;
    - if(inode->i_dev != dev || inode->i_ino != nxp->ex_ino) {
    -
    + if (inode->i_dev != dev || inode->i_ino != nxp->ex_ino) {
    printk(KERN_DEBUG "exp_export: i_dev = %x, dev = %x\n",
    inode->i_dev, dev);
    /* I'm just being paranoid... */
    goto finish;
    }

    - /* We currently export only dirs. */
    + /* We currently export only dirs and regular files.
    + * This is what umountd does.
    + */
    err = -ENOTDIR;
    - if (!S_ISDIR(inode->i_mode))
    + if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode))
    goto finish;

    /* If this is a sub-export, must be root of FS */
    err = -EINVAL;
    - if ((parent = exp_parent(clp, dev)) != NULL) {
    + if ((parent = exp_parent(clp, dev, dentry)) != NULL) {
    struct super_block *sb = inode->i_sb;
    -
    - if (inode != sb->s_root->d_inode) {
    -#ifdef NFSD_PARANOIA
    -printk("exp_export: sub-export %s not root of device %s\n",
    -nxp->ex_path, kdevname(sb->s_dev));
    -#endif
    + if (dev = parent->ex_dev) {
    +dprintk("exp_export: sub-export not valid.\n");
    goto finish;
    }
    }
    @@ -368,7 +410,6 @@
    if (exp->ex_dev == nxp->ex_dev) {
    if (exp->ex_ino != nxp->ex_ino) {
    printk("exp_unexport: ino mismatch, %ld not %ld\n", exp->ex_ino, nxp->ex_ino);
    - break;
    }
    *expp = exp->ex_next;
    exp_do_unexport(exp);
    @@ -390,23 +431,35 @@
    * since its harder to fool a kernel module than a user space program.
    */
    int
    -exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino, struct knfs_fh *f)
    +exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino, char *path, struct knfs_fh *f)
    {
    - struct svc_export *exp = NULL;
    - struct svc_fh fh;
    + struct svc_export *exp;
    struct dentry *dentry;
    struct inode *inode;
    + struct svc_fh fh;
    + int err;

    - dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n", clp->cl_ident, dev, ino);
    + if (path) {
    + dentry = lookup_dentry(path, NULL, 0);

    - if (!(exp = exp_get(clp, dev, ino)))
    - return -EPERM;
    + dprintk("nfsd: exp_rootfh(%s [%p] %s:%x/%ld)\n", path, dentry, clp->cl_ident, dev, ino);
    + dev = dentry->d_inode->i_dev;
    + ino = dentry->d_inode->i_ino;
    +
    + exp = exp_parent(clp, dev, dentry);
    + } else {
    + dprintk("nfsd: exp_rootfh(%s %s:%x/%ld)\n", path, clp->cl_ident, dev, ino);
    + exp = exp_get(clp, dev, ino);
    + dentry = dget(exp->ex_dentry);
    + }
    + err = -EPERM;
    + if (!exp)
    + goto out;

    - dentry = exp->ex_dentry;
    inode = dentry->d_inode;
    if(!inode) {
    printk("exp_rootfh: Aieee, NULL d_inode\n");
    - return -EPERM;
    + goto out;
    }
    if(inode->i_dev != dev || inode->i_ino != ino) {
    printk("exp_rootfh: Aieee, ino/dev mismatch\n");
    @@ -414,12 +467,17 @@
    dev, ino, inode->i_dev, inode->i_ino);
    }

    - dget(dentry);
    - fh_compose(&fh, exp, dentry);
    + /*
    + * fh must be initialized before calling fh_compose
    + */
    + fh_init(&fh);
    + fh_compose(&fh, exp, dget(dentry));
    memcpy(f, &fh.fh_handle, sizeof(struct knfs_fh));
    fh_put(&fh);
    -
    - return 0;
    + err = 0;
    +out:
    + dput(dentry);
    + return err;
    }

    /*
    --- linux/fs/nfsd/nfsctl.c 1998/09/04 01:44:30 1.1
    +++ linux/fs/nfsd/nfsctl.c 1998/09/09 22:22:47
    @@ -5,6 +5,7 @@
    *
    * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
    */
    +#define NFS_GETFH_NEW

    #include <linux/config.h>
    #include <linux/module.h>
    @@ -47,6 +48,7 @@
    static int nfsctl_export(struct nfsctl_export *data);
    static int nfsctl_unexport(struct nfsctl_export *data);
    static int nfsctl_getfh(struct nfsctl_fhparm *, struct knfs_fh *);
    +static int nfsctl_getfd(struct nfsctl_fdparm *, struct knfs_fh *);
    /* static int nfsctl_ugidupdate(struct nfsctl_ugidmap *data); */

    static int initialized = 0;
    @@ -108,6 +110,29 @@
    #endif

    static inline int
    +nfsctl_getfd(struct nfsctl_fdparm *data, struct knfs_fh *res)
    +{
    + struct sockaddr_in *sin;
    + struct svc_client *clp;
    + int err = 0;
    +
    + if (data->gd_addr.sa_family != AF_INET)
    + return -EPROTONOSUPPORT;
    + if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS)
    + return -EINVAL;
    + sin = (struct sockaddr_in *)&data->gd_addr;
    +
    + exp_readlock();
    + if (!(clp = exp_getclient(sin)))
    + err = -EPERM;
    + else
    + err = exp_rootfh(clp, 0, 0, data->gd_path, res);
    + exp_unlock();
    +
    + return err;
    +}
    +
    +static inline int
    nfsctl_getfh(struct nfsctl_fhparm *data, struct knfs_fh *res)
    {
    struct sockaddr_in *sin;
    @@ -124,7 +149,7 @@
    if (!(clp = exp_getclient(sin)))
    err = -EPERM;
    else
    - err = exp_rootfh(clp, to_kdev_t(data->gf_dev), data->gf_ino, res);
    + err = exp_rootfh(clp, to_kdev_t(data->gf_dev), data->gf_ino, NULL, res);
    exp_unlock();

    return err;
    @@ -193,6 +218,9 @@
    #endif
    case NFSCTL_GETFH:
    err = nfsctl_getfh(&arg->ca_getfh, &res->cr_getfh);
    + break;
    + case NFSCTL_GETFD:
    + err = nfsctl_getfd(&arg->ca_getfd, &res->cr_getfh);
    break;
    default:
    err = -EINVAL;
    --- linux/fs/nfsd/vfs.c 1998/09/04 01:44:30 1.1
    +++ linux/fs/nfsd/vfs.c 1998/09/10 05:16:01
    @@ -39,6 +39,7 @@
    #endif

    #define NFSDDBG_FACILITY NFSDDBG_FILEOP
    +#define NFSD_PARANOIA

    /* Open mode for nfsd_open */
    #define OPEN_READ 0
    @@ -171,10 +172,19 @@
    * Make sure we haven't crossed a mount point ...
    */
    if (dchild->d_sb != dparent->d_sb) {
    + struct dentry *tdentry;
    #ifdef NFSD_PARANOIA
    printk("nfsd_lookup: %s/%s crossed mount point!\n", dparent->d_name.name, name);
    #endif
    - goto out_dput;
    + tdentry = dchild->d_covers;
    + if (tdentry == dchild)
    + goto out_dput;
    + dput(dchild);
    + dchild = dget(tdentry);
    + if (dchild->d_sb != dparent->d_sb) {
    +printk("nfsd_lookup: %s/%s crossed mount point!\n", dparent->d_name.name, dchild->d_name.name);
    + goto out_dput;
    + }
    }

    /*
    --- linux/include/linux/nfsd/export.h 1998/09/04 01:44:49 1.1
    +++ linux/include/linux/nfsd/export.h 1998/09/09 02:23:07
    @@ -86,6 +86,7 @@
    void exp_putclient(struct svc_client *clp);
    struct svc_export * exp_get(struct svc_client *clp, kdev_t dev, ino_t ino);
    int exp_rootfh(struct svc_client *, kdev_t, ino_t,
    + char *path,
    struct knfs_fh *);
    int nfserrno(int errno);
    void exp_nlmdetach(void);
    --- linux/include/linux/nfsd/syscall.h 1998/09/04 01:44:49 1.1
    +++ linux/include/linux/nfsd/syscall.h 1998/09/09 22:25:23
    @@ -32,8 +32,8 @@
    #define NFSCTL_EXPORT 3 /* export a file system. */
    #define NFSCTL_UNEXPORT 4 /* unexport a file system. */
    #define NFSCTL_UGIDUPDATE 5 /* update a client's uid/gid map. */
    -#define NFSCTL_GETFH 6 /* get an fh (used by mountd) */
    -
    +#define NFSCTL_GETFH 6 /* get an fh by ino (used by mountd) */
    +#define NFSCTL_GETFD 7 /* get an fh by path (used by mountd) */

    /* SVC */
    struct nfsctl_svc {
    @@ -81,6 +81,13 @@
    int gf_version;
    };

    +/* GETFD */
    +struct nfsctl_fdparm {
    + struct sockaddr gd_addr;
    + char gd_path[NFS_MAXPATHLEN+1];
    + int gd_version;
    +};
    +
    /*
    * This is the argument union.
    */
    @@ -92,6 +99,7 @@
    struct nfsctl_export u_export;
    struct nfsctl_uidmap u_umap;
    struct nfsctl_fhparm u_getfh;
    + struct nfsctl_fdparm u_getfd;
    unsigned int u_debug;
    } u;
    #define ca_svc u.u_svc
    @@ -99,6 +107,7 @@
    #define ca_export u.u_export
    #define ca_umap u.u_umap
    #define ca_getfh u.u_getfh
    +#define ca_getfd u.u_getfd
    #define ca_authd u.u_authd
    #define ca_debug u.u_debug
    };
    \
     
     \ /
      Last update: 2005-03-22 13:44    [W:0.039 / U:30.456 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site