Check more carefully for failing requests. This improves the error message when trying to mount a non-exported nfs directory from: nfs_mount_req: file handle too big: 44831 to nfs_mount_req: Mounting failed: NFS3ERR_ACCES(0xd) . This also fixes an out-of-bounds access as the filehandle size (44831 above) is read from just after the network packet in the error case. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@xxxxxxxxxxxxxx> --- Hello, while working on this patch I decided to keep the error name constants and so deviate from what I promised in reply to Sascha's feedback for v1. The reason is that not all NFS error constants have a corresponding POSIX error code and so pretty printing the error might be helpful. Best regards Uwe fs/nfs.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 102 insertions(+), 10 deletions(-) diff --git a/fs/nfs.c b/fs/nfs.c index 15ddab7915df..1f60cbad4045 100644 --- a/fs/nfs.c +++ b/fs/nfs.c @@ -636,13 +636,82 @@ static uint32_t *nfs_read_post_op_attr(uint32_t *p, struct inode *inode) return p; } +static int nfserror_to_err(u32 nfserror, const char **errorname) +{ + /* + * Most NFS errors have a corresponding POSIX error code. But not all of + * them have one, so some must be mapped to a different code here. + * To get helpful error messages also keep string constants for the + * actual errors. They are stored without the common NFS3ERR_ prefix to + * save some memory. + */ +#define E(NFSERR, ERR) \ + case NFS3ERR_ ## NFSERR: \ + *errorname = #NFSERR; \ + return -ERR + + switch (nfserror) { + E(PERM, EPERM); + E(NOENT, ENOENT); + E(IO, EIO); + E(NXIO, ENXIO); + E(ACCES, EACCES); + E(EXIST, EEXIST); + E(XDEV, EXDEV); + E(NODEV, ENODEV); + E(NOTDIR, ENOTDIR); + E(ISDIR, EISDIR); + E(INVAL, EINVAL); + E(FBIG, EFBIG); + E(NOSPC, ENOSPC); + E(ROFS, EROFS); + E(MLINK, EMLINK); + E(NAMETOOLONG, ENAMETOOLONG); + E(NOTEMPTY, ENOTEMPTY); + E(DQUOT, EDQUOT); + E(STALE, ESTALE); + E(REMOTE, EREMOTE); + E(BADHANDLE, EINVAL); + E(NOT_SYNC, EINVAL); + E(BAD_COOKIE, EINVAL); + E(NOTSUPP, ENOTSUPP); + E(TOOSMALL, EINVAL); + E(SERVERFAULT, EINVAL); + E(BADTYPE, EINVAL); + E(JUKEBOX, EINVAL); + + default: + *errorname = "???"; + return -EINVAL; + } +} + +static int nfs_printerr(u32 nfserror, const char *fmt, ...) +{ + va_list args; + const char *errorname; + int ret; + + va_start(args, fmt); + + vprintf(fmt, args); + + va_end(args); + + ret = nfserror_to_err(nfserror, &errorname); + + printf(": NFS3ERR_%s(0x%x)\n", errorname, (unsigned)nfserror); + + return ret; +} + /* * nfs_mount_req - Mount an NFS Filesystem */ static int nfs_mount_req(struct nfs_priv *npriv) { uint32_t data[1024]; - uint32_t *p; + uint32_t *p, status; int len; int pathlen; struct packet *nfs_packet; @@ -667,7 +736,15 @@ static int nfs_mount_req(struct nfs_priv *npriv) if (IS_ERR(nfs_packet)) return PTR_ERR(nfs_packet); - p = (void *)nfs_packet->data + sizeof(struct rpc_reply) + 4; + p = (void *)nfs_packet->data + sizeof(struct rpc_reply); + + /* + * Theoretically the error status is one of MNT3ERR_..., but the NFS + * constants are identical. + */ + status = ntoh32(net_read_uint32(p++)); + if (status != NFS3_OK) + return nfs_printerr(status, "%s: Mounting failed", __func__); npriv->rootfh.size = ntoh32(net_read_uint32(p++)); if (npriv->rootfh.size > NFS3_FHSIZE) { @@ -719,7 +796,7 @@ static int nfs_lookup_req(struct nfs_priv *npriv, struct nfs_fh *fh, { struct nfs_inode *ninode = nfsi(inode); uint32_t data[1024]; - uint32_t *p; + uint32_t *p, status; int len; struct packet *nfs_packet; @@ -761,7 +838,10 @@ static int nfs_lookup_req(struct nfs_priv *npriv, struct nfs_fh *fh, if (IS_ERR(nfs_packet)) return PTR_ERR(nfs_packet); - p = (void *)nfs_packet->data + sizeof(struct rpc_reply) + 4; + p = (void *)nfs_packet->data + sizeof(struct rpc_reply); + status = ntoh32(net_read_uint32(p++)); + if (status != NFS3_OK) + return nfs_printerr(status, "%s: LOOKUP failed", __func__); ninode->fh.size = ntoh32(net_read_uint32(p++)); if (ninode->fh.size > NFS3_FHSIZE) { @@ -787,7 +867,7 @@ static int nfs_lookup_req(struct nfs_priv *npriv, struct nfs_fh *fh, static void *nfs_readdirattr_req(struct nfs_priv *npriv, struct nfs_dir *dir) { uint32_t data[1024]; - uint32_t *p; + uint32_t *p, status; int len; struct packet *nfs_packet; void *buf; @@ -845,7 +925,13 @@ static void *nfs_readdirattr_req(struct nfs_priv *npriv, struct nfs_dir *dir) if (IS_ERR(nfs_packet)) return NULL; - p = (void *)nfs_packet->data + sizeof(struct rpc_reply) + 4; + p = (void *)nfs_packet->data + sizeof(struct rpc_reply); + status = ntoh32(net_read_uint32(p++)); + if (status != NFS3_OK) { + nfs_printerr(status, "%s: READDIR failed", __func__); + return NULL; + } + p = nfs_read_post_op_attr(p, NULL); /* update cookieverf */ @@ -879,7 +965,7 @@ static int nfs_read_req(struct file_priv *priv, uint64_t offset, uint32_t readlen) { uint32_t data[1024]; - uint32_t *p; + uint32_t *p, status; int len; struct packet *nfs_packet; uint32_t rlen, eof; @@ -922,7 +1008,10 @@ static int nfs_read_req(struct file_priv *priv, uint64_t offset, if (IS_ERR(nfs_packet)) return PTR_ERR(nfs_packet); - p = (void *)nfs_packet->data + sizeof(struct rpc_reply) + 4; + p = (void *)nfs_packet->data + sizeof(struct rpc_reply); + status = ntoh32(net_read_uint32(p++)); + if (status != NFS3_OK) + return nfs_printerr(status, "%s: READ failed", __func__); p = nfs_read_post_op_attr(p, NULL); @@ -981,7 +1070,7 @@ static int nfs_readlink_req(struct nfs_priv *npriv, struct nfs_fh *fh, char **target) { uint32_t data[1024]; - uint32_t *p; + uint32_t *p, status; uint32_t len; struct packet *nfs_packet; @@ -1017,7 +1106,10 @@ static int nfs_readlink_req(struct nfs_priv *npriv, struct nfs_fh *fh, if (IS_ERR(nfs_packet)) return PTR_ERR(nfs_packet); - p = (void *)nfs_packet->data + sizeof(struct rpc_reply) + 4; + p = (void *)nfs_packet->data + sizeof(struct rpc_reply); + status = ntoh32(net_read_uint32(p++)); + if (status != NFS3_OK) + return nfs_printerr(status, "%s: READLINK failed", __func__); p = nfs_read_post_op_attr(p, NULL); -- 2.28.0 _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox