From: Sankar P Subject: novfs: security: Add buffer overflow, integer wraparound fixes Patch-mainline: no References: bnc#594362 Security fixes that help in addressing buffer overflows, limiting the amount of data that can be copied from user-space, etc. Signed-off-by: Sankar P Signed-off-by: Marcus Meissner Signed-off-by: Sebastian Krahmer --- fs/novfs/daemon.c | 36 +- fs/novfs/file.c | 4 fs/novfs/nwcapi.c | 787 +++++++++++++++++++++++++++--------------------------- fs/novfs/nwcapi.h | 12 4 files changed, 439 insertions(+), 400 deletions(-) --- a/fs/novfs/daemon.c +++ b/fs/novfs/daemon.c @@ -811,6 +811,9 @@ static int daemon_login(struct novfs_log struct ncl_string password; if (!copy_from_user(&lLogin, Login, sizeof(lLogin))) { + if (lLogin.Server.length > MAX_SERVER_NAME_LENGTH || lLogin.UserName.length > MAX_NAME_LEN || + lLogin.Password.length > MAX_PASSWORD_LENGTH) + return -EINVAL; server.buffer = kmalloc(lLogin.Server.length, GFP_KERNEL); if (server.buffer) { server.len = lLogin.Server.length; @@ -857,6 +860,8 @@ static int daemon_logout(struct novfs_lo if (copy_from_user(&lLogout, Logout, sizeof(lLogout))) return -EFAULT; + if (lLogout.Server.length > MAX_SERVER_NAME_LENGTH) + return -EINVAL; server.name = kmalloc(lLogout.Server.length, GFP_KERNEL); if (!server.name) return -ENOMEM; @@ -1102,6 +1107,8 @@ int novfs_daemon_ioctl(struct inode *ino char *buf; io.length = 0; cpylen = copy_from_user(&io, (char *)arg, sizeof(io)); + if (io.length <= 0 || io.length > 1024) + return -EINVAL; if (io.length) { buf = kmalloc(io.length + 1, GFP_KERNEL); if (buf) { @@ -1453,6 +1460,8 @@ int novfs_daemon_lib_ioctl(struct inode cpylen = copy_from_user(&io, (void *)arg, sizeof(io)); + if (io.length <= 0 || io.length > 1024) + return -EINVAL; if (io.length) { buf = kmalloc(io.length + 1, @@ -1478,9 +1487,7 @@ int novfs_daemon_lib_ioctl(struct inode cpylen = copy_from_user(&data, (void *)arg, sizeof(data)); - retCode = - ((data. - xfunction & 0x0000FFFF) | 0xCC000000); + retCode = ((data.xfunction & 0x0000FFFF) | 0xCC000000); switch (data.xfunction) { case NWC_OPEN_CONN_BY_NAME: @@ -1815,8 +1822,7 @@ static int NwdConvertLocalHandle(struct //sgled memcpy(lh.NwWareHandle, resource->handle, sizeof(resource->handle)); memcpy(lh.NetWareHandle, resource->handle, sizeof(resource->handle)); //sgled if (pdata->repLen >= sizeof(struct nwc_convert_local_handle)) { - cpylen = - copy_to_user(pdata->repData, &lh, + cpylen = copy_to_user(pdata->repData, &lh, sizeof(struct nwc_convert_local_handle)); retVal = 0; } else { @@ -1838,6 +1844,8 @@ static int NwdGetMountPath(struct novfs_ unsigned long cpylen; struct nwc_get_mount_path mp; + if (pdata->reqLen != sizeof(mp)) + return -EINVAL; cpylen = copy_from_user(&mp, pdata->reqData, pdata->reqLen); if (novfs_current_mnt) { @@ -1878,21 +1886,19 @@ static int set_map_drive(struct novfs_xp return retVal; if (copy_from_user(&symInfo, pdata->reqData, sizeof(symInfo))) return -EFAULT; - drivemap = - kmalloc(sizeof(struct drive_map) + symInfo.linkOffsetLength, + if (symInfo.linkOffsetLength > MAX_NAME_LEN) + return -EINVAL; + drivemap = kmalloc(sizeof(struct drive_map) + symInfo.linkOffsetLength, GFP_KERNEL); if (!drivemap) return -ENOMEM; path = (char *)pdata->reqData; path += symInfo.linkOffset; - cpylen = - copy_from_user(drivemap->name, path, - symInfo.linkOffsetLength); + cpylen = copy_from_user(drivemap->name, path, symInfo.linkOffsetLength); drivemap->session = Session; - drivemap->hash = - full_name_hash(drivemap->name, + drivemap->hash = full_name_hash(drivemap->name, symInfo.linkOffsetLength - 1); drivemap->namelen = symInfo.linkOffsetLength - 1; DbgPrint("hash=0x%lx path=%s", drivemap->hash, drivemap->name); @@ -1910,8 +1916,7 @@ static int set_map_drive(struct novfs_xp dm, dm->hash, dm->namelen, dm->name); if (drivemap->hash == dm->hash) { - if (0 == - strcmp(dm->name, drivemap->name)) { + if (0 == strcmp(dm->name, drivemap->name)) { dm = NULL; break; } @@ -1950,7 +1955,8 @@ static int unmap_drive(struct novfs_xpla return retVal; if (copy_from_user(&symInfo, pdata->reqData, sizeof(symInfo))) return -EFAULT; - + if (symInfo.linkLen > MAX_NAME_LEN || symInfo.linkLen == 0) + return -EINVAL; path = kmalloc(symInfo.linkLen, GFP_KERNEL); if (!path) return -ENOMEM; --- a/fs/novfs/file.c +++ b/fs/novfs/file.c @@ -1077,7 +1077,7 @@ int novfs_write_file(void *Handle, unsig DbgPrint("cmdlen=%ld len=%ld", cmdlen, len); - if ((cmdlen + len) > novfs_max_iosize) { + if (len > novfs_max_iosize - cmdlen) { len = novfs_max_iosize - cmdlen; len = (len / PAGE_SIZE) * PAGE_SIZE; } @@ -1449,6 +1449,8 @@ int novfs_write_stream(void *ConnHandle, size_t len; len = *Bytes; + if (len > novfs_max_iosize) + len = novfs_max_iosize; cmdlen = len + offsetof(struct novfs_write_stream_request, data); *Bytes = 0; --- a/fs/novfs/nwcapi.c +++ b/fs/novfs/nwcapi.c @@ -37,16 +37,20 @@ static void GetConnData(struct nwc_get_c /*++======================================================================*/ int novfs_open_conn_by_name(struct novfs_xplat *pdata, void ** Handle, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; - struct nwd_open_conn_by_name *openConn, *connReply; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; + struct nwd_open_conn_by_name *openConn = NULL, *connReply = NULL; struct nwc_open_conn_by_name ocbn; int retCode = 0; - unsigned long cmdlen, datalen, replylen, cpylen; - char *data; + unsigned long cmdlen, datalen, replylen, cpylen, pnamelen, stypelen; + char *data = NULL; cpylen = copy_from_user(&ocbn, pdata->reqData, sizeof(ocbn)); - datalen = sizeof(*openConn) + strlen_user(ocbn.pName->pString) + strlen_user(ocbn.pServiceType); + pnamelen = strlen_user(ocbn.pName->pString); + stypelen = strlen_user(ocbn.pServiceType); + if (pnamelen > MAX_NAME_LEN || stypelen > NW_MAX_SERVICE_TYPE_LEN) + return -EINVAL; + datalen = sizeof(*openConn) + pnamelen + stypelen; cmdlen = datalen + sizeof(*cmd); cmd = kmalloc(cmdlen, GFP_KERNEL); @@ -61,8 +65,8 @@ int novfs_open_conn_by_name(struct novfs cmd->dataLen = datalen; openConn = (struct nwd_open_conn_by_name *) cmd->data; - openConn->nameLen = strlen_user(ocbn.pName->pString); - openConn->serviceLen = strlen_user(ocbn.pServiceType); + openConn->nameLen = pnamelen; + openConn->serviceLen = stypelen; openConn->uConnFlags = ocbn.uConnFlags; openConn->ConnHandle = Uint32toHandle(ocbn.ConnHandle); data = (char *)openConn; @@ -70,13 +74,9 @@ int novfs_open_conn_by_name(struct novfs openConn->oName = sizeof(*openConn); openConn->oServiceType = openConn->oName + openConn->nameLen; - cpylen = - copy_from_user(data, ocbn.pName->pString, - openConn->nameLen); + cpylen = copy_from_user(data, ocbn.pName->pString, openConn->nameLen); data += openConn->nameLen; - cpylen = - copy_from_user(data, ocbn.pServiceType, - openConn->serviceLen); + cpylen = copy_from_user(data, ocbn.pServiceType, openConn->serviceLen); retCode = Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, @@ -109,9 +109,9 @@ int novfs_open_conn_by_name(struct novfs int novfs_open_conn_by_addr(struct novfs_xplat *pdata, void ** Handle, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; - struct nwd_open_conn_by_addr *openConn, *connReply; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; + struct nwd_open_conn_by_addr *openConn = NULL, *connReply = NULL; struct nwc_open_conn_by_addr ocba; struct nwc_tran_addr tranAddr; int retCode = 0; @@ -133,8 +133,11 @@ int novfs_open_conn_by_addr(struct novfs cmd->dataLen = datalen; openConn = (struct nwd_open_conn_by_addr *) cmd->data; - cpylen = - copy_from_user(&tranAddr, ocba.pTranAddr, sizeof(tranAddr)); + cpylen = copy_from_user(&tranAddr, ocba.pTranAddr, sizeof(tranAddr)); + if (tranAddr.uAddressLength > sizeof(addr)) { + retCode = -EINVAL; + goto out; + } DbgPrint("tranAddr"); novfs_dump(sizeof(tranAddr), &tranAddr); @@ -143,17 +146,14 @@ int novfs_open_conn_by_addr(struct novfs openConn->TranAddr.uAddressLength = tranAddr.uAddressLength; memset(addr, 0xcc, sizeof(addr) - 1); - cpylen = - copy_from_user(addr, tranAddr.puAddress, - tranAddr.uAddressLength); + cpylen = copy_from_user(addr, tranAddr.puAddress, tranAddr.uAddressLength); DbgPrint("addr"); novfs_dump(sizeof(addr), addr); openConn->TranAddr.oAddress = *(unsigned int *) (&addr[2]); - retCode = - Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + retCode = Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, (void **)&reply, &replylen, INTERRUPTIBLE); if (reply) { @@ -178,17 +178,17 @@ int novfs_open_conn_by_addr(struct novfs kfree(reply); } +out: kfree(cmd); - return (retCode); } int novfs_open_conn_by_ref(struct novfs_xplat *pdata, void ** Handle, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; - struct nwd_open_conn_by_ref *openConn; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; + struct nwd_open_conn_by_ref *openConn = NULL; struct nwc_open_conn_by_ref ocbr; int retCode = -ENOMEM; unsigned long cmdlen, datalen, replylen, cpylen; @@ -207,8 +207,7 @@ int novfs_open_conn_by_ref(struct novfs_ cmd->dataLen = datalen; openConn = (struct nwd_open_conn_by_ref *) cmd->data; - openConn->uConnReference = - (void *) (unsigned long) ocbr.uConnReference; + openConn->uConnReference = (void *) (unsigned long) ocbr.uConnReference; openConn->uConnFlags = ocbr.uConnFlags; retCode = @@ -225,13 +224,10 @@ int novfs_open_conn_by_ref(struct novfs_ /* * we got valid data. */ - ocbr.ConnHandle = - HandletoUint32(openConn->ConnHandle); + ocbr.ConnHandle = HandletoUint32(openConn->ConnHandle); *Handle = openConn->ConnHandle; - cpylen = - copy_to_user(pdata->reqData, &ocbr, - sizeof(ocbr)); + cpylen = copy_to_user(pdata->reqData, &ocbr, sizeof(ocbr)); DbgPrint("New Conn Handle = %X", openConn->ConnHandle); } kfree(reply); @@ -245,59 +241,63 @@ int novfs_open_conn_by_ref(struct novfs_ int novfs_raw_send(struct novfs_xplat *pdata, struct novfs_schandle Session) { struct nwc_request xRequest; - struct nwc_frag *frag, *cFrag, *reqFrag; - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; - int retCode = -ENOMEM; + struct nwc_frag *frag = NULL, *cFrag = NULL, *reqFrag = NULL; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; + int retCode = 0; unsigned long cmdlen, datalen, replylen, cpylen, totalLen; unsigned int x; - struct nwd_ncp_req *ncpData; - struct nwd_ncp_rep *ncpReply; - unsigned char *reqData; + struct nwd_ncp_req *ncpData = NULL; + struct nwd_ncp_rep *ncpReply = NULL; + unsigned char *reqData = NULL; unsigned long actualReplyLength = 0; DbgPrint("[XPLAT] Process Raw NCP Send"); cpylen = copy_from_user(&xRequest, pdata->reqData, sizeof(xRequest)); + if (xRequest.uNumReplyFrags > MAX_NUM_REPLIES || xRequest.uNumReplyFrags < MIN_NUM_REPLIES || + xRequest.uNumRequestFrags > MAX_NUM_REQUESTS || xRequest.uNumRequestFrags < MIN_NUM_REQUESTS) + return -EINVAL; + /* * Figure out the length of the request */ - frag = - kmalloc(xRequest.uNumReplyFrags * sizeof(struct nwc_frag), GFP_KERNEL); + frag = kmalloc(xRequest.uNumReplyFrags * sizeof(struct nwc_frag), GFP_KERNEL); - DbgPrint("[XPLAT RawNCP] - Reply Frag Count 0x%X", - xRequest.uNumReplyFrags); + DbgPrint("[XPLAT RawNCP] - Reply Frag Count 0x%X", xRequest.uNumReplyFrags); if (!frag) - return (retCode); + return -ENOMEM; - cpylen = - copy_from_user(frag, xRequest.pReplyFrags, - xRequest.uNumReplyFrags * sizeof(struct nwc_frag)); + cpylen = copy_from_user(frag, xRequest.pReplyFrags, xRequest.uNumReplyFrags * sizeof(struct nwc_frag)); totalLen = 0; cFrag = frag; for (x = 0; x < xRequest.uNumReplyFrags; x++) { DbgPrint("[XPLAT - RawNCP] - Frag Len = %d", cFrag->uLength); + if (cFrag->uLength > MAX_FRAG_SIZE || cFrag->uLength < MIN_FRAG_SIZE) { + retCode = -EINVAL; + goto out; + } totalLen += cFrag->uLength; cFrag++; } DbgPrint("[XPLAT - RawNCP] - totalLen = %d", totalLen); datalen = 0; - reqFrag = - kmalloc(xRequest.uNumRequestFrags * sizeof(struct nwc_frag), - GFP_KERNEL); + reqFrag = kmalloc(xRequest.uNumRequestFrags * sizeof(struct nwc_frag), GFP_KERNEL); if (!reqFrag) { - kfree(frag); - return (retCode); + retCode = -ENOMEM; + goto out; } - cpylen = - copy_from_user(reqFrag, xRequest.pRequestFrags, - xRequest.uNumRequestFrags * sizeof(struct nwc_frag)); + cpylen = copy_from_user(reqFrag, xRequest.pRequestFrags, xRequest.uNumRequestFrags * sizeof(struct nwc_frag)); cFrag = reqFrag; for (x = 0; x < xRequest.uNumRequestFrags; x++) { + if (cFrag->uLength > MAX_FRAG_SIZE || cFrag->uLength < MIN_FRAG_SIZE) { + retCode = -EINVAL; + goto out; + } datalen += cFrag->uLength; cFrag++; } @@ -311,8 +311,10 @@ int novfs_raw_send(struct novfs_xplat *p DbgPrint("[XPLAT RawNCP] - Total Command Data Len = %x", cmdlen); cmd = kmalloc(cmdlen, GFP_KERNEL); - if (!cmd) - return -ENOMEM; + if (!cmd) { + retCode = -ENOMEM; + goto out; + } cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; cmd->Command.SequenceNumber = 0; @@ -333,9 +335,7 @@ int novfs_raw_send(struct novfs_xplat *p cFrag = reqFrag; for (x = 0; x < xRequest.uNumRequestFrags; x++) { - cpylen = - copy_from_user(reqData, cFrag->pData, - cFrag->uLength); + cpylen = copy_from_user(reqData, cFrag->pData, cFrag->uLength); reqData += cFrag->uLength; cFrag++; } @@ -369,12 +369,9 @@ int novfs_raw_send(struct novfs_xplat *p DbgPrint("RawNCP - Copy Frag %d: 0x%X", x, cFrag->uLength); - datalen = - min((unsigned long) cFrag->uLength, totalLen); + datalen = min((unsigned long) cFrag->uLength, totalLen); - cpylen = - copy_to_user(cFrag->pData, reqData, - datalen); + cpylen = copy_to_user(cFrag->pData, reqData, datalen); totalLen -= datalen; reqData += datalen; actualReplyLength += datalen; @@ -387,10 +384,12 @@ int novfs_raw_send(struct novfs_xplat *p retCode = -EIO; } - kfree(cmd); + xRequest.uActualReplyLength = actualReplyLength; cpylen = copy_to_user(pdata->reqData, &xRequest, sizeof(xRequest)); +out: + kfree(cmd); kfree(reqFrag); kfree(frag); @@ -399,10 +398,10 @@ int novfs_raw_send(struct novfs_xplat *p int novfs_conn_close(struct novfs_xplat *pdata, void ** Handle, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; struct nwc_close_conn cc; - struct nwd_close_conn *nwdClose; + struct nwd_close_conn *nwdClose = NULL; int retCode = 0; unsigned long cmdlen, datalen, replylen, cpylen; @@ -439,10 +438,10 @@ int novfs_conn_close(struct novfs_xplat int novfs_sys_conn_close(struct novfs_xplat *pdata, unsigned long *Handle, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; struct nwc_close_conn cc; - struct nwd_close_conn *nwdClose; + struct nwd_close_conn *nwdClose = NULL; unsigned int retCode = 0; unsigned long cmdlen, datalen, replylen, cpylen; @@ -479,7 +478,7 @@ int novfs_sys_conn_close(struct novfs_xp int novfs_login_id(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct nwc_login_id lgn, *plgn; + struct nwc_login_id lgn, *plgn = NULL; int retCode = -ENOMEM; struct ncl_string server; struct ncl_string username; @@ -487,6 +486,11 @@ int novfs_login_id(struct novfs_xplat *p unsigned long cpylen; struct nwc_string nwcStr; + + memset(&server, 0, sizeof(server)); + memset(&username, 0, sizeof(username)); + memset(&password, 0, sizeof(password)); + cpylen = copy_from_user(&lgn, pdata->reqData, sizeof(lgn)); DbgPrint(""); @@ -496,6 +500,9 @@ int novfs_login_id(struct novfs_xplat *p DbgPrint("DomainName\n"); novfs_dump(sizeof(nwcStr), &nwcStr); + if (nwcStr.DataLen > MAX_NAME_LEN) + return -EINVAL; + if ((server.buffer = kmalloc(nwcStr.DataLen, GFP_KERNEL))) { server.type = nwcStr.DataType; server.len = nwcStr.DataLen; @@ -505,8 +512,11 @@ int novfs_login_id(struct novfs_xplat *p cpylen = copy_from_user(&nwcStr, lgn.pObjectName, sizeof(nwcStr)); DbgPrint("ObjectName"); + if (nwcStr.DataLen > MAX_OBJECT_NAME_LENGTH) { + retCode = -EINVAL; + goto out; + } novfs_dump(sizeof(nwcStr), &nwcStr); - if ((username.buffer = kmalloc(nwcStr.DataLen, GFP_KERNEL))) { username.type = nwcStr.DataType; username.len = nwcStr.DataLen; @@ -516,6 +526,10 @@ int novfs_login_id(struct novfs_xplat *p cpylen = copy_from_user(&nwcStr, lgn.pPassword, sizeof(nwcStr)); DbgPrint("Password"); + if (nwcStr.DataLen > MAX_PASSWORD_LENGTH) { + retCode = -EINVAL; + goto out; + } novfs_dump(sizeof(nwcStr), &nwcStr); if ((password.buffer = kmalloc(nwcStr.DataLen, GFP_KERNEL))) { @@ -531,24 +545,26 @@ int novfs_login_id(struct novfs_xplat *p cpylen = copy_to_user(&plgn->AuthenticationId, &lgn.AuthenticationId, sizeof(plgn->AuthenticationId)); } memset(password.buffer, 0, password.len); - kfree(password.buffer); + } } memset(username.buffer, 0, username.len); - kfree(username.buffer); } } - kfree(server.buffer); } +out: + kfree(password.buffer); + kfree(username.buffer); + kfree(server.buffer); return (retCode); } int novfs_auth_conn(struct novfs_xplat *pdata, struct novfs_schandle Session) { struct nwc_auth_with_id pauth; - struct nwc_auth_wid *pDauth; - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; + struct nwc_auth_wid *pDauth = NULL; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; int retCode = -ENOMEM; unsigned long cmdlen, datalen, replylen, cpylen; @@ -583,10 +599,10 @@ int novfs_auth_conn(struct novfs_xplat * int novfs_license_conn(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; struct nwc_license_conn lisc; - struct nwc_lisc_id * pDLisc; + struct nwc_lisc_id * pDLisc = NULL; int retCode = -ENOMEM; unsigned long cmdlen, datalen, replylen, cpylen; @@ -621,9 +637,9 @@ int novfs_license_conn(struct novfs_xpla int novfs_logout_id(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; - struct nwc_lo_id logout, *pDLogout; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; + struct nwc_lo_id logout, *pDLogout = NULL; int retCode = -ENOMEM; unsigned long cmdlen, datalen, replylen, cpylen; @@ -659,9 +675,9 @@ int novfs_logout_id(struct novfs_xplat * int novfs_unlicense_conn(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; - struct nwc_unlic_conn *pUconn, ulc; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; + struct nwc_unlic_conn *pUconn = NULL, ulc; int retCode = -ENOMEM; unsigned long cmdlen, datalen, replylen, cpylen; @@ -697,9 +713,9 @@ int novfs_unlicense_conn(struct novfs_xp int novfs_unauthenticate(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; - struct nwc_unauthenticate auth, *pDAuth; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; + struct nwc_unauthenticate auth, *pDAuth = NULL; int retCode = -ENOMEM; unsigned long cmdlen, datalen, replylen, cpylen; @@ -736,10 +752,10 @@ int novfs_unauthenticate(struct novfs_xp int novfs_get_conn_info(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; struct nwc_get_conn_info connInfo; - struct nwd_conn_info *pDConnInfo; + struct nwd_conn_info *pDConnInfo = NULL; int retCode = -ENOMEM; unsigned long cmdlen, replylen, cpylen; @@ -751,6 +767,11 @@ int novfs_get_conn_info(struct novfs_xpl if (!cmd) return -ENOMEM; + if (connInfo.uInfoLength > MAX_INFO_LEN) { + retCode = -EINVAL; + goto out; + } + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; cmd->Command.SequenceNumber = 0; cmd->Command.SessionId = Session; @@ -775,6 +796,7 @@ int novfs_get_conn_info(struct novfs_xpl kfree(reply); } +out: kfree(cmd); return (retCode); @@ -782,20 +804,23 @@ int novfs_get_conn_info(struct novfs_xpl int novfs_set_conn_info(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; struct nwc_set_conn_info connInfo; - struct nwd_set_conn_info *pDConnInfo; + struct nwd_set_conn_info *pDConnInfo = NULL; int retCode = -ENOMEM; unsigned long cmdlen, replylen, cpylen; cmdlen = sizeof(*cmd) + sizeof(*pDConnInfo); cmd = kmalloc(cmdlen, GFP_KERNEL); - cpylen = - copy_from_user(&connInfo, pdata->reqData, sizeof(struct nwc_set_conn_info)); + cpylen = copy_from_user(&connInfo, pdata->reqData, sizeof(struct nwc_set_conn_info)); if (!cmd) return -ENOMEM; + if (connInfo.uInfoLength > MAX_INFO_LEN) { + retCode = -EINVAL; + goto out; + } cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; cmd->Command.SequenceNumber = 0; @@ -817,6 +842,8 @@ int novfs_set_conn_info(struct novfs_xpl retCode = reply->Reply.ErrorCode; kfree(reply); } + +out: kfree(cmd); return (retCode); @@ -824,12 +851,12 @@ int novfs_set_conn_info(struct novfs_xpl int novfs_get_id_info(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; - struct nwc_get_id_info qidInfo, *gId; - struct nwd_get_id_info *idInfo; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; + struct nwc_get_id_info qidInfo, *gId = NULL; + struct nwd_get_id_info *idInfo = NULL; struct nwc_string xferStr; - char *str; + char *str = NULL; int retCode = -ENOMEM; unsigned long cmdlen, replylen, cpylen; @@ -846,12 +873,10 @@ int novfs_get_id_info(struct novfs_xplat cmd->NwcCommand = NWC_GET_IDENTITY_INFO; idInfo = (struct nwd_get_id_info *) cmd->data; - idInfo->AuthenticationId = qidInfo.AuthenticationId; cmd->dataLen = sizeof(*idInfo); - retCode = - Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + retCode = Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, (void **)&reply, &replylen, INTERRUPTIBLE); if (reply) { @@ -863,77 +888,77 @@ int novfs_get_id_info(struct novfs_xplat */ gId = pdata->reqData; idInfo = (struct nwd_get_id_info *) reply->data; - cpylen = - copy_to_user(&gId->AuthenticationId, + cpylen = copy_to_user(&gId->AuthenticationId, &idInfo->AuthenticationId, sizeof(idInfo-> AuthenticationId)); - cpylen = - copy_to_user(&gId->AuthType, + cpylen = copy_to_user(&gId->AuthType, &idInfo->AuthType, sizeof(idInfo->AuthType)); - cpylen = - copy_to_user(&gId->IdentityFlags, + cpylen = copy_to_user(&gId->IdentityFlags, &idInfo->IdentityFlags, sizeof(idInfo->IdentityFlags)); - cpylen = - copy_to_user(&gId->NameType, + cpylen = copy_to_user(&gId->NameType, &idInfo->NameType, sizeof(idInfo->NameType)); - cpylen = - copy_to_user(&gId->ObjectType, + cpylen = copy_to_user(&gId->ObjectType, &idInfo->ObjectType, sizeof(idInfo->ObjectType)); - cpylen = - copy_from_user(&xferStr, gId->pDomainName, + cpylen = copy_from_user(&xferStr, gId->pDomainName, sizeof(struct nwc_string)); - str = - (char *)((char *)reply->data + - idInfo->pDomainNameOffset); - cpylen = - copy_to_user(xferStr.pBuffer, str, - idInfo->domainLen); + if (idInfo->pDomainNameOffset >= reply->dataLen) { + retCode = -EINVAL; + goto out; + } + str = (char *)((char *)reply->data + idInfo->pDomainNameOffset); + if (idInfo->domainLen > reply->dataLen - idInfo->pDomainNameOffset ) { + retCode = -EINVAL; + goto out; + } + + cpylen = copy_to_user(xferStr.pBuffer, str, idInfo->domainLen); xferStr.DataType = NWC_STRING_TYPE_ASCII; xferStr.DataLen = idInfo->domainLen; - cpylen = - copy_to_user(gId->pDomainName, &xferStr, - sizeof(struct nwc_string)); + cpylen = copy_to_user(gId->pDomainName, &xferStr, sizeof(struct nwc_string)); + cpylen = copy_from_user(&xferStr, gId->pObjectName, sizeof(struct nwc_string)); - cpylen = - copy_from_user(&xferStr, gId->pObjectName, - sizeof(struct nwc_string)); - str = - (char *)((char *)reply->data + - idInfo->pObjectNameOffset); - cpylen = - copy_to_user(xferStr.pBuffer, str, - idInfo->objectLen); + if (idInfo->pObjectNameOffset >= reply->dataLen) { + retCode = -EINVAL; + goto out; + } + str = (char *)((char *)reply->data + idInfo->pObjectNameOffset); + if (idInfo->objectLen > reply->dataLen - idInfo->pObjectNameOffset) { + retCode = -EINVAL; + goto out; + } + cpylen = copy_to_user(xferStr.pBuffer, str, idInfo->objectLen); xferStr.DataLen = idInfo->objectLen - 1; xferStr.DataType = NWC_STRING_TYPE_ASCII; - cpylen = - copy_to_user(gId->pObjectName, &xferStr, - sizeof(struct nwc_string)); + cpylen = copy_to_user(gId->pObjectName, &xferStr, sizeof(struct nwc_string)); + } } +out: kfree(reply); - } kfree(cmd); return (retCode); } int novfs_scan_conn_info(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; - struct nwc_scan_conn_info connInfo, *rInfo; - struct nwd_scan_conn_info *pDConnInfo; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; + struct nwc_scan_conn_info connInfo, *rInfo = NULL; + struct nwd_scan_conn_info *pDConnInfo = NULL; int retCode = -ENOMEM; unsigned long cmdlen, replylen, cpylen; - unsigned char *localData; + unsigned char *localData = NULL; - cpylen = - copy_from_user(&connInfo, pdata->reqData, sizeof(struct nwc_scan_conn_info)); + cpylen = copy_from_user(&connInfo, pdata->reqData, sizeof(struct nwc_scan_conn_info)); + + if (connInfo.uReturnInfoLength > MAX_INFO_LEN || connInfo.uScanInfoLen > MAX_INFO_LEN) + return -EINVAL; cmdlen = sizeof(*cmd) + sizeof(*pDConnInfo) + connInfo.uScanInfoLen; cmd = kmalloc(cmdlen, GFP_KERNEL); @@ -962,8 +987,7 @@ int novfs_scan_conn_info(struct novfs_xp __DbgPrint(" connInfo.uScanFlags = 0x%X\n", connInfo.uScanFlags); pDConnInfo->uScanIndex = connInfo.uScanIndex; - pDConnInfo->uConnectionReference = - connInfo.uConnectionReference; + pDConnInfo->uConnectionReference = connInfo.uConnectionReference; pDConnInfo->uScanInfoLevel = connInfo.uScanInfoLevel; pDConnInfo->uScanInfoLen = connInfo.uScanInfoLen; pDConnInfo->uReturnInfoLength = connInfo.uReturnInfoLength; @@ -974,8 +998,7 @@ int novfs_scan_conn_info(struct novfs_xp localData = (unsigned char *) pDConnInfo; pDConnInfo->uScanConnInfoOffset = sizeof(*pDConnInfo); localData += pDConnInfo->uScanConnInfoOffset; - cpylen = - copy_from_user(localData, connInfo.pScanConnInfo, + cpylen = copy_from_user(localData, connInfo.pScanConnInfo, connInfo.uScanInfoLen); } else { pDConnInfo->uScanConnInfoOffset = 0; @@ -1035,8 +1058,7 @@ int novfs_scan_conn_info(struct novfs_xp static void GetUserData(struct nwc_scan_conn_info * connInfo, struct novfs_xplat_call_request *cmd, struct novfs_xplat_call_reply *reply) { unsigned long uLevel; - struct nwd_scan_conn_info *pDConnInfo; - + struct nwd_scan_conn_info *pDConnInfo = NULL; unsigned char *srcData = NULL; unsigned long dataLen = 0, cpylen; @@ -1082,26 +1104,17 @@ static void GetUserData(struct nwc_scan_ DbgPrint("NWC_CONN_INFO_TRAN_ADDR 0x%p -> 0x%p :: 0x%X", srcData, connInfo->pReturnConnInfo, dataLen); - cpylen = - copy_from_user(&tranAddr, dstData, - sizeof(tranAddr)); - - srcData += - ((struct nwd_scan_conn_info *) srcData)-> - uReturnConnInfoOffset; - - tranAddr.uTransportType = - ((struct nwd_tran_addr *) srcData)->uTransportType; - tranAddr.uAddressLength = - ((struct tagNwdTranAddrEx *) srcData)->uAddressLength; - - cpylen = - copy_to_user(dstData, &tranAddr, sizeof(tranAddr)); - cpylen = - copy_to_user(tranAddr.puAddress, - ((struct tagNwdTranAddrEx *) srcData)->Buffer, - ((struct tagNwdTranAddrEx *) srcData)-> - uAddressLength); + cpylen = copy_from_user(&tranAddr, dstData, sizeof(tranAddr)); + if (((struct nwd_scan_conn_info *) srcData)->uReturnConnInfoOffset >= reply->dataLen) + goto out; + srcData += ((struct nwd_scan_conn_info *)srcData)->uReturnConnInfoOffset; + tranAddr.uTransportType = ((struct nwd_tran_addr *)srcData)->uTransportType; + tranAddr.uAddressLength = ((struct tagNwdTranAddrEx *)srcData)->uAddressLength; + if (tranAddr.uAddressLength > MAX_ADDRESS_LENGTH) + goto out; + cpylen = copy_to_user(dstData, &tranAddr, sizeof(tranAddr)); + cpylen = copy_to_user(tranAddr.puAddress, + ((struct tagNwdTranAddrEx *) srcData)->Buffer, tranAddr.uAddressLength); dataLen = 0; break; } @@ -1115,13 +1128,13 @@ static void GetUserData(struct nwc_scan_ break; } - if (srcData && dataLen) { + if (srcData && dataLen && dataLen <= reply->dataLen) { DbgPrint("Copy Data 0x%p -> 0x%p :: 0x%X", srcData, connInfo->pReturnConnInfo, dataLen); - cpylen = - copy_to_user(connInfo->pReturnConnInfo, srcData, dataLen); + cpylen = copy_to_user(connInfo->pReturnConnInfo, srcData, dataLen); } +out: return; } @@ -1131,7 +1144,7 @@ static void GetUserData(struct nwc_scan_ static void GetConnData(struct nwc_get_conn_info * connInfo, struct novfs_xplat_call_request *cmd, struct novfs_xplat_call_reply *reply) { unsigned long uLevel; - struct nwd_conn_info * pDConnInfo; + struct nwd_conn_info *pDConnInfo = NULL; unsigned char *srcData = NULL; unsigned long dataLen = 0, cpylen; @@ -1156,21 +1169,17 @@ static void GetConnData(struct nwc_get_c srcData = (unsigned char *) reply->data; - cpylen = - copy_from_user(&tranAddr, dstData, - sizeof(tranAddr)); + cpylen = copy_from_user(&tranAddr, dstData, sizeof(tranAddr)); tranAddr.uTransportType = ((struct tagNwdTranAddrEx *) srcData)->uTransportType; tranAddr.uAddressLength = ((struct tagNwdTranAddrEx *) srcData)->uAddressLength; - - cpylen = - copy_to_user(dstData, &tranAddr, sizeof(tranAddr)); - cpylen = - copy_to_user(tranAddr.puAddress, + if (tranAddr.uAddressLength > MAX_ADDRESS_LENGTH) + goto out; + cpylen = copy_to_user(dstData, &tranAddr, sizeof(tranAddr)); + cpylen = copy_to_user(tranAddr.puAddress, ((struct tagNwdTranAddrEx *) srcData)->Buffer, - ((struct tagNwdTranAddrEx *) srcData)-> - uAddressLength); + tranAddr.uAddressLength); dataLen = 0; break; } @@ -1214,20 +1223,19 @@ static void GetConnData(struct nwc_get_c break; } - if (srcData && dataLen) { - cpylen = - copy_to_user(connInfo->pConnInfo, srcData, - connInfo->uInfoLength); + if (srcData && dataLen && dataLen <= reply->dataLen) { + cpylen = copy_to_user(connInfo->pConnInfo, srcData, connInfo->uInfoLength); } +out: return; } int novfs_get_daemon_ver(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; - struct nwd_get_reqversion *pDVersion; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; + struct nwd_get_reqversion *pDVersion = NULL; int retCode = -ENOMEM; unsigned long cmdlen, datalen, replylen, cpylen; @@ -1261,17 +1269,18 @@ int novfs_get_daemon_ver(struct novfs_xp int novfs_get_preferred_DS_tree(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; - struct nwd_get_pref_ds_tree *pDGetTree; - struct nwc_get_pref_ds_tree xplatCall, *p; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; + struct nwd_get_pref_ds_tree *pDGetTree = NULL; + struct nwc_get_pref_ds_tree xplatCall, *p = NULL; int retCode = -ENOMEM; unsigned long cmdlen, datalen, replylen, cpylen; - unsigned char *dPtr; + unsigned char *dPtr = NULL; - cpylen = - copy_from_user(&xplatCall, pdata->reqData, + cpylen = copy_from_user(&xplatCall, pdata->reqData, sizeof(struct nwc_get_pref_ds_tree)); + if (xplatCall.uTreeLength > NW_MAX_TREE_NAME_LEN) + return -EINVAL; datalen = sizeof(*pDGetTree) + xplatCall.uTreeLength; cmdlen = datalen + sizeof(*cmd); cmd = kmalloc(cmdlen, GFP_KERNEL); @@ -1292,10 +1301,12 @@ int novfs_get_preferred_DS_tree(struct n if (reply) { retCode = reply->Reply.ErrorCode; if (!retCode) { - pDGetTree = - (struct nwd_get_pref_ds_tree *) reply->data; - dPtr = - reply->data + pDGetTree->DsTreeNameOffset; + pDGetTree = (struct nwd_get_pref_ds_tree *) reply->data; + if (pDGetTree->DsTreeNameOffset >= reply->dataLen) { + retCode = -EINVAL; + goto out; + } + dPtr = reply->data + pDGetTree->DsTreeNameOffset; p = (struct nwc_get_pref_ds_tree *) pdata->reqData; DbgPrint("Reply recieved"); @@ -1303,14 +1314,17 @@ int novfs_get_preferred_DS_tree(struct n pDGetTree->uTreeLength); __DbgPrint(" TreeName = %s\n", dPtr); - cpylen = - copy_to_user(p, &pDGetTree->uTreeLength, 4); - cpylen = - copy_to_user(xplatCall.pDsTreeName, dPtr, - pDGetTree->uTreeLength); + if (pDGetTree->uTreeLength > reply->dataLen - pDGetTree->DsTreeNameOffset) { + retCode = -EINVAL; + goto out; + } + cpylen = copy_to_user(p, &pDGetTree->uTreeLength, 4); + cpylen = copy_to_user(xplatCall.pDsTreeName, dPtr, pDGetTree->uTreeLength); } - kfree(reply); } + +out: + kfree(reply); kfree(cmd); return (retCode); @@ -1318,17 +1332,17 @@ int novfs_get_preferred_DS_tree(struct n int novfs_set_preferred_DS_tree(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; - struct nwd_set_pref_ds_tree *pDSetTree; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; + struct nwd_set_pref_ds_tree *pDSetTree = NULL; struct nwc_set_pref_ds_tree xplatCall; int retCode = -ENOMEM; unsigned long cmdlen, datalen, replylen, cpylen; - unsigned char *dPtr; + unsigned char *dPtr = NULL; - cpylen = - copy_from_user(&xplatCall, pdata->reqData, - sizeof(struct nwc_set_pref_ds_tree)); + cpylen = copy_from_user(&xplatCall, pdata->reqData, sizeof(struct nwc_set_pref_ds_tree)); + if (xplatCall.uTreeLength > NW_MAX_TREE_NAME_LEN) + return -EINVAL; datalen = sizeof(*pDSetTree) + xplatCall.uTreeLength; cmdlen = datalen + sizeof(*cmd); cmd = kmalloc(cmdlen, GFP_KERNEL); @@ -1346,8 +1360,7 @@ int novfs_set_preferred_DS_tree(struct n pDSetTree->uTreeLength = xplatCall.uTreeLength; dPtr = cmd->data + sizeof(*pDSetTree); - cpylen = - copy_from_user(dPtr, xplatCall.pDsTreeName, + cpylen = copy_from_user(dPtr, xplatCall.pDsTreeName, xplatCall.uTreeLength); retCode = @@ -1366,19 +1379,19 @@ int novfs_set_preferred_DS_tree(struct n int novfs_set_default_ctx(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; struct nwc_set_def_name_ctx xplatCall; - struct nwd_set_def_name_ctx * pDSet; + struct nwd_set_def_name_ctx * pDSet = NULL; int retCode = -ENOMEM; unsigned long cmdlen, datalen, replylen, cpylen; - unsigned char *dPtr; + unsigned char *dPtr = NULL; - cpylen = - copy_from_user(&xplatCall, pdata->reqData, + cpylen = copy_from_user(&xplatCall, pdata->reqData, sizeof(struct nwc_set_def_name_ctx)); - datalen = - sizeof(*pDSet) + xplatCall.uTreeLength + xplatCall.uNameLength; + if (xplatCall.uNameLength > MAX_NAME_LEN || xplatCall.uTreeLength > NW_MAX_TREE_NAME_LEN) + return -EINVAL; + datalen = sizeof(*pDSet) + xplatCall.uTreeLength + xplatCall.uNameLength; cmdlen = datalen + sizeof(*cmd); cmd = kmalloc(cmdlen, GFP_KERNEL); @@ -1388,23 +1401,19 @@ int novfs_set_default_ctx(struct novfs_x cmd->Command.SequenceNumber = 0; cmd->Command.SessionId = Session; cmd->NwcCommand = NWC_SET_DEFAULT_NAME_CONTEXT; - cmd->dataLen = - sizeof(struct nwd_set_def_name_ctx) + - xplatCall.uTreeLength + xplatCall.uNameLength; + cmd->dataLen = sizeof(struct nwd_set_def_name_ctx) + xplatCall.uTreeLength + xplatCall.uNameLength; pDSet = (struct nwd_set_def_name_ctx *) cmd->data; dPtr = cmd->data; pDSet->TreeOffset = sizeof(struct nwd_set_def_name_ctx); pDSet->uTreeLength = xplatCall.uTreeLength; - pDSet->NameContextOffset = - pDSet->TreeOffset + xplatCall.uTreeLength; + pDSet->NameContextOffset = pDSet->TreeOffset + xplatCall.uTreeLength; pDSet->uNameLength = xplatCall.uNameLength; //sgled cpylen = copy_from_user(dPtr+pDSet->TreeOffset, xplatCall.pTreeName, xplatCall.uTreeLength); cpylen = copy_from_user(dPtr + pDSet->TreeOffset, xplatCall.pDsTreeName, xplatCall.uTreeLength); //sgled - cpylen = - copy_from_user(dPtr + pDSet->NameContextOffset, + cpylen = copy_from_user(dPtr + pDSet->NameContextOffset, xplatCall.pNameContext, xplatCall.uNameLength); @@ -1424,20 +1433,20 @@ int novfs_set_default_ctx(struct novfs_x int novfs_get_default_ctx(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; struct nwc_get_def_name_ctx xplatCall; - struct nwd_get_def_name_ctx * pGet; - char *dPtr; + struct nwd_get_def_name_ctx * pGet = NULL; + char *dPtr = NULL; int retCode = -ENOMEM; unsigned long cmdlen, replylen, cpylen; - cpylen = - copy_from_user(&xplatCall, pdata->reqData, + cpylen = copy_from_user(&xplatCall, pdata->reqData, sizeof(struct nwc_get_def_name_ctx)); - cmdlen = - sizeof(*cmd) + sizeof(struct nwd_get_def_name_ctx ) + - xplatCall.uTreeLength; + if (xplatCall.uTreeLength > NW_MAX_TREE_NAME_LEN) + return -EINVAL; + + cmdlen = sizeof(*cmd) + sizeof(struct nwd_get_def_name_ctx ) + xplatCall.uTreeLength; cmd = kmalloc(cmdlen, GFP_KERNEL); if (!cmd) @@ -1512,16 +1521,20 @@ int novfs_query_feature(struct novfs_xpl int novfs_get_tree_monitored_conn(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; - struct nwc_get_tree_monitored_conn_ref xplatCall, *p; - struct nwd_get_tree_monitored_conn_ref *pDConnRef; - char *dPtr; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; + struct nwc_get_tree_monitored_conn_ref xplatCall, *p = NULL; + struct nwd_get_tree_monitored_conn_ref *pDConnRef = NULL; + char *dPtr = NULL; unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; cpylen = copy_from_user(&xplatCall, pdata->reqData, sizeof(struct nwc_get_tree_monitored_conn_ref)); + if (!access_ok(VERIFY_READ, xplatCall.pTreeName, sizeof(struct nwc_string))) + return -EINVAL; + if (xplatCall.pTreeName->DataLen > NW_MAX_TREE_NAME_LEN) + return -EINVAL; datalen = sizeof(*pDConnRef) + xplatCall.pTreeName->DataLen; cmdlen = datalen + sizeof(*cmd); cmd = kmalloc(cmdlen, GFP_KERNEL); @@ -1564,12 +1577,12 @@ int novfs_get_tree_monitored_conn(struct int novfs_enum_ids(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; - struct nwc_enum_ids xplatCall, *eId; - struct nwd_enum_ids *pEnum; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; + struct nwc_enum_ids xplatCall, *eId = NULL; + struct nwd_enum_ids *pEnum = NULL; struct nwc_string xferStr; - char *str; + char *str = NULL; unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; cpylen = @@ -1629,56 +1642,71 @@ int novfs_enum_ids(struct novfs_xplat *p cpylen = copy_from_user(&xferStr, eId->pDomainName, sizeof(struct nwc_string)); + if (pEnum->domainNameOffset >= reply->dataLen) { + status = -EINVAL; + goto out; + } str = (char *)((char *)reply->data + pEnum->domainNameOffset); - DbgPrint("[XPLAT NWCAPI] Found Domain %s", - str); + DbgPrint("[XPLAT NWCAPI] Found Domain %s", str); + if (pEnum->domainNameLen > reply->dataLen - pEnum->domainNameOffset) { + status = -EINVAL; + goto out; + } cpylen = copy_to_user(xferStr.pBuffer, str, pEnum->domainNameLen); xferStr.DataType = NWC_STRING_TYPE_ASCII; xferStr.DataLen = pEnum->domainNameLen - 1; - cpylen = - copy_to_user(eId->pDomainName, &xferStr, + cpylen = copy_to_user(eId->pDomainName, &xferStr, sizeof(struct nwc_string)); - cpylen = - copy_from_user(&xferStr, eId->pObjectName, + cpylen = copy_from_user(&xferStr, eId->pObjectName, sizeof(struct nwc_string)); - str = - (char *)((char *)reply->data + - pEnum->objectNameOffset); + if (pEnum->objectNameOffset >= reply->dataLen) { + status = -EINVAL; + goto out; + } + str = (char *)((char *)reply->data + pEnum->objectNameOffset); DbgPrint("[XPLAT NWCAPI] Found User %s", str); - cpylen = - copy_to_user(xferStr.pBuffer, str, - pEnum->objectNameLen); + if (pEnum->objectNameLen > reply->dataLen - pEnum->objectNameOffset) { + status = -EINVAL; + goto out; + } + cpylen = copy_to_user(xferStr.pBuffer, str, pEnum->objectNameLen); xferStr.DataType = NWC_STRING_TYPE_ASCII; xferStr.DataLen = pEnum->objectNameLen - 1; - cpylen = - copy_to_user(eId->pObjectName, &xferStr, - sizeof(struct nwc_string)); + cpylen = copy_to_user(eId->pObjectName, &xferStr, sizeof(struct nwc_string)); } - - kfree(reply); - } +out: + kfree(reply); kfree(cmd); return (status); } int novfs_change_auth_key(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; struct nwc_change_key xplatCall; - struct nwd_change_key *pNewKey; + struct nwd_change_key *pNewKey = NULL; struct nwc_string xferStr; - char *str; - unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; + char *str = NULL; + unsigned long status = -ENOMEM, cmdlen = 0, datalen, replylen, cpylen; - cpylen = - copy_from_user(&xplatCall, pdata->reqData, sizeof(struct nwc_change_key)); + cpylen = copy_from_user(&xplatCall, pdata->reqData, sizeof(struct nwc_change_key)); + if (!access_ok(VERIFY_READ, xplatCall.pDomainName, sizeof(struct nwc_string)) || + !access_ok(VERIFY_READ, xplatCall.pObjectName, sizeof(struct nwc_string)) || + !access_ok(VERIFY_READ, xplatCall.pNewPassword, sizeof(struct nwc_string)) || + !access_ok(VERIFY_READ, xplatCall.pVerifyPassword, sizeof(struct nwc_string))) + return -EINVAL; + if (xplatCall.pDomainName->DataLen > MAX_DOMAIN_LEN || + xplatCall.pObjectName->DataLen > MAX_OBJECT_NAME_LENGTH || + xplatCall.pNewPassword->DataLen > MAX_PASSWORD_LENGTH || + xplatCall.pVerifyPassword->DataLen > MAX_PASSWORD_LENGTH) + return -EINVAL; datalen = sizeof(struct nwd_change_key) + xplatCall.pDomainName->DataLen + @@ -1707,10 +1735,12 @@ int novfs_change_auth_key(struct novfs_x * Get the tree name */ str += sizeof(*pNewKey); - cpylen = - copy_from_user(&xferStr, xplatCall.pDomainName, - sizeof(struct nwc_string)); + cpylen = copy_from_user(&xferStr, xplatCall.pDomainName, sizeof(struct nwc_string)); pNewKey->domainNameOffset = sizeof(*pNewKey); + if (xferStr.DataLen > MAX_DOMAIN_LEN) { + status = -EINVAL; + goto out; + } cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); pNewKey->domainNameLen = xferStr.DataLen; @@ -1718,11 +1748,12 @@ int novfs_change_auth_key(struct novfs_x * Get the User Name */ str += pNewKey->domainNameLen; - cpylen = - copy_from_user(&xferStr, xplatCall.pObjectName, - sizeof(struct nwc_string)); - pNewKey->objectNameOffset = - pNewKey->domainNameOffset + pNewKey->domainNameLen; + cpylen = copy_from_user(&xferStr, xplatCall.pObjectName, sizeof(struct nwc_string)); + pNewKey->objectNameOffset = pNewKey->domainNameOffset + pNewKey->domainNameLen; + if (xferStr.DataLen > MAX_OBJECT_NAME_LENGTH) { + status = -EINVAL; + goto out; + } cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); pNewKey->objectNameLen = xferStr.DataLen; @@ -1730,11 +1761,12 @@ int novfs_change_auth_key(struct novfs_x * Get the New Password */ str += pNewKey->objectNameLen; - cpylen = - copy_from_user(&xferStr, xplatCall.pNewPassword, - sizeof(struct nwc_string)); - pNewKey->newPasswordOffset = - pNewKey->objectNameOffset + pNewKey->objectNameLen; + cpylen = copy_from_user(&xferStr, xplatCall.pNewPassword, sizeof(struct nwc_string)); + pNewKey->newPasswordOffset = pNewKey->objectNameOffset + pNewKey->objectNameLen; + if (xferStr.DataLen > MAX_PASSWORD_LENGTH) { + status = -EINVAL; + goto out; + } cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); pNewKey->newPasswordLen = xferStr.DataLen; @@ -1742,34 +1774,35 @@ int novfs_change_auth_key(struct novfs_x * Get the Verify Password */ str += pNewKey->newPasswordLen; - cpylen = - copy_from_user(&xferStr, xplatCall.pVerifyPassword, - sizeof(struct nwc_string)); - pNewKey->verifyPasswordOffset = - pNewKey->newPasswordOffset + pNewKey->newPasswordLen; + cpylen = copy_from_user(&xferStr, xplatCall.pVerifyPassword, sizeof(struct nwc_string)); + pNewKey->verifyPasswordOffset = pNewKey->newPasswordOffset + pNewKey->newPasswordLen; + if (xferStr.DataLen > MAX_PASSWORD_LENGTH) { + status = -EINVAL; + goto out; + } cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); pNewKey->verifyPasswordLen = xferStr.DataLen; - status = - Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + status = Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, (void **)&reply, &replylen, INTERRUPTIBLE); if (reply) { status = reply->Reply.ErrorCode; - kfree(reply); + } +out: memset(cmd, 0, cmdlen); - + kfree(reply); kfree(cmd); return (status); } int novfs_set_pri_conn(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; struct nwc_set_primary_conn xplatCall; - struct nwd_set_primary_conn *pConn; + struct nwd_set_primary_conn *pConn = NULL; unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; cpylen = @@ -1805,7 +1838,7 @@ int novfs_set_pri_conn(struct novfs_xpla int novfs_get_pri_conn(struct novfs_xplat *pdata, struct novfs_schandle Session) { struct novfs_xplat_call_request cmd; - struct novfs_xplat_call_reply *reply; + struct novfs_xplat_call_reply *reply = NULL; unsigned long status = -ENOMEM, cmdlen, replylen, cpylen; cmdlen = (unsigned long) (&((struct novfs_xplat_call_request *) 0)->data); @@ -1837,8 +1870,8 @@ int novfs_get_pri_conn(struct novfs_xpla int novfs_set_map_drive(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; unsigned long status = 0, datalen, cmdlen, replylen; struct nwc_map_drive_ex symInfo; @@ -1846,6 +1879,8 @@ int novfs_set_map_drive(struct novfs_xpl cmdlen = sizeof(*cmd); if (copy_from_user(&symInfo, pdata->reqData, sizeof(symInfo))) return -EFAULT; + if (symInfo.dirPathOffsetLength > MAX_OFFSET_LEN || symInfo.linkOffsetLength > MAX_OFFSET_LEN) + return -EINVAL; datalen = sizeof(symInfo) + symInfo.dirPathOffsetLength + symInfo.linkOffsetLength; @@ -1890,14 +1925,16 @@ int novfs_set_map_drive(struct novfs_xpl int novfs_unmap_drive(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; unsigned long status = 0, datalen, cmdlen, replylen, cpylen; struct nwc_unmap_drive_ex symInfo; DbgPrint(""); cpylen = copy_from_user(&symInfo, pdata->reqData, sizeof(symInfo)); + if (symInfo.linkLen > MAX_NAME_LEN) + return -EINVAL; cmdlen = sizeof(*cmd); datalen = sizeof(symInfo) + symInfo.linkLen; @@ -1913,8 +1950,7 @@ int novfs_unmap_drive(struct novfs_xplat cmd->NwcCommand = NWC_UNMAP_DRIVE; cpylen = copy_from_user(cmd->data, pdata->reqData, datalen); - status = - Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + status = Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, (void **)&reply, &replylen, INTERRUPTIBLE); @@ -1928,11 +1964,11 @@ int novfs_unmap_drive(struct novfs_xplat int novfs_enum_drives(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; unsigned long status = 0, cmdlen, replylen, cpylen; unsigned long offset; - char *cp; + char *cp = NULL; DbgPrint(""); @@ -1955,37 +1991,36 @@ int novfs_enum_drives(struct novfs_xplat status = reply->Reply.ErrorCode; DbgPrint("Status Code = 0x%X", status); if (!status) { - offset = - sizeof(((struct nwc_get_mapped_drives *) pdata-> + offset = sizeof(((struct nwc_get_mapped_drives *) pdata-> repData)->MapBuffLen); cp = reply->data; - replylen = - ((struct nwc_get_mapped_drives *) pdata->repData)-> - MapBuffLen; - cpylen = - copy_to_user(pdata->repData, cp, offset); + replylen = ((struct nwc_get_mapped_drives *) pdata->repData)->MapBuffLen; + if (offset > reply->dataLen) { + status = -EINVAL; + goto out; + } + cpylen = copy_to_user(pdata->repData, cp, offset); cp += offset; - cpylen = - copy_to_user(((struct nwc_get_mapped_drives *) pdata-> + cpylen = copy_to_user(((struct nwc_get_mapped_drives *) pdata-> repData)->MapBuffer, cp, min(replylen - offset, reply->dataLen - offset)); } - - kfree(reply); } +out: + kfree(reply); kfree(cmd); return (status); } int novfs_get_bcast_msg(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; unsigned long cmdlen, replylen; int status = 0x8866, cpylen; struct nwc_get_bcast_notification msg; - struct nwd_get_bcast_notification *dmsg; + struct nwd_get_bcast_notification *dmsg = NULL; cmdlen = sizeof(*cmd) + sizeof(*dmsg); cmd = kmalloc(cmdlen, GFP_KERNEL); @@ -2013,33 +2048,21 @@ int novfs_get_bcast_msg(struct novfs_xpl if (!status) { char *cp = pdata->repData; - dmsg = - (struct nwd_get_bcast_notification *) reply->data; + dmsg = (struct nwd_get_bcast_notification *) reply->data; if (pdata->repLen < dmsg->messageLen) { dmsg->messageLen = pdata->repLen; } msg.messageLen = dmsg->messageLen; - cpylen = - offsetof(struct - nwc_get_bcast_notification, - message); + cpylen = offsetof(struct nwc_get_bcast_notification, message); cp += cpylen; - cpylen = - copy_to_user(pdata->repData, &msg, cpylen); - cpylen = - copy_to_user(cp, dmsg->message, - msg.messageLen); + cpylen = copy_to_user(pdata->repData, &msg, cpylen); + cpylen = copy_to_user(cp, dmsg->message, msg.messageLen); } else { msg.messageLen = 0; msg.message[0] = 0; - cpylen = offsetof(struct - nwc_get_bcast_notification, - message); - cpylen = - copy_to_user(pdata->repData, &msg, - sizeof(msg)); + cpylen = offsetof(struct nwc_get_bcast_notification, message); + cpylen = copy_to_user(pdata->repData, &msg, sizeof(msg)); } - kfree(reply); } kfree(cmd); @@ -2048,24 +2071,21 @@ int novfs_get_bcast_msg(struct novfs_xpl int novfs_set_key_value(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; struct nwc_set_key xplatCall; - struct nwd_set_key *pNewKey; + struct nwd_set_key *pNewKey = NULL; struct nwc_string cstrObjectName, cstrPassword; - char *str; + char *str = NULL; unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; cpylen = copy_from_user(&xplatCall, pdata->reqData, sizeof(struct nwc_set_key)); - cpylen = - copy_from_user(&cstrObjectName, xplatCall.pObjectName, - sizeof(struct nwc_string)); - cpylen = - copy_from_user(&cstrPassword, xplatCall.pNewPassword, - sizeof(struct nwc_string)); + cpylen = copy_from_user(&cstrObjectName, xplatCall.pObjectName, sizeof(struct nwc_string)); + cpylen = copy_from_user(&cstrPassword, xplatCall.pNewPassword, sizeof(struct nwc_string)); - datalen = - sizeof(struct nwd_set_key ) + cstrObjectName.DataLen + cstrPassword.DataLen; + if (cstrObjectName.DataLen > MAX_OBJECT_NAME_LENGTH || cstrPassword.DataLen > MAX_PASSWORD_LENGTH) + return -EINVAL; + datalen = sizeof(struct nwd_set_key ) + cstrObjectName.DataLen + cstrPassword.DataLen; cmdlen = sizeof(*cmd) + datalen; cmd = kmalloc(cmdlen, GFP_KERNEL); @@ -2099,16 +2119,12 @@ int novfs_set_key_value(struct novfs_xpl /* * Get the Verify Password */ - cpylen = - copy_from_user(str, cstrPassword.pBuffer, - cstrPassword.DataLen); + cpylen = copy_from_user(str, cstrPassword.pBuffer, cstrPassword.DataLen); pNewKey->newPasswordLen = cstrPassword.DataLen; - pNewKey->newPasswordOffset = - pNewKey->objectNameOffset + pNewKey->objectNameLen; + pNewKey->newPasswordOffset = pNewKey->objectNameOffset + pNewKey->objectNameLen; - status = - Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + status = Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, (void **)&reply, &replylen, INTERRUPTIBLE); if (reply) { @@ -2121,16 +2137,22 @@ int novfs_set_key_value(struct novfs_xpl int novfs_verify_key_value(struct novfs_xplat *pdata, struct novfs_schandle Session) { - struct novfs_xplat_call_request *cmd; - struct novfs_xplat_call_reply *reply; + struct novfs_xplat_call_request *cmd = NULL; + struct novfs_xplat_call_reply *reply = NULL; struct nwc_verify_key xplatCall; - struct nwd_verify_key *pNewKey; + struct nwd_verify_key *pNewKey = NULL; struct nwc_string xferStr; - char *str; + char *str = NULL; unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; - cpylen = - copy_from_user(&xplatCall, pdata->reqData, sizeof(struct nwc_verify_key)); + cpylen = copy_from_user(&xplatCall, pdata->reqData, sizeof(struct nwc_verify_key)); + + if (!access_ok(VERIFY_READ, xplatCall.pDomainName, sizeof(struct nwc_string)) || + !access_ok(VERIFY_READ, xplatCall.pVerifyPassword, sizeof(struct nwc_string))) + return -EINVAL; + if (xplatCall.pDomainName->DataLen > MAX_NAME_LEN || xplatCall.pObjectName->DataLen > MAX_OBJECT_NAME_LENGTH || + xplatCall.pVerifyPassword->DataLen > MAX_PASSWORD_LENGTH) + return -EINVAL; datalen = sizeof(struct nwd_verify_key) + xplatCall.pDomainName->DataLen + @@ -2169,11 +2191,9 @@ int novfs_verify_key_value(struct novfs_ * Get the User Name */ str += pNewKey->domainNameLen; - cpylen = - copy_from_user(&xferStr, xplatCall.pObjectName, + cpylen = copy_from_user(&xferStr, xplatCall.pObjectName, sizeof(struct nwc_string)); - pNewKey->objectNameOffset = - pNewKey->domainNameOffset + pNewKey->domainNameLen; + pNewKey->objectNameOffset = pNewKey->domainNameOffset + pNewKey->domainNameLen; cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); pNewKey->objectNameLen = xferStr.DataLen; @@ -2181,16 +2201,14 @@ int novfs_verify_key_value(struct novfs_ * Get the Verify Password */ str += pNewKey->objectNameLen; - cpylen = - copy_from_user(&xferStr, xplatCall.pVerifyPassword, + cpylen = copy_from_user(&xferStr, xplatCall.pVerifyPassword, sizeof(struct nwc_string)); pNewKey->verifyPasswordOffset = pNewKey->objectNameOffset + pNewKey->objectNameLen; cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); pNewKey->verifyPasswordLen = xferStr.DataLen; - status = - Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + status = Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, (void **)&reply, &replylen, INTERRUPTIBLE); if (reply) { @@ -2200,3 +2218,4 @@ int novfs_verify_key_value(struct novfs_ kfree(cmd); return (status); } + --- a/fs/novfs/nwcapi.h +++ b/fs/novfs/nwcapi.h @@ -297,6 +297,18 @@ N_EXTERN_LIBRARY(NWRCODE) #define MAX_ADDRESS_LENGTH 32 #define MAX_NAME_SERVICE_PROVIDERS 10 +#define MAX_NAME_LEN 1024 +#define MAX_NUM_REPLIES 4096 +#define MIN_NUM_REPLIES 1 +#define MAX_NUM_REQUESTS 4096 +#define MIN_NUM_REQUESTS 1 +#define MAX_FRAG_SIZE 4096 +#define MIN_FRAG_SIZE 1 +#define MAX_INFO_LEN 4096 +#define MAX_DOMAIN_LEN MAX_NETWORK_NAME_LENGTH +#define MAX_OFFSET_LEN 4096 + + // // Flags for the GetBroadcastMessage API //