diff options
author | 2008-02-20 00:07:00 +0000 | |
---|---|---|
committer | 2008-02-20 00:07:00 +0000 | |
commit | 4fa4a321731bee0dc7ced70667a2539150968f50 (patch) | |
tree | 200601e868c1087146b986f07c8b8501f9a8f06d | |
parent | Releasing 2.6.18-9 (diff) | |
download | xen-4fa4a321731bee0dc7ced70667a2539150968f50.tar.gz xen-4fa4a321731bee0dc7ced70667a2539150968f50.tar.bz2 xen-4fa4a321731bee0dc7ced70667a2539150968f50.zip |
Update to current set of Security patches for 2.6.18
svn path=/patches/; revision=67
20 files changed, 2450 insertions, 0 deletions
diff --git a/trunk/2.6.18/00000_README b/trunk/2.6.18/00000_README index 3eae5d1..9202654 100644 --- a/trunk/2.6.18/00000_README +++ b/trunk/2.6.18/00000_README @@ -196,9 +196,96 @@ Patches fix for CVE-2007-2242. Thanks to Brian Haley for the patch. (closes: Debian #440127) +/* This is already in Xen 3.2 30042_reset-pdeathsig-on-suid-upstream.patch Update fix for CVE-2007-3848 with the patch accepted upstream (formerly 30013_reset-pdeathsig-on-suid.patch) +*/ + +30043_don-t-leak-nt-bit-into-next-task-xen.patch + [SECURITY] Don't leak NT bit into next task (Xen). + See CVE-2006-5755 + +30044_cifs-better-failed-mount-errors.patch, +30045_cifs-corrupt-server-response-overflow.patch + [SECURITY][CIFS] Fix multiple overflows that can be remotely triggered + by a server sending a corrupt response. + See CVE-2007-5904 + +30046_wait_task_stopped-hang.patch + [SECURITY] wait_task_stopped was incorrectly testing for TASK_TRACED - + check p->exit_state instead avoiding a potential system hang + See CVE-2007-5500 + +30047_ieee80211-underflow.patch + [SECURITY] Fix integer overflow in ieee80211 which makes it possible + for a malicious frame to crash a system using a driver built on top of + the Linux 802.11 wireless code. + See CVE-2007-4997 + +30048_sysfs_readdir-NULL-deref-1.patch, +30049_sysfs_readdir-NULL-deref-2.patch, +30050_sysfs-fix-condition-check.patch + [SECURITY] Fix potential NULL pointer dereference which can lead to + a local DoS (kernel oops) + See CVE-2007-3104 + +30051_tmpfs-restore-clear_highpage.patch + [SECURITY] Fix a theoretical kernel memory leak in the tmpfs filesystem + See CVE-2007-6417 + +30052_minixfs-printk-hang.patch + [SECURITY] Rate-limit printks caused by accessing a corrupted minixfs + filesystem that would otherwise cause a system to hang (printk storm) + See CVE-2006-6058 + +30053_hrtimer-large-relative-timeouts-overflow.patch + [SECURITY] Avoid overflow in hrtimers due to large relative timeouts + See CVE-2007-5966 + +30054_coredump-only-to-same-uid.patch + [SECURITY] Fix an issue where core dumping over a file that + already exists retains the ownership of the original file + See CVE-2007-6206 + +30055_isdn-net-overflow.patch + [SECURITY] Fix potential overflows in the ISDN subsystem + See CVE-2007-6063 + +30056_proc-snd-page-alloc-mem-leak.patch + [SECURITY][ABI Changer] Fix an issue in the alsa subsystem that allows a + local user to read potentially sensitive kernel memory from the proc + filesystem + See CVE-2007-4571 + +30057_fat-move-ioctl-compat-code.patch +30058_bugfix/fat-fix-compat-ioctls.patch + [SECURITY][ABI Changer] Fix kernel_dirent corruption in the compat layer + for fat ioctls + See CVE-2007-2878 + +30059_vfs-use-access-mode-flag.patch + [SECURITY] Use the access mode flag instead of the open flag when + testing access mode for a directory. Modify + features/all/vserver/vs2.0.2.2-rc9.patch to apply on top of this + See CVE-2008-0001 + +30060_i4l-isdn_ioctl-mem-overrun.patch + [SECURITY] Fix potential isdn ioctl memory overrun + See CVE-2007-6151 + +30061_vmsplice-security.patch + [SECURITY] Fix missing access check in vmsplice. + See CVE-2008-0010, CVE-2008-0600 + +30062_clear-spurious-irq.patch + Fix a minor denial of service issue that allows local users to disable + an interrupt by causing an interrupt handler to be quickly inserted/removed. + This has only been shown to happen with certain serial devices so can only + be triggered by a user who already has additional priveleges (dialout + group). (closes: Debian #404815) + + 50009_gentooify-tls-warning.patch Change tls warning instructions to apply directly to Gentoo. diff --git a/trunk/2.6.18/30044_cifs-better-failed-mount-errors.patch b/trunk/2.6.18/30044_cifs-better-failed-mount-errors.patch new file mode 100644 index 0000000..d3b7c91 --- /dev/null +++ b/trunk/2.6.18/30044_cifs-better-failed-mount-errors.patch @@ -0,0 +1,234 @@ +From: Steve French <sfrench@us.ibm.com> +Date: Thu, 18 Oct 2007 21:45:27 +0000 (+0000) +Subject: [CIFS] log better errors on failed mounts +X-Git-Tag: v2.6.24-rc1~138^2 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=a761ac579b89bc1f00212a42401398108deba65c + +[CIFS] log better errors on failed mounts + +Also returns more accurate errors to mount for the cases of +account expired and password expired + +Acked-by: Jeff Layton <jlayton@redhat.com> +Signed-off-by: Steve French <sfrench@us.ibm.com> +--- + +Backported to Debian's 2.6.18 by dann frazier <dannf@debian.org> + +diff -urpN linux-source-2.6.18.orig/fs/cifs/cifsproto.h linux-source-2.6.18/fs/cifs/cifsproto.h +--- linux-source-2.6.18.orig/fs/cifs/cifsproto.h 2006-09-19 21:42:06.000000000 -0600 ++++ linux-source-2.6.18/fs/cifs/cifsproto.h 2007-11-25 14:13:04.000000000 -0700 +@@ -49,7 +49,8 @@ extern int SendReceive(const unsigned in + int * /* bytes returned */ , const int long_op); + extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, + struct kvec *, int /* nvec to send */, +- int * /* type of buf returned */ , const int long_op); ++ int * /* type of buf returned */ , const int long_op, ++ const int logError /* whether to log status code*/ ); + extern int SendReceiveBlockingLock(const unsigned int /* xid */ , struct cifsTconInfo *, + struct smb_hdr * /* input */ , + struct smb_hdr * /* out */ , +@@ -64,7 +65,7 @@ extern unsigned int smbCalcSize_LE(struc + extern int decode_negTokenInit(unsigned char *security_blob, int length, + enum securityEnum *secType); + extern int cifs_inet_pton(int, char * source, void *dst); +-extern int map_smb_to_linux_error(struct smb_hdr *smb); ++extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr); + extern void header_assemble(struct smb_hdr *, char /* command */ , + const struct cifsTconInfo *, int /* length of + fixed section (word count) in two byte units */); +diff -urpN linux-source-2.6.18.orig/fs/cifs/cifssmb.c linux-source-2.6.18/fs/cifs/cifssmb.c +--- linux-source-2.6.18.orig/fs/cifs/cifssmb.c 2007-10-03 12:38:14.000000000 -0600 ++++ linux-source-2.6.18/fs/cifs/cifssmb.c 2007-11-25 14:14:07.000000000 -0700 +@@ -1170,9 +1170,8 @@ CIFSSMBRead(const int xid, struct cifsTc + + iov[0].iov_base = (char *)pSMB; + iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; +- rc = SendReceive2(xid, tcon->ses, iov, +- 1 /* num iovecs */, +- &resp_buf_type, 0); ++ rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, ++ &resp_buf_type, 0 /* not long op */, 1 /* log err */ ); + cifs_stats_inc(&tcon->num_reads); + pSMBr = (READ_RSP *)iov[0].iov_base; + if (rc) { +@@ -1389,7 +1388,7 @@ CIFSSMBWrite2(const int xid, struct cifs + + + rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, +- long_op); ++ long_op, 0 /* do not log STATUS code */ ); + cifs_stats_inc(&tcon->num_writes); + if (rc) { + cFYI(1, ("Send error Write2 = %d", rc)); +@@ -2822,7 +2821,8 @@ CIFSSMBGetCIFSACL(const int xid, struct + iov[0].iov_base = (char *)pSMB; + iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; + +- rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0); ++ rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, ++ 0 /* not long op */, 0 /* do not log STATUS codes */ ); + cifs_stats_inc(&tcon->num_acl_get); + if (rc) { + cFYI(1, ("Send error in QuerySecDesc = %d", rc)); +diff -urpN linux-source-2.6.18.orig/fs/cifs/netmisc.c linux-source-2.6.18/fs/cifs/netmisc.c +--- linux-source-2.6.18.orig/fs/cifs/netmisc.c 2006-09-19 21:42:06.000000000 -0600 ++++ linux-source-2.6.18/fs/cifs/netmisc.c 2007-11-25 14:16:03.000000000 -0700 +@@ -114,10 +114,16 @@ static const struct smb_to_posix_error m + {ERRusempx, -EIO}, + {ERRusestd, -EIO}, + {ERR_NOTIFY_ENUM_DIR, -ENOBUFS}, +- {ERRaccountexpired, -EACCES}, ++ {ERRnoSuchUser, -EACCES}, ++/* {ERRaccountexpired, -EACCES}, + {ERRbadclient, -EACCES}, + {ERRbadLogonTime, -EACCES}, +- {ERRpasswordExpired, -EACCES}, ++ {ERRpasswordExpired, -EACCES},*/ ++ {ERRaccountexpired, -EKEYEXPIRED}, ++ {ERRbadclient, -EACCES}, ++ {ERRbadLogonTime, -EACCES}, ++ {ERRpasswordExpired, -EKEYEXPIRED}, ++ + {ERRnosupport, -EINVAL}, + {0, 0} + }; +@@ -314,7 +320,7 @@ static const struct { + from NT_STATUS_NO_SUCH_USER to NT_STATUS_LOGON_FAILURE + during the session setup } */ + { +- ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER}, { /* could map to 2238 */ + ERRHRD, ERRgeneral, NT_STATUS_GROUP_EXISTS}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_GROUP}, { + ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_GROUP}, { +@@ -329,10 +335,10 @@ static const struct { + ERRHRD, ERRgeneral, NT_STATUS_PASSWORD_RESTRICTION}, { + ERRDOS, ERRnoaccess, NT_STATUS_LOGON_FAILURE}, { + ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, { +- ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS}, { +- ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION}, { ++ ERRSRV, ERRbadLogonTime, NT_STATUS_INVALID_LOGON_HOURS}, { ++ ERRSRV, ERRbadclient, NT_STATUS_INVALID_WORKSTATION}, { + ERRSRV, ERRpasswordExpired, NT_STATUS_PASSWORD_EXPIRED}, { +- ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED}, { ++ ERRSRV, ERRaccountexpired, NT_STATUS_ACCOUNT_DISABLED}, { + ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, { + ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, { + ERRHRD, ERRgeneral, NT_STATUS_LUIDS_EXHAUSTED}, { +@@ -629,7 +635,7 @@ static const struct { + ERRDOS, ERRnoaccess, NT_STATUS_TRUST_FAILURE}, { + ERRHRD, ERRgeneral, NT_STATUS_MUTANT_LIMIT_EXCEEDED}, { + ERRDOS, ERRnetlogonNotStarted, NT_STATUS_NETLOGON_NOT_STARTED}, { +- ERRSRV, 2239, NT_STATUS_ACCOUNT_EXPIRED}, { ++ ERRSRV, ERRaccountexpired, NT_STATUS_ACCOUNT_EXPIRED}, { + ERRHRD, ERRgeneral, NT_STATUS_POSSIBLE_DEADLOCK}, { + ERRHRD, ERRgeneral, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT}, { + ERRHRD, ERRgeneral, NT_STATUS_REMOTE_SESSION_LIMIT}, { +@@ -798,7 +804,7 @@ ntstatus_to_dos(__u32 ntstatus, __u8 * e + } + + int +-map_smb_to_linux_error(struct smb_hdr *smb) ++map_smb_to_linux_error(struct smb_hdr *smb, int logErr) + { + unsigned int i; + int rc = -EIO; /* if transport error smb error may not be set */ +@@ -814,7 +820,9 @@ map_smb_to_linux_error(struct smb_hdr *s + if (smb->Flags2 & SMBFLG2_ERR_STATUS) { + /* translate the newer STATUS codes to old style errors and then to POSIX errors */ + __u32 err = le32_to_cpu(smb->Status.CifsError); +- if(cifsFYI & CIFS_RC) ++ if (logErr && (err != (NT_STATUS_MORE_PROCESSING_REQUIRED))) ++ cifs_print_status(err); ++ else if (cifsFYI & CIFS_RC) + cifs_print_status(err); + ntstatus_to_dos(err, &smberrclass, &smberrcode); + } else { +@@ -854,7 +862,8 @@ map_smb_to_linux_error(struct smb_hdr *s + } + /* else ERRHRD class errors or junk - return EIO */ + +- cFYI(1, (" !!Mapping smb error code %d to POSIX err %d !!", smberrcode,rc)); ++ cFYI(1, ("Mapping smb error code %d to POSIX err %d", ++ smberrcode, rc)); + + /* generic corrective action e.g. reconnect SMB session on ERRbaduid could be added */ + +diff -urpN linux-source-2.6.18.orig/fs/cifs/sess.c linux-source-2.6.18/fs/cifs/sess.c +--- linux-source-2.6.18.orig/fs/cifs/sess.c 2006-09-19 21:42:06.000000000 -0600 ++++ linux-source-2.6.18/fs/cifs/sess.c 2007-11-25 14:17:16.000000000 -0700 +@@ -482,7 +482,8 @@ CIFS_SessSetup(unsigned int xid, struct + + iov[1].iov_base = str_area; + iov[1].iov_len = count; +- rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, 0); ++ rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, ++ 0 /* not long op */, 1 /* log NT STATUS if any */ ); + /* SMB request buf freed in SendReceive2 */ + + cFYI(1,("ssetup rc from sendrecv2 is %d",rc)); +diff -urpN linux-source-2.6.18.orig/fs/cifs/smberr.h linux-source-2.6.18/fs/cifs/smberr.h +--- linux-source-2.6.18.orig/fs/cifs/smberr.h 2006-09-19 21:42:06.000000000 -0600 ++++ linux-source-2.6.18/fs/cifs/smberr.h 2007-11-25 14:12:02.000000000 -0700 +@@ -173,9 +173,10 @@ + #define ERRusestd 251 /* temporarily unable to use either raw + or mpx */ + #define ERR_NOTIFY_ENUM_DIR 1024 ++#define ERRnoSuchUser 2238 /* user account does not exist */ + #define ERRaccountexpired 2239 +-#define ERRbadclient 2240 +-#define ERRbadLogonTime 2241 ++#define ERRbadclient 2240 /* can not logon from this client */ ++#define ERRbadLogonTime 2241 /* logon hours do not allow this */ + #define ERRpasswordExpired 2242 + #define ERRnetlogonNotStarted 2455 + #define ERRnosupport 0xFFFF +diff -urpN linux-source-2.6.18.orig/fs/cifs/transport.c linux-source-2.6.18/fs/cifs/transport.c +--- linux-source-2.6.18.orig/fs/cifs/transport.c 2006-09-19 21:42:06.000000000 -0600 ++++ linux-source-2.6.18/fs/cifs/transport.c 2007-11-25 14:18:15.000000000 -0700 +@@ -419,7 +419,7 @@ static int wait_for_response(struct cifs + int + SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, + struct kvec *iov, int n_vec, int * pRespBufType /* ret */, +- const int long_op) ++ const int long_op, const int logError) + { + int rc = 0; + unsigned int receive_len; +@@ -465,7 +465,6 @@ SendReceive2(const unsigned int xid, str + wake_up(&ses->server->request_q); + return rc; + } +- + rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); + + midQ->midState = MID_REQUEST_SUBMITTED; +@@ -568,8 +567,7 @@ SendReceive2(const unsigned int xid, str + } + + /* BB special case reconnect tid and uid here? */ +- /* BB special case Errbadpassword and pwdexpired here */ +- rc = map_smb_to_linux_error(midQ->resp_buf); ++ rc = map_smb_to_linux_error(midQ->resp_buf, logError); + + /* convert ByteCount if necessary */ + if (receive_len >= +@@ -750,7 +748,7 @@ SendReceive(const unsigned int xid, stru + *pbytes_returned = out_buf->smb_buf_length; + + /* BB special case reconnect tid and uid here? */ +- rc = map_smb_to_linux_error(out_buf); ++ rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); + + /* convert ByteCount if necessary */ + if (receive_len >= +@@ -995,7 +993,7 @@ SendReceiveBlockingLock(const unsigned i + *pbytes_returned = out_buf->smb_buf_length; + + /* BB special case reconnect tid and uid here? */ +- rc = map_smb_to_linux_error(out_buf); ++ rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); + + /* convert ByteCount if necessary */ + if (receive_len >= diff --git a/trunk/2.6.18/30045_cifs-corrupt-server-response-overflow.patch b/trunk/2.6.18/30045_cifs-corrupt-server-response-overflow.patch new file mode 100644 index 0000000..eb79c7b --- /dev/null +++ b/trunk/2.6.18/30045_cifs-corrupt-server-response-overflow.patch @@ -0,0 +1,694 @@ +From: Steve French <sfrench@us.ibm.com> +Date: Tue, 13 Nov 2007 22:41:37 +0000 (+0000) +Subject: [CIFS] Fix buffer overflow if server sends corrupt response to small +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fsfrench%2Fcifs-2.6.git;a=commitdiff_plain;h=133672efbc1085f9af990bdc145e1822ea93bcf3 + +[CIFS] Fix buffer overflow if server sends corrupt response to small +request + +In SendReceive() function in transport.c - it memcpy's +message payload into a buffer passed via out_buf param. The function +assumes that all buffers are of size (CIFSMaxBufSize + +MAX_CIFS_HDR_SIZE) , unfortunately it is also called with smaller +(MAX_CIFS_SMALL_BUFFER_SIZE) buffers. There are eight callers +(SMB worker functions) which are primarily affected by this change: + +TreeDisconnect, uLogoff, Close, findClose, SetFileSize, SetFileTimes, +Lock and PosixLock + +CC: Dave Kleikamp <shaggy@austin.ibm.com> +CC: Przemyslaw Wegrzyn <czajnik@czajsoft.pl> +Acked-by: Jeff Layton <jlayton@redhat.com> +Signed-off-by: Steve French <sfrench@us.ibm.com> +--- + +Backported to Debian's 2.6.18 by dann frazier <dannf@debian.org> + +diff -urpN linux-source-2.6.18.orig/fs/cifs/cifsglob.h linux-source-2.6.18/fs/cifs/cifsglob.h +--- linux-source-2.6.18.orig/fs/cifs/cifsglob.h 2006-09-19 21:42:06.000000000 -0600 ++++ linux-source-2.6.18/fs/cifs/cifsglob.h 2007-11-25 14:19:26.000000000 -0700 +@@ -437,6 +437,17 @@ struct dir_notify_req { + #define CIFS_LARGE_BUFFER 2 + #define CIFS_IOVEC 4 /* array of response buffers */ + ++/* Type of Request to SendReceive2 */ ++#define CIFS_STD_OP 0 /* normal request timeout */ ++#define CIFS_LONG_OP 1 /* long op (up to 45 sec, oplock time) */ ++#define CIFS_VLONG_OP 2 /* sloow op - can take up to 180 seconds */ ++#define CIFS_BLOCKING_OP 4 /* operation can block */ ++#define CIFS_ASYNC_OP 8 /* do not wait for response */ ++#define CIFS_TIMEOUT_MASK 0x00F /* only one of 5 above set in req */ ++#define CIFS_LOG_ERROR 0x010 /* log NT STATUS if non-zero */ ++#define CIFS_LARGE_BUF_OP 0x020 /* large request buffer */ ++#define CIFS_NO_RESP 0x040 /* no response buffer required */ ++ + /* Security Flags: indicate type of session setup needed */ + #define CIFSSEC_MAY_SIGN 0x00001 + #define CIFSSEC_MAY_NTLM 0x00002 +diff -urpN linux-source-2.6.18.orig/fs/cifs/cifsproto.h linux-source-2.6.18/fs/cifs/cifsproto.h +--- linux-source-2.6.18.orig/fs/cifs/cifsproto.h 2007-11-25 14:13:04.000000000 -0700 ++++ linux-source-2.6.18/fs/cifs/cifsproto.h 2007-11-25 14:21:47.000000000 -0700 +@@ -47,10 +47,11 @@ extern int SendReceive(const unsigned in + struct smb_hdr * /* input */ , + struct smb_hdr * /* out */ , + int * /* bytes returned */ , const int long_op); ++extern int SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses, ++ struct smb_hdr *in_buf, int flags); + extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, + struct kvec *, int /* nvec to send */, +- int * /* type of buf returned */ , const int long_op, +- const int logError /* whether to log status code*/ ); ++ int * /* type of buf returned */ , const int flags); + extern int SendReceiveBlockingLock(const unsigned int /* xid */ , struct cifsTconInfo *, + struct smb_hdr * /* input */ , + struct smb_hdr * /* out */ , +diff -urpN linux-source-2.6.18.orig/fs/cifs/cifssmb.c linux-source-2.6.18/fs/cifs/cifssmb.c +--- linux-source-2.6.18.orig/fs/cifs/cifssmb.c 2007-11-25 14:14:07.000000000 -0700 ++++ linux-source-2.6.18/fs/cifs/cifssmb.c 2007-11-25 14:26:03.000000000 -0700 +@@ -619,9 +619,7 @@ int + CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) + { + struct smb_hdr *smb_buffer; +- struct smb_hdr *smb_buffer_response; /* BB removeme BB */ + int rc = 0; +- int length; + + cFYI(1, ("In tree disconnect")); + /* +@@ -658,16 +656,12 @@ CIFSSMBTDis(const int xid, struct cifsTc + if (rc) { + up(&tcon->tconSem); + return rc; +- } else { +- smb_buffer_response = smb_buffer; /* BB removeme BB */ + } +- rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response, +- &length, 0); ++ ++ rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0); + if (rc) + cFYI(1, ("Tree disconnect failed %d", rc)); + +- if (smb_buffer) +- cifs_small_buf_release(smb_buffer); + up(&tcon->tconSem); + + /* No need to return error on this operation if tid invalidated and +@@ -681,10 +675,8 @@ CIFSSMBTDis(const int xid, struct cifsTc + int + CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) + { +- struct smb_hdr *smb_buffer_response; + LOGOFF_ANDX_REQ *pSMB; + int rc = 0; +- int length; + + cFYI(1, ("In SMBLogoff for session disconnect")); + if (ses) +@@ -703,8 +695,6 @@ CIFSSMBLogoff(const int xid, struct cifs + return rc; + } + +- smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */ +- + if(ses->server) { + pSMB->hdr.Mid = GetNextMid(ses->server); + +@@ -716,8 +706,7 @@ CIFSSMBLogoff(const int xid, struct cifs + pSMB->hdr.Uid = ses->Suid; + + pSMB->AndXCommand = 0xFF; +- rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, +- smb_buffer_response, &length, 0); ++ rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0); + if (ses->server) { + atomic_dec(&ses->server->socketUseCount); + if (atomic_read(&ses->server->socketUseCount) == 0) { +@@ -728,7 +717,6 @@ CIFSSMBLogoff(const int xid, struct cifs + } + } + up(&ses->sesSem); +- cifs_small_buf_release(pSMB); + + /* if session dead then we do not need to do ulogoff, + since server closed smb session, no sense reporting +@@ -978,7 +966,7 @@ OldOpenRetry: + pSMB->ByteCount = cpu_to_le16(count); + /* long_op set to 1 to allow for oplock break timeouts */ + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, +- (struct smb_hdr *) pSMBr, &bytes_returned, 1); ++ (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP); + cifs_stats_inc(&tcon->num_opens); + if (rc) { + cFYI(1, ("Error in Open = %d", rc)); +@@ -1092,7 +1080,7 @@ openRetry: + pSMB->ByteCount = cpu_to_le16(count); + /* long_op set to 1 to allow for oplock break timeouts */ + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, +- (struct smb_hdr *) pSMBr, &bytes_returned, 1); ++ (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP); + cifs_stats_inc(&tcon->num_opens); + if (rc) { + cFYI(1, ("Error in Open = %d", rc)); +@@ -1171,7 +1159,7 @@ CIFSSMBRead(const int xid, struct cifsTc + iov[0].iov_base = (char *)pSMB; + iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; + rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, +- &resp_buf_type, 0 /* not long op */, 1 /* log err */ ); ++ &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR); + cifs_stats_inc(&tcon->num_reads); + pSMBr = (READ_RSP *)iov[0].iov_base; + if (rc) { +@@ -1388,7 +1376,7 @@ CIFSSMBWrite2(const int xid, struct cifs + + + rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, +- long_op, 0 /* do not log STATUS code */ ); ++ long_op); + cifs_stats_inc(&tcon->num_writes); + if (rc) { + cFYI(1, ("Send error Write2 = %d", rc)); +@@ -1430,7 +1418,7 @@ CIFSSMBLock(const int xid, struct cifsTc + int timeout = 0; + __u16 count; + +- cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock)); ++ cFYI(1, ("CIFSSMBLock timeout %d numLock %d", waitFlag, numLock)); + rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB); + + if (rc) +@@ -1439,10 +1427,10 @@ CIFSSMBLock(const int xid, struct cifsTc + pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */ + + if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) { +- timeout = -1; /* no response expected */ ++ timeout = CIFS_ASYNC_OP; /* no response expected */ + pSMB->Timeout = 0; + } else if (waitFlag == TRUE) { +- timeout = 3; /* blocking operation, no timeout */ ++ timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */ + pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */ + } else { + pSMB->Timeout = 0; +@@ -1472,15 +1460,16 @@ CIFSSMBLock(const int xid, struct cifsTc + if (waitFlag) { + rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned); ++ cifs_small_buf_release(pSMB); + } else { +- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, +- (struct smb_hdr *) pSMBr, &bytes_returned, timeout); ++ rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB, ++ timeout); ++ /* SMB buffer freed by function above */ + } + cifs_stats_inc(&tcon->num_locks); + if (rc) { + cFYI(1, ("Send error in Lock = %d", rc)); + } +- cifs_small_buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ +@@ -1500,7 +1489,9 @@ CIFSSMBPosixLock(const int xid, struct c + int rc = 0; + int timeout = 0; + int bytes_returned = 0; ++ int resp_buf_type = 0; + __u16 params, param_offset, offset, byte_count, count; ++ struct kvec iov[1]; + + cFYI(1, ("Posix Lock")); + +@@ -1544,7 +1535,7 @@ CIFSSMBPosixLock(const int xid, struct c + + parm_data->lock_type = cpu_to_le16(lock_type); + if(waitFlag) { +- timeout = 3; /* blocking operation, no timeout */ ++ timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */ + parm_data->lock_flags = cpu_to_le16(1); + pSMB->Timeout = cpu_to_le32(-1); + } else +@@ -1564,8 +1555,13 @@ CIFSSMBPosixLock(const int xid, struct c + rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned); + } else { +- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, +- (struct smb_hdr *) pSMBr, &bytes_returned, timeout); ++ iov[0].iov_base = (char *)pSMB; ++ iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; ++ rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, ++ &resp_buf_type, timeout); ++ pSMB = NULL; /* request buf already freed by SendReceive2. Do ++ not try to free it twice below on exit */ ++ pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base; + } + + if (rc) { +@@ -1600,6 +1596,11 @@ plk_err_exit: + if (pSMB) + cifs_small_buf_release(pSMB); + ++ if (resp_buf_type == CIFS_SMALL_BUFFER) ++ cifs_small_buf_release(iov[0].iov_base); ++ else if (resp_buf_type == CIFS_LARGE_BUFFER) ++ cifs_buf_release(iov[0].iov_base); ++ + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + +@@ -1612,8 +1613,6 @@ CIFSSMBClose(const int xid, struct cifsT + { + int rc = 0; + CLOSE_REQ *pSMB = NULL; +- CLOSE_RSP *pSMBr = NULL; +- int bytes_returned; + cFYI(1, ("In CIFSSMBClose")); + + /* do not retry on dead session on close */ +@@ -1623,13 +1622,10 @@ CIFSSMBClose(const int xid, struct cifsT + if (rc) + return rc; + +- pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */ +- + pSMB->FileID = (__u16) smb_file_id; + pSMB->LastWriteTime = 0; + pSMB->ByteCount = 0; +- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, +- (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); + cifs_stats_inc(&tcon->num_closes); + if (rc) { + if(rc!=-EINTR) { +@@ -1638,8 +1634,6 @@ CIFSSMBClose(const int xid, struct cifsT + } + } + +- cifs_small_buf_release(pSMB); +- + /* Since session is dead, file will be closed on server already */ + if(rc == -EAGAIN) + rc = 0; +@@ -2822,7 +2816,7 @@ CIFSSMBGetCIFSACL(const int xid, struct + iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; + + rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, +- 0 /* not long op */, 0 /* do not log STATUS codes */ ); ++ CIFS_STD_OP); + cifs_stats_inc(&tcon->num_acl_get); + if (rc) { + cFYI(1, ("Send error in QuerySecDesc = %d", rc)); +@@ -3444,8 +3438,6 @@ CIFSFindClose(const int xid, struct cifs + { + int rc = 0; + FINDCLOSE_REQ *pSMB = NULL; +- CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */ +- int bytes_returned; + + cFYI(1, ("In CIFSSMBFindClose")); + rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB); +@@ -3457,16 +3449,13 @@ CIFSFindClose(const int xid, struct cifs + if (rc) + return rc; + +- pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */ + pSMB->FileID = searchHandle; + pSMB->ByteCount = 0; +- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, +- (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); + if (rc) { + cERROR(1, ("Send error in FindClose = %d", rc)); + } + cifs_stats_inc(&tcon->num_fclose); +- cifs_small_buf_release(pSMB); + + /* Since session is dead, search handle closed on server already */ + if (rc == -EAGAIN) +@@ -4373,11 +4362,9 @@ CIFSSMBSetFileSize(const int xid, struct + __u16 fid, __u32 pid_of_opener, int SetAllocation) + { + struct smb_com_transaction2_sfi_req *pSMB = NULL; +- struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; + char *data_offset; + struct file_end_of_file_info *parm_data; + int rc = 0; +- int bytes_returned = 0; + __u16 params, param_offset, offset, byte_count, count; + + cFYI(1, ("SetFileSize (via SetFileInfo) %lld", +@@ -4387,8 +4374,6 @@ CIFSSMBSetFileSize(const int xid, struct + if (rc) + return rc; + +- pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB; +- + pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); + pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); + +@@ -4439,17 +4424,13 @@ CIFSSMBSetFileSize(const int xid, struct + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += byte_count; + pSMB->ByteCount = cpu_to_le16(byte_count); +- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, +- (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); + if (rc) { + cFYI(1, + ("Send error in SetFileInfo (SetFileSize) = %d", + rc)); + } + +- if (pSMB) +- cifs_small_buf_release(pSMB); +- + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + +@@ -4467,10 +4448,8 @@ CIFSSMBSetFileTimes(const int xid, struc + __u16 fid) + { + struct smb_com_transaction2_sfi_req *pSMB = NULL; +- struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; + char *data_offset; + int rc = 0; +- int bytes_returned = 0; + __u16 params, param_offset, offset, byte_count, count; + + cFYI(1, ("Set Times (via SetFileInfo)")); +@@ -4479,8 +4458,6 @@ CIFSSMBSetFileTimes(const int xid, struc + if (rc) + return rc; + +- pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB; +- + /* At this point there is no need to override the current pid + with the pid of the opener, but that could change if we someday + use an existing handle (rather than opening one on the fly) */ +@@ -4520,14 +4497,11 @@ CIFSSMBSetFileTimes(const int xid, struc + pSMB->hdr.smb_buf_length += byte_count; + pSMB->ByteCount = cpu_to_le16(byte_count); + memcpy(data_offset,data,sizeof(FILE_BASIC_INFO)); +- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, +- (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); + if (rc) { + cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc)); + } + +- cifs_small_buf_release(pSMB); +- + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + +@@ -4808,7 +4782,8 @@ int CIFSSMBNotify(const int xid, struct + pSMB->ByteCount = 0; + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, +- (struct smb_hdr *) pSMBr, &bytes_returned, -1); ++ (struct smb_hdr *)pSMBr, &bytes_returned, ++ CIFS_ASYNC_OP); + if (rc) { + cFYI(1, ("Error in Notify = %d", rc)); + } else { +diff -urpN linux-source-2.6.18.orig/fs/cifs/connect.c linux-source-2.6.18/fs/cifs/connect.c +--- linux-source-2.6.18.orig/fs/cifs/connect.c 2006-09-19 21:42:06.000000000 -0600 ++++ linux-source-2.6.18/fs/cifs/connect.c 2007-11-25 14:19:26.000000000 -0700 +@@ -2148,7 +2148,7 @@ CIFSSessSetup(unsigned int xid, struct c + pSMB->req_no_secext.ByteCount = cpu_to_le16(count); + + rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, +- &bytes_returned, 1); ++ &bytes_returned, CIFS_LONG_OP); + if (rc) { + /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */ + } else if ((smb_buffer_response->WordCount == 3) +@@ -2434,7 +2434,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned i + pSMB->req.ByteCount = cpu_to_le16(count); + + rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, +- &bytes_returned, 1); ++ &bytes_returned, CIFS_LONG_OP); + + if (smb_buffer_response->Status.CifsError == + cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED)) +@@ -2860,7 +2860,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xi + pSMB->req.ByteCount = cpu_to_le16(count); + + rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, +- &bytes_returned, 1); ++ &bytes_returned, CIFS_LONG_OP); + if (rc) { + /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ + } else if ((smb_buffer_response->WordCount == 3) +@@ -3131,7 +3131,8 @@ CIFSTCon(unsigned int xid, struct cifsSe + pSMB->hdr.smb_buf_length += count; + pSMB->ByteCount = cpu_to_le16(count); + +- rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0); ++ rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, ++ CIFS_STD_OP); + + /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */ + /* above now done in SendReceive */ +diff -urpN linux-source-2.6.18.orig/fs/cifs/file.c linux-source-2.6.18/fs/cifs/file.c +--- linux-source-2.6.18.orig/fs/cifs/file.c 2007-10-03 12:38:13.000000000 -0600 ++++ linux-source-2.6.18/fs/cifs/file.c 2007-11-25 14:20:52.000000000 -0700 +@@ -813,9 +813,9 @@ ssize_t cifs_user_write(struct file *fil + } + + if (*poffset > file->f_dentry->d_inode->i_size) +- long_op = 2; /* writes past end of file can take a long time */ ++ long_op = CIFS_VLONG_OP; /* writes past EOF take long time */ + else +- long_op = 1; ++ long_op = CIFS_LONG_OP; + + for (total_written = 0; write_size > total_written; + total_written += bytes_written) { +@@ -868,7 +868,7 @@ ssize_t cifs_user_write(struct file *fil + } + } else + *poffset += bytes_written; +- long_op = FALSE; /* subsequent writes fast - ++ long_op = CIFS_STD_OP; /* subsequent writes fast - + 15 seconds is plenty */ + } + +@@ -927,9 +927,9 @@ static ssize_t cifs_write(struct file *f + } + + if (*poffset > file->f_dentry->d_inode->i_size) +- long_op = 2; /* writes past end of file can take a long time */ ++ long_op = CIFS_VLONG_OP; /* writes past EOF can be slow */ + else +- long_op = 1; ++ long_op = CIFS_LONG_OP; + + for (total_written = 0; write_size > total_written; + total_written += bytes_written) { +@@ -1001,7 +1001,7 @@ static ssize_t cifs_write(struct file *f + } + } else + *poffset += bytes_written; +- long_op = FALSE; /* subsequent writes fast - ++ long_op = CIFS_STD_OP; /* subsequent writes fast - + 15 seconds is plenty */ + } + +@@ -1288,7 +1288,7 @@ retry: + open_file->netfid, + bytes_to_write, offset, + &bytes_written, iov, n_iov, +- 1); ++ CIFS_LONG_OP); + atomic_dec(&open_file->wrtPending); + if (rc || bytes_written < bytes_to_write) { + cERROR(1,("Write2 ret %d, written = %d", +diff -urpN linux-source-2.6.18.orig/fs/cifs/sess.c linux-source-2.6.18/fs/cifs/sess.c +--- linux-source-2.6.18.orig/fs/cifs/sess.c 2007-11-25 14:17:16.000000000 -0700 ++++ linux-source-2.6.18/fs/cifs/sess.c 2007-11-25 14:19:26.000000000 -0700 +@@ -483,7 +483,7 @@ CIFS_SessSetup(unsigned int xid, struct + iov[1].iov_base = str_area; + iov[1].iov_len = count; + rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, +- 0 /* not long op */, 1 /* log NT STATUS if any */ ); ++ CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR); + /* SMB request buf freed in SendReceive2 */ + + cFYI(1,("ssetup rc from sendrecv2 is %d",rc)); +diff -urpN linux-source-2.6.18.orig/fs/cifs/transport.c linux-source-2.6.18/fs/cifs/transport.c +--- linux-source-2.6.18.orig/fs/cifs/transport.c 2007-11-25 14:18:15.000000000 -0700 ++++ linux-source-2.6.18/fs/cifs/transport.c 2007-11-25 14:30:14.000000000 -0700 +@@ -308,7 +308,7 @@ smb_send2(struct socket *ssocket, struct + + static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) + { +- if(long_op == -1) { ++ if (long_op == CIFS_ASYNC_OP) { + /* oplock breaks must not be held up */ + atomic_inc(&ses->server->inFlight); + } else { +@@ -337,7 +337,7 @@ static int wait_for_free_request(struct + they are allowed to block on server */ + + /* update # of requests on the wire to server */ +- if (long_op < 3) ++ if (long_op != CIFS_BLOCKING_OP) + atomic_inc(&ses->server->inFlight); + spin_unlock(&GlobalMid_Lock); + break; +@@ -416,17 +416,48 @@ static int wait_for_response(struct cifs + } + } + ++ ++/* ++ * ++ * Send an SMB Request. No response info (other than return code) ++ * needs to be parsed. ++ * ++ * flags indicate the type of request buffer and how long to wait ++ * and whether to log NT STATUS code (error) before mapping it to POSIX error ++ * ++ */ ++int ++SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses, ++ struct smb_hdr *in_buf, int flags) ++{ ++ int rc; ++ struct kvec iov[1]; ++ int resp_buf_type; ++ ++ iov[0].iov_base = (char *)in_buf; ++ iov[0].iov_len = in_buf->smb_buf_length + 4; ++ flags |= CIFS_NO_RESP; ++ rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags); ++#ifdef CONFIG_CIFS_DEBUG2 ++ cFYI(1, ("SendRcvNoR flags %d rc %d", flags, rc)); ++#endif ++ return rc; ++} ++ + int + SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, + struct kvec *iov, int n_vec, int * pRespBufType /* ret */, +- const int long_op, const int logError) ++ const int flags) + { + int rc = 0; ++ int long_op; + unsigned int receive_len; + unsigned long timeout; + struct mid_q_entry *midQ; + struct smb_hdr *in_buf = iov[0].iov_base; + ++ long_op = flags & CIFS_TIMEOUT_MASK; ++ + *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */ + + if ((ses == NULL) || (ses->server == NULL)) { +@@ -484,15 +515,22 @@ SendReceive2(const unsigned int xid, str + if(rc < 0) + goto out; + +- if (long_op == -1) +- goto out; +- else if (long_op == 2) /* writes past end of file can take loong time */ ++ if (long_op == CIFS_STD_OP) ++ timeout = 15 * HZ; ++ else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */ + timeout = 180 * HZ; +- else if (long_op == 1) ++ else if (long_op == CIFS_LONG_OP) + timeout = 45 * HZ; /* should be greater than + servers oplock break timeout (about 43 seconds) */ +- else +- timeout = 15 * HZ; ++ else if (long_op == CIFS_ASYNC_OP) ++ goto out; ++ else if (long_op == CIFS_BLOCKING_OP) ++ timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */ ++ else { ++ cERROR(1, ("unknown timeout flag %d", long_op)); ++ rc = -EIO; ++ goto out; ++ } + + /* wait for 15 seconds or until woken up due to response arriving or + due to last connection to this server being unmounted */ +@@ -567,7 +605,8 @@ SendReceive2(const unsigned int xid, str + } + + /* BB special case reconnect tid and uid here? */ +- rc = map_smb_to_linux_error(midQ->resp_buf, logError); ++ rc = map_smb_to_linux_error(midQ->resp_buf, ++ flags & CIFS_LOG_ERROR); + + /* convert ByteCount if necessary */ + if (receive_len >= +@@ -576,8 +615,10 @@ SendReceive2(const unsigned int xid, str + (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) + BCC(midQ->resp_buf) = + le16_to_cpu(BCC_LE(midQ->resp_buf)); +- midQ->resp_buf = NULL; /* mark it so will not be freed +- by DeleteMidQEntry */ ++ if ((flags & CIFS_NO_RESP) == 0) ++ midQ->resp_buf = NULL; /* mark it so buf will ++ not be freed by ++ DeleteMidQEntry */ + } else { + rc = -EIO; + cFYI(1,("Bad MID state?")); +@@ -666,17 +707,25 @@ SendReceive(const unsigned int xid, stru + if(rc < 0) + goto out; + +- if (long_op == -1) ++ if (long_op == CIFS_STD_OP) ++ timeout = 15 * HZ; ++ /* wait for 15 seconds or until woken up due to response arriving or ++ due to last connection to this server being unmounted */ ++ else if (long_op == CIFS_ASYNC_OP) + goto out; +- else if (long_op == 2) /* writes past end of file can take loong time */ ++ else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */ + timeout = 180 * HZ; +- else if (long_op == 1) ++ else if (long_op == CIFS_LONG_OP) + timeout = 45 * HZ; /* should be greater than + servers oplock break timeout (about 43 seconds) */ +- else +- timeout = 15 * HZ; +- /* wait for 15 seconds or until woken up due to response arriving or +- due to last connection to this server being unmounted */ ++ else if (long_op == CIFS_BLOCKING_OP) ++ timeout = 0x7FFFFFFF; /* large but no so large as to wrap */ ++ else { ++ cERROR(1, ("unknown timeout flag %d", long_op)); ++ rc = -EIO; ++ goto out; ++ } ++ + if (signal_pending(current)) { + /* if signal pending do not hold up user for full smb timeout + but we still give response a change to complete */ +@@ -817,7 +866,7 @@ send_lock_cancel(const unsigned int xid, + pSMB->hdr.Mid = GetNextMid(ses->server); + + return SendReceive(xid, ses, in_buf, out_buf, +- &bytes_returned, 0); ++ &bytes_returned, CIFS_STD_OP); + } + + int +@@ -849,7 +898,7 @@ SendReceiveBlockingLock(const unsigned i + to the same server. We may make this configurable later or + use ses->maxReq */ + +- rc = wait_for_free_request(ses, 3); ++ rc = wait_for_free_request(ses, CIFS_BLOCKING_OP); + if (rc) + return rc; + diff --git a/trunk/2.6.18/30046_wait_task_stopped-hang.patch b/trunk/2.6.18/30046_wait_task_stopped-hang.patch new file mode 100644 index 0000000..de602c4 --- /dev/null +++ b/trunk/2.6.18/30046_wait_task_stopped-hang.patch @@ -0,0 +1,38 @@ +From: Roland McGrath <roland@redhat.com> +Date: Wed, 14 Nov 2007 06:11:50 +0000 (-0800) +Subject: wait_task_stopped: Check p->exit_state instead of TASK_TRACED +X-Git-Tag: v2.6.24-rc3~12 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=a3474224e6a01924be40a8255636ea5522c1023a + +wait_task_stopped: Check p->exit_state instead of TASK_TRACED + +The original meaning of the old test (p->state > TASK_STOPPED) was +"not dead", since it was before TASK_TRACED existed and before the +state/exit_state split. It was a wrong correction in commit +14bf01bb0599c89fc7f426d20353b76e12555308 to make this test for +TASK_TRACED instead. It should have been changed when TASK_TRACED +was introducted and again when exit_state was introduced. + +Signed-off-by: Roland McGrath <roland@redhat.com> +Cc: Oleg Nesterov <oleg@tv-sign.ru> +Cc: Alexey Dobriyan <adobriyan@sw.ru> +Cc: Kees Cook <kees@ubuntu.com> +Acked-by: Scott James Remnant <scott@ubuntu.com> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +--- + +Adjusted to apply to Debian's 2.6.18 by dann frazier <dannf@debian.org> + +diff -urpN linux-source-2.6.18.orig/kernel/exit.c linux-source-2.6.18/kernel/exit.c +--- linux-source-2.6.18.orig/kernel/exit.c 2006-09-19 21:42:06.000000000 -0600 ++++ linux-source-2.6.18/kernel/exit.c 2007-11-25 13:39:32.000000000 -0700 +@@ -1287,8 +1287,7 @@ static int wait_task_stopped(struct task + int why = (p->ptrace & PT_PTRACED) ? CLD_TRAPPED : CLD_STOPPED; + + exit_code = p->exit_code; +- if (unlikely(!exit_code) || +- unlikely(p->state & TASK_TRACED)) ++ if (unlikely(!exit_code) || unlikely(p->exit_state)) + goto bail_ref; + return wait_noreap_copyout(p, pid, uid, + why, (exit_code << 8) | 0x7f, diff --git a/trunk/2.6.18/30047_ieee80211-underflow.patch b/trunk/2.6.18/30047_ieee80211-underflow.patch new file mode 100644 index 0000000..53c733a --- /dev/null +++ b/trunk/2.6.18/30047_ieee80211-underflow.patch @@ -0,0 +1,54 @@ +From: John W. Linville <linville@tuxdriver.com> +Date: Tue, 2 Oct 2007 04:03:54 +0000 (-0700) +Subject: [IEEE80211]: avoid integer underflow for runt rx frames +X-Git-Tag: kvm-47~34^2~42^2 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Favi%2Fkvm.git;a=commitdiff_plain;h=04045f98e0457aba7d4e6736f37eed189c48a5f7 + +[IEEE80211]: avoid integer underflow for runt rx frames + +Reported by Chris Evans <scarybeasts@gmail.com>: + +> The summary is that an evil 80211 frame can crash out a victim's +> machine. It only applies to drivers using the 80211 wireless code, and +> only then to certain drivers (and even then depends on a card's +> firmware not dropping a dubious packet). I must confess I'm not +> keeping track of Linux wireless support, and the different protocol +> stacks etc. +> +> Details are as follows: +> +> ieee80211_rx() does not explicitly check that "skb->len >= hdrlen". +> There are other skb->len checks, but not enough to prevent a subtle +> off-by-two error if the frame has the IEEE80211_STYPE_QOS_DATA flag +> set. +> +> This leads to integer underflow and crash here: +> +> if (frag != 0) +> flen -= hdrlen; +> +> (flen is subsequently used as a memcpy length parameter). + +How about this? + +Signed-off-by: John W. Linville <linville@tuxdriver.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +--- + +diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c +index f2de2e4..6284c99 100644 +--- a/net/ieee80211/ieee80211_rx.c ++++ b/net/ieee80211/ieee80211_rx.c +@@ -366,6 +366,12 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, + frag = WLAN_GET_SEQ_FRAG(sc); + hdrlen = ieee80211_get_hdrlen(fc); + ++ if (skb->len < hdrlen) { ++ printk(KERN_INFO "%s: invalid SKB length %d\n", ++ dev->name, skb->len); ++ goto rx_dropped; ++ } ++ + /* Put this code here so that we avoid duplicating it in all + * Rx paths. - Jean II */ + #ifdef CONFIG_WIRELESS_EXT diff --git a/trunk/2.6.18/30048_sysfs_readdir-NULL-deref-1.patch b/trunk/2.6.18/30048_sysfs_readdir-NULL-deref-1.patch new file mode 100644 index 0000000..c13fd1b --- /dev/null +++ b/trunk/2.6.18/30048_sysfs_readdir-NULL-deref-1.patch @@ -0,0 +1,112 @@ +From: Eric Sandeen <sandeen@sandeen.net> +Date: Mon, 11 Jun 2007 05:02:45 +0000 (+0900) +Subject: sysfs: store sysfs inode nrs in s_ino to avoid readdir oopses +X-Git-Tag: v2.6.22-rc5~47 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fstable%2Flinux-2.6.22.y.git;a=commitdiff_plain;h=dc351252b33f8fede396d6173dba117bcb933607 + +sysfs: store sysfs inode nrs in s_ino to avoid readdir oopses + +Backport of +ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.22-rc1/2.6.22-rc1-mm1/broken-out/gregkh-driver-sysfs-allocate-inode-number-using-ida.patch + +For regular files in sysfs, sysfs_readdir wants to traverse +sysfs_dirent->s_dentry->d_inode->i_ino to get to the inode number. +But, the dentry can be reclaimed under memory pressure, and there is +no synchronization with readdir. This patch follows Tejun's scheme of +allocating and storing an inode number in the new s_ino member of a +sysfs_dirent, when dirents are created, and retrieving it from there +for readdir, so that the pointer chain doesn't have to be traversed. + +Tejun's upstream patch uses a new-ish "ida" allocator which brings +along some extra complexity; this -stable patch has a brain-dead +incrementing counter which does not guarantee uniqueness, but because +sysfs doesn't hash inodes as iunique expects, uniqueness wasn't +guaranteed today anyway. + +Signed-off-by: Eric Sandeen <sandeen@redhat.com> +Signed-off-by: Tejun Heo <htejun@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + +Backported to Debian's 2.6.18 by dann frazier <dannf@hp.com> + +diff -urpN linux-source-2.6.18.orig/fs/sysfs/dir.c linux-source-2.6.18/fs/sysfs/dir.c +--- linux-source-2.6.18.orig/fs/sysfs/dir.c 2006-09-19 21:42:06.000000000 -0600 ++++ linux-source-2.6.18/fs/sysfs/dir.c 2007-11-07 15:31:11.000000000 -0700 +@@ -29,6 +29,14 @@ static struct dentry_operations sysfs_de + .d_iput = sysfs_d_iput, + }; + ++static unsigned int sysfs_inode_counter; ++ino_t sysfs_get_inum(void) ++{ ++ if (unlikely(sysfs_inode_counter < 3)) ++ sysfs_inode_counter = 3; ++ return sysfs_inode_counter++; ++} ++ + /* + * Allocates a new sysfs_dirent and links it to the parent sysfs_dirent + */ +@@ -42,6 +50,7 @@ static struct sysfs_dirent * sysfs_new_d + return NULL; + + memset(sd, 0, sizeof(*sd)); ++ sd->s_ino = sysfs_get_inum(); + atomic_set(&sd->s_count, 1); + atomic_set(&sd->s_event, 0); + INIT_LIST_HEAD(&sd->s_children); +@@ -416,7 +425,7 @@ static int sysfs_readdir(struct file * f + + switch (i) { + case 0: +- ino = dentry->d_inode->i_ino; ++ ino = parent_sd->s_ino; + if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) + break; + filp->f_pos++; +@@ -445,10 +454,7 @@ static int sysfs_readdir(struct file * f + + name = sysfs_get_name(next); + len = strlen(name); +- if (next->s_dentry) +- ino = next->s_dentry->d_inode->i_ino; +- else +- ino = iunique(sysfs_sb, 2); ++ ino = next->s_ino; + + if (filldir(dirent, name, len, filp->f_pos, ino, + dt_type(next)) < 0) +diff -urpN linux-source-2.6.18.orig/fs/sysfs/inode.c linux-source-2.6.18/fs/sysfs/inode.c +--- linux-source-2.6.18.orig/fs/sysfs/inode.c 2006-09-19 21:42:06.000000000 -0600 ++++ linux-source-2.6.18/fs/sysfs/inode.c 2007-11-07 15:30:13.000000000 -0700 +@@ -129,6 +129,7 @@ struct inode * sysfs_new_inode(mode_t mo + inode->i_mapping->a_ops = &sysfs_aops; + inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; + inode->i_op = &sysfs_inode_operations; ++ inode->i_ino = sd->s_ino; + lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key); + + if (sd->s_iattr) { +diff -urpN linux-source-2.6.18.orig/fs/sysfs/mount.c linux-source-2.6.18/fs/sysfs/mount.c +--- linux-source-2.6.18.orig/fs/sysfs/mount.c 2006-09-19 21:42:06.000000000 -0600 ++++ linux-source-2.6.18/fs/sysfs/mount.c 2007-11-07 15:30:13.000000000 -0700 +@@ -29,6 +29,7 @@ static struct sysfs_dirent sysfs_root = + .s_element = NULL, + .s_type = SYSFS_ROOT, + .s_iattr = NULL, ++ .s_ino = 1, + }; + + static int sysfs_fill_super(struct super_block *sb, void *data, int silent) +diff -urpN linux-source-2.6.18.orig/include/linux/sysfs.h linux-source-2.6.18/include/linux/sysfs.h +--- linux-source-2.6.18.orig/include/linux/sysfs.h 2006-09-19 21:42:06.000000000 -0600 ++++ linux-source-2.6.18/include/linux/sysfs.h 2007-11-07 15:34:16.000000000 -0700 +@@ -72,6 +72,7 @@ struct sysfs_dirent { + void * s_element; + int s_type; + umode_t s_mode; ++ ino_t s_ino; + struct dentry * s_dentry; + struct iattr * s_iattr; + atomic_t s_event; diff --git a/trunk/2.6.18/30049_sysfs_readdir-NULL-deref-2.patch b/trunk/2.6.18/30049_sysfs_readdir-NULL-deref-2.patch new file mode 100644 index 0000000..e242c17 --- /dev/null +++ b/trunk/2.6.18/30049_sysfs_readdir-NULL-deref-2.patch @@ -0,0 +1,128 @@ +From: Tejun Heo <htejun@gmail.com> +Date: Mon, 11 Jun 2007 05:04:01 +0000 (+0900) +Subject: sysfs: fix race condition around sd->s_dentry, take#2 +X-Git-Tag: v2.6.22-rc5~45 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fstable%2Flinux-2.6.22.y.git;a=commitdiff_plain;h=dd14cbc994709a1c5a64ed3621f583c49a27e521 + +sysfs: fix race condition around sd->s_dentry, take#2 + +Allowing attribute and symlink dentries to be reclaimed means +sd->s_dentry can change dynamically. However, updates to the field +are unsynchronized leading to race conditions. This patch adds +sysfs_lock and use it to synchronize updates to sd->s_dentry. + +Due to the locking around ->d_iput, the check in sysfs_drop_dentry() +is complex. sysfs_lock only protect sd->s_dentry pointer itself. The +validity of the dentry is protected by dcache_lock, so whether dentry +is alive or not can only be tested while holding both locks. + +This is minimal backport of sysfs_drop_dentry() rewrite in devel +branch. + +Signed-off-by: Tejun Heo <htejun@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + +Backported to Debian's 2.6.18 by dann frazier <dannf@hp.com> + +diff -urpN linux-source-2.6.18.orig/fs/sysfs/dir.c linux-source-2.6.18/fs/sysfs/dir.c +--- linux-source-2.6.18.orig/fs/sysfs/dir.c 2007-11-07 15:44:57.000000000 -0700 ++++ linux-source-2.6.18/fs/sysfs/dir.c 2007-11-07 15:38:57.000000000 -0700 +@@ -12,14 +12,26 @@ + #include "sysfs.h" + + DECLARE_RWSEM(sysfs_rename_sem); ++spinlock_t sysfs_lock = SPIN_LOCK_UNLOCKED; + + static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) + { + struct sysfs_dirent * sd = dentry->d_fsdata; + + if (sd) { +- BUG_ON(sd->s_dentry != dentry); +- sd->s_dentry = NULL; ++ /* sd->s_dentry is protected with sysfs_lock. This ++ * allows sysfs_drop_dentry() to dereference it. ++ */ ++ spin_lock(&sysfs_lock); ++ ++ /* The dentry might have been deleted or another ++ * lookup could have happened updating sd->s_dentry to ++ * point the new dentry. Ignore if it isn't pointing ++ * to this dentry. ++ */ ++ if (sd->s_dentry == dentry) ++ sd->s_dentry = NULL; ++ spin_unlock(&sysfs_lock); + sysfs_put(sd); + } + iput(inode); +@@ -218,7 +230,10 @@ static int sysfs_attach_attr(struct sysf + } + + dentry->d_fsdata = sysfs_get(sd); ++ /* protect sd->s_dentry against sysfs_d_iput */ ++ spin_lock(&sysfs_lock); + sd->s_dentry = dentry; ++ spin_unlock(&sysfs_lock); + error = sysfs_create(dentry, (attr->mode & S_IALLUGO) | S_IFREG, init); + if (error) { + sysfs_put(sd); +@@ -240,7 +255,10 @@ static int sysfs_attach_link(struct sysf + int err = 0; + + dentry->d_fsdata = sysfs_get(sd); ++ /* protect sd->s_dentry against sysfs_d_iput */ ++ spin_lock(&sysfs_lock); + sd->s_dentry = dentry; ++ spin_unlock(&sysfs_lock); + err = sysfs_create(dentry, S_IFLNK|S_IRWXUGO, init_symlink); + if (!err) { + dentry->d_op = &sysfs_dentry_ops; +diff -urpN linux-source-2.6.18.orig/fs/sysfs/inode.c linux-source-2.6.18/fs/sysfs/inode.c +--- linux-source-2.6.18.orig/fs/sysfs/inode.c 2007-11-07 15:44:57.000000000 -0700 ++++ linux-source-2.6.18/fs/sysfs/inode.c 2007-11-07 15:40:19.000000000 -0700 +@@ -217,8 +217,22 @@ const unsigned char * sysfs_get_name(str + */ + void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent) + { +- struct dentry * dentry = sd->s_dentry; ++ struct dentry *dentry = NULL; + ++ /* We're not holding a reference to ->s_dentry dentry but the ++ * field will stay valid as long as sysfs_lock is held. ++ */ ++ spin_lock(&sysfs_lock); ++ spin_lock(&dcache_lock); ++ ++ /* dget dentry if it's still alive */ ++ if (sd->s_dentry && sd->s_dentry->d_inode) ++ dentry = dget_locked(sd->s_dentry); ++ ++ spin_unlock(&dcache_lock); ++ spin_unlock(&sysfs_lock); ++ ++ /* drop dentry */ + if (dentry) { + spin_lock(&dcache_lock); + spin_lock(&dentry->d_lock); +@@ -232,6 +246,8 @@ void sysfs_drop_dentry(struct sysfs_dire + spin_unlock(&dentry->d_lock); + spin_unlock(&dcache_lock); + } ++ ++ dput(dentry); + } + } + +diff -urpN linux-source-2.6.18.orig/fs/sysfs/sysfs.h linux-source-2.6.18/fs/sysfs/sysfs.h +--- linux-source-2.6.18.orig/fs/sysfs/sysfs.h 2006-09-19 21:42:06.000000000 -0600 ++++ linux-source-2.6.18/fs/sysfs/sysfs.h 2007-11-07 15:38:57.000000000 -0700 +@@ -20,6 +20,7 @@ extern const unsigned char * sysfs_get_n + extern void sysfs_drop_dentry(struct sysfs_dirent *sd, struct dentry *parent); + extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); + ++extern spinlock_t sysfs_lock; + extern struct rw_semaphore sysfs_rename_sem; + extern struct super_block * sysfs_sb; + extern const struct file_operations sysfs_dir_operations; diff --git a/trunk/2.6.18/30050_sysfs-fix-condition-check.patch b/trunk/2.6.18/30050_sysfs-fix-condition-check.patch new file mode 100644 index 0000000..652065e --- /dev/null +++ b/trunk/2.6.18/30050_sysfs-fix-condition-check.patch @@ -0,0 +1,29 @@ +From: Tejun Heo <htejun@gmail.com> +Date: Mon, 11 Jun 2007 05:03:27 +0000 (+0900) +Subject: sysfs: fix condition check in sysfs_drop_dentry() +X-Git-Tag: v2.6.22-rc5~46 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=6aa054aadfea613a437ad0b15d38eca2b963fc0a + +sysfs: fix condition check in sysfs_drop_dentry() + +The condition check doesn't make much sense as it basically always +succeeds. This causes NULL dereferencing on certain cases. It seems +that parentheses are put in the wrong place. Fix it. + +Signed-off-by: Tejun Heo <htejun@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + +Adjusted to apply to Debian's 2.6.18 by dann frazier <dannf@hp.com> + +--- linux-source-2.6.18+2.6.22.y/fs/sysfs/inode.c.orig 2007-11-07 15:40:19.000000000 -0700 ++++ linux-source-2.6.18+2.6.22.y/fs/sysfs/inode.c 2007-11-07 17:09:33.000000000 -0700 +@@ -236,7 +236,7 @@ void sysfs_drop_dentry(struct sysfs_dire + if (dentry) { + spin_lock(&dcache_lock); + spin_lock(&dentry->d_lock); +- if (!(d_unhashed(dentry) && dentry->d_inode)) { ++ if (!d_unhashed(dentry) && dentry->d_inode) { + dget_locked(dentry); + __d_drop(dentry); + spin_unlock(&dentry->d_lock); diff --git a/trunk/2.6.18/30051_tmpfs-restore-clear_highpage.patch b/trunk/2.6.18/30051_tmpfs-restore-clear_highpage.patch new file mode 100644 index 0000000..c4ed61c --- /dev/null +++ b/trunk/2.6.18/30051_tmpfs-restore-clear_highpage.patch @@ -0,0 +1,44 @@ +commit e84e2e132c9c66d8498e7710d4ea532d1feaaac5 +Author: Hugh Dickins <hugh@veritas.com> +Date: Wed Nov 28 18:55:10 2007 +0000 + + tmpfs: restore missing clear_highpage + + tmpfs was misconverted to __GFP_ZERO in 2.6.11. There's an unusual case in + which shmem_getpage receives the page from its caller instead of allocating. + We must cover this case by clear_highpage before SetPageUptodate, as before. + + Signed-off-by: Hugh Dickins <hugh@veritas.com> + Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> + +Adjusted to apply to Debian's 2.6.18 by dann frazier <dannf@hp.com> + +diff -urpN linux-source-2.6.18.orig/mm/shmem.c linux-source-2.6.18/mm/shmem.c +--- linux-source-2.6.18.orig/mm/shmem.c 2007-12-01 15:24:42.000000000 -0700 ++++ linux-source-2.6.18/mm/shmem.c 2007-12-17 18:24:57.000000000 -0700 +@@ -972,7 +972,7 @@ shmem_alloc_page(gfp_t gfp, struct shmem + pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, idx); + pvma.vm_pgoff = idx; + pvma.vm_end = PAGE_SIZE; +- page = alloc_page_vma(gfp | __GFP_ZERO, &pvma, 0); ++ page = alloc_page_vma(gfp, &pvma, 0); + mpol_free(pvma.vm_policy); + return page; + } +@@ -992,7 +992,7 @@ shmem_swapin(struct shmem_inode_info *in + static inline struct page * + shmem_alloc_page(gfp_t gfp,struct shmem_inode_info *info, unsigned long idx) + { +- return alloc_page(gfp | __GFP_ZERO); ++ return alloc_page(gfp); + } + #endif + +@@ -1201,6 +1201,7 @@ repeat: + + info->alloced++; + spin_unlock(&info->lock); ++ clear_highpage(filepage); + flush_dcache_page(filepage); + SetPageUptodate(filepage); + } diff --git a/trunk/2.6.18/30052_minixfs-printk-hang.patch b/trunk/2.6.18/30052_minixfs-printk-hang.patch new file mode 100644 index 0000000..b7b205b --- /dev/null +++ b/trunk/2.6.18/30052_minixfs-printk-hang.patch @@ -0,0 +1,76 @@ +From: Eric Sandeen <sandeen@redhat.com> +Date: Wed, 17 Oct 2007 06:27:15 +0000 (-0700) +Subject: minixfs: limit minixfs printks on corrupted dir i_size (CVE-2006-6058) +X-Git-Tag: v2.6.23.7~3 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fstable%2Flinux-2.6.23.y.git;a=commitdiff_plain;h=f0ae3188daf70ed07a4dfbeb133bef3a92838a15 + +minixfs: limit minixfs printks on corrupted dir i_size (CVE-2006-6058) + +patch f44ec6f3f89889a469773b1fd894f8fcc07c29cf upstream. + +This attempts to address CVE-2006-6058 +http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2006-6058 + +first reported at http://projects.info-pull.com/mokb/MOKB-17-11-2006.html + +Essentially a corrupted minix dir inode reporting a very large +i_size will loop for a very long time in minix_readdir, minix_find_entry, +etc, because on EIO they just move on to try the next page. This is +under the BKL, printk-storming as well. This can lock up the machine +for a very long time. Simply ratelimiting the printks gets things back +under control. Make the message a bit more informative while we're here. + +Signed-off-by: Eric Sandeen <sandeen@redhat.com> +Cc: Bodo Eggert <7eggert@gmx.de> +Signed-off-by: Andrew Morton <akpm@linux-foundation.org> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + +Backported to Debian's 2.6.18 by dann frazier <dannf@debian.org> + +diff -urpN linux-source-2.6.18.orig/fs/minix/itree_v1.c linux-source-2.6.18/fs/minix/itree_v1.c +--- linux-source-2.6.18.orig/fs/minix/itree_v1.c 2006-09-19 21:42:06.000000000 -0600 ++++ linux-source-2.6.18/fs/minix/itree_v1.c 2007-12-16 19:13:41.000000000 -0700 +@@ -23,11 +23,16 @@ static inline block_t *i_data(struct ino + static int block_to_path(struct inode * inode, long block, int offsets[DEPTH]) + { + int n = 0; ++ char b[BDEVNAME_SIZE]; + + if (block < 0) { +- printk("minix_bmap: block<0\n"); ++ printk("MINIX-fs: block_to_path: block %ld < 0 on dev %s\n", ++ block, bdevname(inode->i_sb->s_bdev, b)); + } else if (block >= (minix_sb(inode->i_sb)->s_max_size/BLOCK_SIZE)) { +- printk("minix_bmap: block>big\n"); ++ if (printk_ratelimit()) ++ printk("MINIX-fs: block_to_path: " ++ "block %ld too big on dev %s\n", ++ block, bdevname(inode->i_sb->s_bdev, b)); + } else if (block < 7) { + offsets[n++] = block; + } else if ((block -= 7) < 512) { +diff -urpN linux-source-2.6.18.orig/fs/minix/itree_v2.c linux-source-2.6.18/fs/minix/itree_v2.c +--- linux-source-2.6.18.orig/fs/minix/itree_v2.c 2006-09-19 21:42:06.000000000 -0600 ++++ linux-source-2.6.18/fs/minix/itree_v2.c 2007-12-16 19:40:06.000000000 -0700 +@@ -23,11 +23,17 @@ static inline block_t *i_data(struct ino + static int block_to_path(struct inode * inode, long block, int offsets[DEPTH]) + { + int n = 0; ++ char b[BDEVNAME_SIZE]; ++ struct super_block *sb = inode->i_sb; + + if (block < 0) { +- printk("minix_bmap: block<0\n"); ++ printk("MINIX-fs: block_to_path: block %ld < 0 on dev %s\n", ++ block, bdevname(sb->s_bdev, b)); + } else if (block >= (minix_sb(inode->i_sb)->s_max_size/BLOCK_SIZE)) { +- printk("minix_bmap: block>big\n"); ++ if (printk_ratelimit()) ++ printk("MINIX-fs: block_to_path: " ++ "block %ld too big on dev %s\n", ++ block, bdevname(sb->s_bdev, b)); + } else if (block < 7) { + offsets[n++] = block; + } else if ((block -= 7) < 256) { diff --git a/trunk/2.6.18/30053_hrtimer-large-relative-timeouts-overflow.patch b/trunk/2.6.18/30053_hrtimer-large-relative-timeouts-overflow.patch new file mode 100644 index 0000000..57c2b94 --- /dev/null +++ b/trunk/2.6.18/30053_hrtimer-large-relative-timeouts-overflow.patch @@ -0,0 +1,45 @@ +From: Thomas Gleixner <tglx@linutronix.de> +Date: Fri, 7 Dec 2007 18:16:17 +0000 (+0100) +Subject: hrtimers: avoid overflow for large relative timeouts +X-Git-Tag: v2.6.24-rc5~49^2~2 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=62f0f61e6673e67151a7c8c0f9a09c7ea43fe2b5;hp=f194d132e4971111f85c18c96067acffb13cee6d + +hrtimers: avoid overflow for large relative timeouts + +Relative hrtimers with a large timeout value might end up as negative +timer values, when the current time is added in hrtimer_start(). + +This in turn is causing the clockevents_set_next() function to set an +huge timeout and sleep for quite a long time when we have a clock +source which is capable of long sleeps like HPET. With PIT this almost +goes unnoticed as the maximum delta is ~27ms. The non-hrt/nohz code +sorts this out in the next timer interrupt, so we never noticed that +problem which has been there since the first day of hrtimers. + +This bug became more apparent in 2.6.24 which activates HPET on more +hardware. + +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +Signed-off-by: Ingo Molnar <mingo@elte.hu> +--- + +Adjusted to apply to Debian's 2.6.18 by dann frazier <dannf@debian.org> + +diff -urpN linux-source-2.6.18.orig/kernel/hrtimer.c linux-source-2.6.18/kernel/hrtimer.c +--- linux-source-2.6.18.orig/kernel/hrtimer.c 2006-09-19 21:42:06.000000000 -0600 ++++ linux-source-2.6.18/kernel/hrtimer.c 2007-12-16 18:43:03.000000000 -0700 +@@ -443,6 +443,14 @@ hrtimer_start(struct hrtimer *timer, kti + #ifdef CONFIG_TIME_LOW_RES + tim = ktime_add(tim, base->resolution); + #endif ++ /* ++ * Careful here: User space might have asked for a ++ * very long sleep, so the add above might result in a ++ * negative number, which enqueues the timer in front ++ * of the queue. ++ */ ++ if (tim.tv64 < 0) ++ tim.tv64 = KTIME_MAX; + } + timer->expires = tim; + diff --git a/trunk/2.6.18/30054_coredump-only-to-same-uid.patch b/trunk/2.6.18/30054_coredump-only-to-same-uid.patch new file mode 100644 index 0000000..74af052 --- /dev/null +++ b/trunk/2.6.18/30054_coredump-only-to-same-uid.patch @@ -0,0 +1,38 @@ +From: Ingo Molnar <mingo@elte.hu> +Date: Wed, 28 Nov 2007 12:59:18 +0000 (+0100) +Subject: vfs: coredumping fix +X-Git-Tag: v2.6.24-rc4~82 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=c46f739dd39db3b07ab5deb4e3ec81e1c04a91af + +vfs: coredumping fix + +fix: http://bugzilla.kernel.org/show_bug.cgi?id=3043 + +only allow coredumping to the same uid that the coredumping +task runs under. + +Signed-off-by: Ingo Molnar <mingo@elte.hu> +Acked-by: Alan Cox <alan@redhat.com> +Acked-by: Christoph Hellwig <hch@lst.de> +Acked-by: Al Viro <viro@ftp.linux.org.uk> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +--- + +Adjusted to apply to Debian's 2.6.18 by dann frazier <dannf@debian.org> + +diff -urpN linux-source-2.6.18.orig/fs/exec.c linux-source-2.6.18/fs/exec.c +--- linux-source-2.6.18.orig/fs/exec.c 2007-10-03 12:38:15.000000000 -0600 ++++ linux-source-2.6.18/fs/exec.c 2007-12-05 23:41:00.000000000 -0700 +@@ -1524,6 +1524,12 @@ int do_coredump(long signr, int exit_cod + + if (!S_ISREG(inode->i_mode)) + goto close_fail; ++ /* ++ * Dont allow local users get cute and trick others to coredump ++ * into their pre-created files: ++ */ ++ if (inode->i_uid != current->fsuid) ++ goto close_fail; + if (!file->f_op) + goto close_fail; + if (!file->f_op->write) diff --git a/trunk/2.6.18/30055_isdn-net-overflow.patch b/trunk/2.6.18/30055_isdn-net-overflow.patch new file mode 100644 index 0000000..9ea5f60 --- /dev/null +++ b/trunk/2.6.18/30055_isdn-net-overflow.patch @@ -0,0 +1,54 @@ +From: Karsten Keil <kkeil@suse.de> +Date: Thu, 22 Nov 2007 11:43:13 +0000 (+0100) +Subject: isdn: avoid copying overly-long strings +X-Git-Tag: v2.6.24-rc4~110 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=0f13864e5b24d9cbe18d125d41bfa4b726a82e40 + +isdn: avoid copying overly-long strings + +Addresses http://bugzilla.kernel.org/show_bug.cgi?id=9416 + +Signed-off-by: Karsten Keil <kkeil@suse.de> +Signed-off-by: Andrew Morton <akpm@linux-foundation.org> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +--- + +diff -urpN linux-source-2.6.18.orig/drivers/isdn/i4l/isdn_net.c linux-source-2.6.18/drivers/isdn/i4l/isdn_net.c +--- linux-source-2.6.18.orig/drivers/isdn/i4l/isdn_net.c 2006-09-19 21:42:06.000000000 -0600 ++++ linux-source-2.6.18/drivers/isdn/i4l/isdn_net.c 2007-12-04 09:39:24.000000000 -0700 +@@ -2125,7 +2125,7 @@ isdn_net_find_icall(int di, int ch, int + u_long flags; + isdn_net_dev *p; + isdn_net_phone *n; +- char nr[32]; ++ char nr[ISDN_MSNLEN]; + char *my_eaz; + + /* Search name in netdev-chain */ +@@ -2134,7 +2134,7 @@ isdn_net_find_icall(int di, int ch, int + nr[1] = '\0'; + printk(KERN_INFO "isdn_net: Incoming call without OAD, assuming '0'\n"); + } else +- strcpy(nr, setup->phone); ++ strlcpy(nr, setup->phone, ISDN_MSNLEN); + si1 = (int) setup->si1; + si2 = (int) setup->si2; + if (!setup->eazmsn[0]) { +@@ -2803,7 +2803,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg + chidx = -1; + } + } +- strcpy(lp->msn, cfg->eaz); ++ strlcpy(lp->msn, cfg->eaz, sizeof(lp->msn)); + lp->pre_device = drvidx; + lp->pre_channel = chidx; + lp->onhtime = cfg->onhtime; +@@ -2952,7 +2952,7 @@ isdn_net_addphone(isdn_net_ioctl_phone * + if (p) { + if (!(n = (isdn_net_phone *) kmalloc(sizeof(isdn_net_phone), GFP_KERNEL))) + return -ENOMEM; +- strcpy(n->num, phone->phone); ++ strlcpy(n->num, phone->phone, sizeof(n->num)); + n->next = p->local->phone[phone->outgoing & 1]; + p->local->phone[phone->outgoing & 1] = n; + return 0; diff --git a/trunk/2.6.18/30056_proc-snd-page-alloc-mem-leak.patch b/trunk/2.6.18/30056_proc-snd-page-alloc-mem-leak.patch new file mode 100644 index 0000000..f11dbcf --- /dev/null +++ b/trunk/2.6.18/30056_proc-snd-page-alloc-mem-leak.patch @@ -0,0 +1,169 @@ +From: Takashi Iwai <tiwai@suse.de> +Date: Mon, 17 Sep 2007 19:55:10 +0000 (+0200) +Subject: Convert snd-page-alloc proc file to use seq_file +X-Git-Tag: v2.6.23-rc8~3 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=ccec6e2c4a74adf76ed4e2478091a311b1806212;hp=7bae705ef2c2daac1993de03e5be93b5c300fc5e + +Convert snd-page-alloc proc file to use seq_file + +Use seq_file for the proc file read/write of snd-page-alloc module. +This automatically fixes bugs in the old proc code. + +Signed-off-by: Takashi Iwai <tiwai@suse.de> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +--- + +Backported to Debian's 2.6.18 by dann frazier <dannf@debian.org> + +diff -urpN linux-source-2.6.18.orig/sound/core/memalloc.c linux-source-2.6.18/sound/core/memalloc.c +--- linux-source-2.6.18.orig/sound/core/memalloc.c 2006-09-19 21:42:06.000000000 -0600 ++++ linux-source-2.6.18/sound/core/memalloc.c 2007-09-25 17:53:01.000000000 -0600 +@@ -27,6 +27,7 @@ + #include <linux/pci.h> + #include <linux/slab.h> + #include <linux/mm.h> ++#include <linux/seq_file.h> + #include <asm/uaccess.h> + #include <linux/dma-mapping.h> + #include <linux/moduleparam.h> +@@ -483,10 +484,8 @@ static void free_all_reserved_pages(void + #define SND_MEM_PROC_FILE "driver/snd-page-alloc" + static struct proc_dir_entry *snd_mem_proc; + +-static int snd_mem_proc_read(char *page, char **start, off_t off, +- int count, int *eof, void *data) ++static int snd_mem_proc_read(struct seq_file *seq, void *offset) + { +- int len = 0; + long pages = snd_allocated_pages >> (PAGE_SHIFT-12); + struct list_head *p; + struct snd_mem_list *mem; +@@ -494,44 +493,47 @@ static int snd_mem_proc_read(char *page, + static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" }; + + mutex_lock(&list_mutex); +- len += snprintf(page + len, count - len, +- "pages : %li bytes (%li pages per %likB)\n", +- pages * PAGE_SIZE, pages, PAGE_SIZE / 1024); ++ seq_printf(seq, "pages : %li bytes (%li pages per %likB)\n", ++ pages * PAGE_SIZE, pages, PAGE_SIZE / 1024); + devno = 0; + list_for_each(p, &mem_list_head) { + mem = list_entry(p, struct snd_mem_list, list); + devno++; +- len += snprintf(page + len, count - len, +- "buffer %d : ID %08x : type %s\n", +- devno, mem->id, types[mem->buffer.dev.type]); +- len += snprintf(page + len, count - len, +- " addr = 0x%lx, size = %d bytes\n", +- (unsigned long)mem->buffer.addr, (int)mem->buffer.bytes); ++ seq_printf(seq, "buffer %d : ID %08x : type %s\n", ++ devno, mem->id, types[mem->buffer.dev.type]); ++ seq_printf(seq, " addr = 0x%lx, size = %d bytes\n", ++ (unsigned long)mem->buffer.addr, ++ (int)mem->buffer.bytes); + } + mutex_unlock(&list_mutex); +- return len; ++ return 0; ++} ++ ++static int snd_mem_proc_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, snd_mem_proc_read, NULL); + } + + /* FIXME: for pci only - other bus? */ + #ifdef CONFIG_PCI + #define gettoken(bufp) strsep(bufp, " \t\n") + +-static int snd_mem_proc_write(struct file *file, const char __user *buffer, +- unsigned long count, void *data) ++static ssize_t snd_mem_proc_write(struct file *file, const char __user * buffer, ++ size_t count, loff_t * ppos) + { + char buf[128]; + char *token, *p; + +- if (count > ARRAY_SIZE(buf) - 1) +- count = ARRAY_SIZE(buf) - 1; ++ if (count > sizeof(buf) - 1) ++ return -EINVAL; + if (copy_from_user(buf, buffer, count)) + return -EFAULT; +- buf[ARRAY_SIZE(buf) - 1] = '\0'; ++ buf[count] = '\0'; + + p = buf; + token = gettoken(&p); + if (! token || *token == '#') +- return (int)count; ++ return count; + if (strcmp(token, "add") == 0) { + char *endp; + int vendor, device, size, buffers; +@@ -552,7 +554,7 @@ static int snd_mem_proc_write(struct fil + (buffers = simple_strtol(token, NULL, 0)) <= 0 || + buffers > 4) { + printk(KERN_ERR "snd-page-alloc: invalid proc write format\n"); +- return (int)count; ++ return count; + } + vendor &= 0xffff; + device &= 0xffff; +@@ -564,7 +566,7 @@ static int snd_mem_proc_write(struct fil + if (pci_set_dma_mask(pci, mask) < 0 || + pci_set_consistent_dma_mask(pci, mask) < 0) { + printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", mask, vendor, device); +- return (int)count; ++ return count; + } + } + for (i = 0; i < buffers; i++) { +@@ -574,7 +576,7 @@ static int snd_mem_proc_write(struct fil + size, &dmab) < 0) { + printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size); + pci_dev_put(pci); +- return (int)count; ++ return count; + } + snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci)); + } +@@ -600,9 +602,21 @@ static int snd_mem_proc_write(struct fil + free_all_reserved_pages(); + else + printk(KERN_ERR "snd-page-alloc: invalid proc cmd\n"); +- return (int)count; ++ return count; + } + #endif /* CONFIG_PCI */ ++ ++static const struct file_operations snd_mem_proc_fops = { ++ .owner = THIS_MODULE, ++ .open = snd_mem_proc_open, ++ .read = seq_read, ++#ifdef CONFIG_PCI ++ .write = snd_mem_proc_write, ++#endif ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ + #endif /* CONFIG_PROC_FS */ + + /* +@@ -613,12 +627,8 @@ static int __init snd_mem_init(void) + { + #ifdef CONFIG_PROC_FS + snd_mem_proc = create_proc_entry(SND_MEM_PROC_FILE, 0644, NULL); +- if (snd_mem_proc) { +- snd_mem_proc->read_proc = snd_mem_proc_read; +-#ifdef CONFIG_PCI +- snd_mem_proc->write_proc = snd_mem_proc_write; +-#endif +- } ++ if (snd_mem_proc) ++ snd_mem_proc->proc_fops = &snd_mem_proc_fops; + #endif + return 0; + } diff --git a/trunk/2.6.18/30057_fat-move-ioctl-compat-code.patch b/trunk/2.6.18/30057_fat-move-ioctl-compat-code.patch new file mode 100644 index 0000000..cde2538 --- /dev/null +++ b/trunk/2.6.18/30057_fat-move-ioctl-compat-code.patch @@ -0,0 +1,167 @@ +From: David Howells <dhowells@redhat.com> +Date: Thu, 31 Aug 2006 10:50:04 +0000 (+0200) +Subject: [PATCH] BLOCK: Move the msdos device ioctl compat stuff to the msdos driver [try #6] +X-Git-Tag: v2.6.19~1581^2~9 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=188f83dfe0eeecd1427d0d255cc97dbf7ef6b4b7 + +[PATCH] BLOCK: Move the msdos device ioctl compat stuff to the msdos driver [try #6] + +Move the msdos device ioctl compat stuff from fs/compat_ioctl.c to the msdos +driver so that the msdos header file doesn't need to be included. + +Signed-Off-By: David Howells <dhowells@redhat.com> +Signed-off-by: Jens Axboe <axboe@kernel.dk> +--- + +Backported to Debian's 2.6.18 by dann frazier <dannf@debian.org> + +diff -urpN linux-source-2.6.18.orig/fs/compat_ioctl.c linux-source-2.6.18/fs/compat_ioctl.c +--- linux-source-2.6.18.orig/fs/compat_ioctl.c 2006-09-20 04:42:06.000000000 +0100 ++++ linux-source-2.6.18/fs/compat_ioctl.c 2007-06-22 15:57:42.000000000 +0100 +@@ -113,7 +113,6 @@ + #include <linux/nbd.h> + #include <linux/random.h> + #include <linux/filter.h> +-#include <linux/msdos_fs.h> + #include <linux/pktcdvd.h> + + #include <linux/hiddev.h> +@@ -2052,51 +2051,6 @@ static int mtd_rw_oob(unsigned int fd, u + return err; + } + +-#define VFAT_IOCTL_READDIR_BOTH32 _IOR('r', 1, struct compat_dirent[2]) +-#define VFAT_IOCTL_READDIR_SHORT32 _IOR('r', 2, struct compat_dirent[2]) +- +-static long +-put_dirent32 (struct dirent *d, struct compat_dirent __user *d32) +-{ +- if (!access_ok(VERIFY_WRITE, d32, sizeof(struct compat_dirent))) +- return -EFAULT; +- +- __put_user(d->d_ino, &d32->d_ino); +- __put_user(d->d_off, &d32->d_off); +- __put_user(d->d_reclen, &d32->d_reclen); +- if (__copy_to_user(d32->d_name, d->d_name, d->d_reclen)) +- return -EFAULT; +- +- return 0; +-} +- +-static int vfat_ioctl32(unsigned fd, unsigned cmd, unsigned long arg) +-{ +- struct compat_dirent __user *p = compat_ptr(arg); +- int ret; +- mm_segment_t oldfs = get_fs(); +- struct dirent d[2]; +- +- switch(cmd) +- { +- case VFAT_IOCTL_READDIR_BOTH32: +- cmd = VFAT_IOCTL_READDIR_BOTH; +- break; +- case VFAT_IOCTL_READDIR_SHORT32: +- cmd = VFAT_IOCTL_READDIR_SHORT; +- break; +- } +- +- set_fs(KERNEL_DS); +- ret = sys_ioctl(fd,cmd,(unsigned long)&d); +- set_fs(oldfs); +- if (ret >= 0) { +- ret |= put_dirent32(&d[0], p); +- ret |= put_dirent32(&d[1], p + 1); +- } +- return ret; +-} +- + #define REISERFS_IOC_UNPACK32 _IOW(0xCD,1,int) + + static int reiserfs_ioctl32(unsigned fd, unsigned cmd, unsigned long ptr) +@@ -2866,9 +2820,6 @@ HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_io + HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget) + HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset) + HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64) +-/* vfat */ +-HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32) +-HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32) + HANDLE_IOCTL(REISERFS_IOC_UNPACK32, reiserfs_ioctl32) + /* Raw devices */ + HANDLE_IOCTL(RAW_SETBIND, raw_ioctl) +diff -urpN linux-source-2.6.18.orig/fs/fat/dir.c linux-source-2.6.18/fs/fat/dir.c +--- linux-source-2.6.18.orig/fs/fat/dir.c 2006-09-20 04:42:06.000000000 +0100 ++++ linux-source-2.6.18/fs/fat/dir.c 2007-06-22 15:55:53.000000000 +0100 +@@ -20,6 +20,7 @@ + #include <linux/dirent.h> + #include <linux/smp_lock.h> + #include <linux/buffer_head.h> ++#include <linux/compat.h> + #include <asm/uaccess.h> + + static inline loff_t fat_make_i_pos(struct super_block *sb, +@@ -741,10 +742,65 @@ static int fat_dir_ioctl(struct inode * + return ret; + } + ++#ifdef CONFIG_COMPAT ++#define VFAT_IOCTL_READDIR_BOTH32 _IOR('r', 1, struct compat_dirent[2]) ++#define VFAT_IOCTL_READDIR_SHORT32 _IOR('r', 2, struct compat_dirent[2]) ++ ++static long fat_compat_put_dirent32(struct dirent *d, ++ struct compat_dirent __user *d32) ++{ ++ if (!access_ok(VERIFY_WRITE, d32, sizeof(struct compat_dirent))) ++ return -EFAULT; ++ ++ __put_user(d->d_ino, &d32->d_ino); ++ __put_user(d->d_off, &d32->d_off); ++ __put_user(d->d_reclen, &d32->d_reclen); ++ if (__copy_to_user(d32->d_name, d->d_name, d->d_reclen)) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++static long fat_compat_dir_ioctl(struct file *file, unsigned cmd, ++ unsigned long arg) ++{ ++ struct compat_dirent __user *p = compat_ptr(arg); ++ int ret; ++ mm_segment_t oldfs = get_fs(); ++ struct dirent d[2]; ++ ++ switch (cmd) { ++ case VFAT_IOCTL_READDIR_BOTH32: ++ cmd = VFAT_IOCTL_READDIR_BOTH; ++ break; ++ case VFAT_IOCTL_READDIR_SHORT32: ++ cmd = VFAT_IOCTL_READDIR_SHORT; ++ break; ++ default: ++ return -ENOIOCTLCMD; ++ } ++ ++ set_fs(KERNEL_DS); ++ lock_kernel(); ++ ret = fat_dir_ioctl(file->f_dentry->d_inode, file, ++ cmd, (unsigned long) &d); ++ unlock_kernel(); ++ set_fs(oldfs); ++ if (ret >= 0) { ++ ret |= fat_compat_put_dirent32(&d[0], p); ++ ret |= fat_compat_put_dirent32(&d[1], p + 1); ++ } ++ return ret; ++} ++#endif /* CONFIG_COMPAT */ ++ + const struct file_operations fat_dir_operations = { + .read = generic_read_dir, + .readdir = fat_readdir, + .ioctl = fat_dir_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = fat_compat_dir_ioctl, ++#endif + .fsync = file_fsync, + }; + diff --git a/trunk/2.6.18/30058_fat-fix-compat-ioctls.patch b/trunk/2.6.18/30058_fat-fix-compat-ioctls.patch new file mode 100644 index 0000000..f98c7d1 --- /dev/null +++ b/trunk/2.6.18/30058_fat-fix-compat-ioctls.patch @@ -0,0 +1,311 @@ +From: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> +Date: Tue, 8 May 2007 07:31:28 +0000 (-0700) +Subject: fat: fix VFAT compat ioctls on 64-bit systems +X-Git-Tag: v2.6.22-rc1~614 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=c483bab099cb89e92b7cad94a52fcdaf37e56657 + +fat: fix VFAT compat ioctls on 64-bit systems + +If you compile and run the below test case in an msdos or vfat directory on +an x86-64 system with -m32 you'll get garbage in the kernel_dirent struct +followed by a SIGSEGV. + +The patch fixes this. + +Reported and initial fix by Bart Oldeman + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <dirent.h> +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +struct kernel_dirent { + long d_ino; + long d_off; + unsigned short d_reclen; + char d_name[256]; /* We must not include limits.h! */ +}; +#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct kernel_dirent [2]) +#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct kernel_dirent [2]) + +int main(void) +{ + int fd = open(".", O_RDONLY); + struct kernel_dirent de[2]; + + while (1) { + int i = ioctl(fd, VFAT_IOCTL_READDIR_BOTH, (long)de); + if (i == -1) break; + if (de[0].d_reclen == 0) break; + printf("SFN: reclen=%2d off=%d ino=%d, %-12s", + de[0].d_reclen, de[0].d_off, de[0].d_ino, de[0].d_name); + if (de[1].d_reclen) + printf("\tLFN: reclen=%2d off=%d ino=%d, %s", + de[1].d_reclen, de[1].d_off, de[1].d_ino, de[1].d_name); + printf("\n"); + } + return 0; +} + +Signed-off-by: Bart Oldeman <bartoldeman@users.sourceforge.net> +Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> +Cc: <stable@kernel.org> +Signed-off-by: Andrew Morton <akpm@linux-foundation.org> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +--- + +Backported to Debian's 2.6.18 by dann frazier <dannf@debian.org> + +diff -urpN linux-source-2.6.18.orig/fs/fat/dir.c linux-source-2.6.18/fs/fat/dir.c +--- linux-source-2.6.18.orig/fs/fat/dir.c 2007-06-22 21:48:00.000000000 -0600 ++++ linux-source-2.6.18/fs/fat/dir.c 2007-06-22 21:48:42.000000000 -0600 +@@ -422,7 +422,7 @@ EODir: + EXPORT_SYMBOL_GPL(fat_search_long); + + struct fat_ioctl_filldir_callback { +- struct dirent __user *dirent; ++ void __user *dirent; + int result; + /* for dir ioctl */ + const char *longname; +@@ -647,62 +647,85 @@ static int fat_readdir(struct file *filp + return __fat_readdir(inode, filp, dirent, filldir, 0, 0); + } + +-static int fat_ioctl_filldir(void *__buf, const char *name, int name_len, +- loff_t offset, ino_t ino, unsigned int d_type) ++#define FAT_IOCTL_FILLDIR_FUNC(func, dirent_type) \ ++static int func(void *__buf, const char *name, int name_len, \ ++ loff_t offset, ino_t ino, unsigned int d_type) \ ++{ \ ++ struct fat_ioctl_filldir_callback *buf = __buf; \ ++ struct dirent_type __user *d1 = buf->dirent; \ ++ struct dirent_type __user *d2 = d1 + 1; \ ++ \ ++ if (buf->result) \ ++ return -EINVAL; \ ++ buf->result++; \ ++ \ ++ if (name != NULL) { \ ++ /* dirent has only short name */ \ ++ if (name_len >= sizeof(d1->d_name)) \ ++ name_len = sizeof(d1->d_name) - 1; \ ++ \ ++ if (put_user(0, d2->d_name) || \ ++ put_user(0, &d2->d_reclen) || \ ++ copy_to_user(d1->d_name, name, name_len) || \ ++ put_user(0, d1->d_name + name_len) || \ ++ put_user(name_len, &d1->d_reclen)) \ ++ goto efault; \ ++ } else { \ ++ /* dirent has short and long name */ \ ++ const char *longname = buf->longname; \ ++ int long_len = buf->long_len; \ ++ const char *shortname = buf->shortname; \ ++ int short_len = buf->short_len; \ ++ \ ++ if (long_len >= sizeof(d1->d_name)) \ ++ long_len = sizeof(d1->d_name) - 1; \ ++ if (short_len >= sizeof(d1->d_name)) \ ++ short_len = sizeof(d1->d_name) - 1; \ ++ \ ++ if (copy_to_user(d2->d_name, longname, long_len) || \ ++ put_user(0, d2->d_name + long_len) || \ ++ put_user(long_len, &d2->d_reclen) || \ ++ put_user(ino, &d2->d_ino) || \ ++ put_user(offset, &d2->d_off) || \ ++ copy_to_user(d1->d_name, shortname, short_len) || \ ++ put_user(0, d1->d_name + short_len) || \ ++ put_user(short_len, &d1->d_reclen)) \ ++ goto efault; \ ++ } \ ++ return 0; \ ++efault: \ ++ buf->result = -EFAULT; \ ++ return -EFAULT; \ ++} ++ ++FAT_IOCTL_FILLDIR_FUNC(fat_ioctl_filldir, dirent) ++ ++static int fat_ioctl_readdir(struct inode *inode, struct file *filp, ++ void __user *dirent, filldir_t filldir, ++ int short_only, int both) + { +- struct fat_ioctl_filldir_callback *buf = __buf; +- struct dirent __user *d1 = buf->dirent; +- struct dirent __user *d2 = d1 + 1; +- +- if (buf->result) +- return -EINVAL; +- buf->result++; +- +- if (name != NULL) { +- /* dirent has only short name */ +- if (name_len >= sizeof(d1->d_name)) +- name_len = sizeof(d1->d_name) - 1; +- +- if (put_user(0, d2->d_name) || +- put_user(0, &d2->d_reclen) || +- copy_to_user(d1->d_name, name, name_len) || +- put_user(0, d1->d_name + name_len) || +- put_user(name_len, &d1->d_reclen)) +- goto efault; +- } else { +- /* dirent has short and long name */ +- const char *longname = buf->longname; +- int long_len = buf->long_len; +- const char *shortname = buf->shortname; +- int short_len = buf->short_len; +- +- if (long_len >= sizeof(d1->d_name)) +- long_len = sizeof(d1->d_name) - 1; +- if (short_len >= sizeof(d1->d_name)) +- short_len = sizeof(d1->d_name) - 1; +- +- if (copy_to_user(d2->d_name, longname, long_len) || +- put_user(0, d2->d_name + long_len) || +- put_user(long_len, &d2->d_reclen) || +- put_user(ino, &d2->d_ino) || +- put_user(offset, &d2->d_off) || +- copy_to_user(d1->d_name, shortname, short_len) || +- put_user(0, d1->d_name + short_len) || +- put_user(short_len, &d1->d_reclen)) +- goto efault; ++ struct fat_ioctl_filldir_callback buf; ++ int ret; ++ ++ buf.dirent = dirent; ++ buf.result = 0; ++ mutex_lock(&inode->i_mutex); ++ ret = -ENOENT; ++ if (!IS_DEADDIR(inode)) { ++ ret = __fat_readdir(inode, filp, &buf, filldir, ++ short_only, both); + } +- return 0; +-efault: +- buf->result = -EFAULT; +- return -EFAULT; ++ mutex_unlock(&inode->i_mutex); ++ if (ret >= 0) ++ ret = buf.result; ++ return ret; + } + +-static int fat_dir_ioctl(struct inode * inode, struct file * filp, +- unsigned int cmd, unsigned long arg) ++static int fat_dir_ioctl(struct inode *inode, struct file *filp, ++ unsigned int cmd, unsigned long arg) + { +- struct fat_ioctl_filldir_callback buf; +- struct dirent __user *d1; +- int ret, short_only, both; ++ struct dirent __user *d1 = (struct dirent __user *)arg; ++ int short_only, both; + + switch (cmd) { + case VFAT_IOCTL_READDIR_SHORT: +@@ -717,7 +740,6 @@ static int fat_dir_ioctl(struct inode * + return fat_generic_ioctl(inode, filp, cmd, arg); + } + +- d1 = (struct dirent __user *)arg; + if (!access_ok(VERIFY_WRITE, d1, sizeof(struct dirent[2]))) + return -EFAULT; + /* +@@ -728,69 +750,48 @@ static int fat_dir_ioctl(struct inode * + if (put_user(0, &d1->d_reclen)) + return -EFAULT; + +- buf.dirent = d1; +- buf.result = 0; +- mutex_lock(&inode->i_mutex); +- ret = -ENOENT; +- if (!IS_DEADDIR(inode)) { +- ret = __fat_readdir(inode, filp, &buf, fat_ioctl_filldir, +- short_only, both); +- } +- mutex_unlock(&inode->i_mutex); +- if (ret >= 0) +- ret = buf.result; +- return ret; ++ return fat_ioctl_readdir(inode, filp, d1, fat_ioctl_filldir, ++ short_only, both); + } + + #ifdef CONFIG_COMPAT + #define VFAT_IOCTL_READDIR_BOTH32 _IOR('r', 1, struct compat_dirent[2]) + #define VFAT_IOCTL_READDIR_SHORT32 _IOR('r', 2, struct compat_dirent[2]) + +-static long fat_compat_put_dirent32(struct dirent *d, +- struct compat_dirent __user *d32) +-{ +- if (!access_ok(VERIFY_WRITE, d32, sizeof(struct compat_dirent))) +- return -EFAULT; ++FAT_IOCTL_FILLDIR_FUNC(fat_compat_ioctl_filldir, compat_dirent) + +- __put_user(d->d_ino, &d32->d_ino); +- __put_user(d->d_off, &d32->d_off); +- __put_user(d->d_reclen, &d32->d_reclen); +- if (__copy_to_user(d32->d_name, d->d_name, d->d_reclen)) +- return -EFAULT; +- +- return 0; +-} +- +-static long fat_compat_dir_ioctl(struct file *file, unsigned cmd, ++static long fat_compat_dir_ioctl(struct file *filp, unsigned cmd, + unsigned long arg) + { +- struct compat_dirent __user *p = compat_ptr(arg); +- int ret; +- mm_segment_t oldfs = get_fs(); +- struct dirent d[2]; ++ struct inode *inode = filp->f_dentry->d_inode; ++ struct compat_dirent __user *d1 = compat_ptr(arg); ++ int short_only, both; + + switch (cmd) { +- case VFAT_IOCTL_READDIR_BOTH32: +- cmd = VFAT_IOCTL_READDIR_BOTH; +- break; + case VFAT_IOCTL_READDIR_SHORT32: +- cmd = VFAT_IOCTL_READDIR_SHORT; ++ short_only = 1; ++ both = 0; ++ break; ++ case VFAT_IOCTL_READDIR_BOTH32: ++ short_only = 0; ++ both = 1; + break; + default: + return -ENOIOCTLCMD; + } + +- set_fs(KERNEL_DS); +- lock_kernel(); +- ret = fat_dir_ioctl(file->f_dentry->d_inode, file, +- cmd, (unsigned long) &d); +- unlock_kernel(); +- set_fs(oldfs); +- if (ret >= 0) { +- ret |= fat_compat_put_dirent32(&d[0], p); +- ret |= fat_compat_put_dirent32(&d[1], p + 1); +- } +- return ret; ++ if (!access_ok(VERIFY_WRITE, d1, sizeof(struct compat_dirent[2]))) ++ return -EFAULT; ++ /* ++ * Yes, we don't need this put_user() absolutely. However old ++ * code didn't return the right value. So, app use this value, ++ * in order to check whether it is EOF. ++ */ ++ if (put_user(0, &d1->d_reclen)) ++ return -EFAULT; ++ ++ return fat_ioctl_readdir(inode, filp, d1, fat_compat_ioctl_filldir, ++ short_only, both); + } + #endif /* CONFIG_COMPAT */ + diff --git a/trunk/2.6.18/30059_vfs-use-access-mode-flag.patch b/trunk/2.6.18/30059_vfs-use-access-mode-flag.patch new file mode 100644 index 0000000..ef47e1a --- /dev/null +++ b/trunk/2.6.18/30059_vfs-use-access-mode-flag.patch @@ -0,0 +1,52 @@ +From: Linus Torvalds <torvalds@woody.linux-foundation.org> +Date: Sat, 12 Jan 2008 22:06:34 +0000 (-0800) +Subject: Use access mode instead of open flags to determine needed permissions +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=974a9f0b47da74e28f68b9c8645c3786aa5ace1a + +Use access mode instead of open flags to determine needed permissions + +Way back when (in commit 834f2a4a1554dc5b2598038b3fe8703defcbe467, aka +"VFS: Allow the filesystem to return a full file pointer on open intent" +to be exact), Trond changed the open logic to keep track of the original +flags to a file open, in order to pass down the the intent of a dentry +lookup to the low-level filesystem. + +However, when doing that reorganization, it changed the meaning of +namei_flags, and thus inadvertently changed the test of access mode for +directories (and RO filesystem) to use the wrong flag. So fix those +test back to use access mode ("acc_mode") rather than the open flag +("flag"). + +Issue noticed by Bill Roman at Datalight. + +Reported-and-tested-by: Bill Roman <bill.roman@datalight.com> +Acked-by: Trond Myklebust <Trond.Myklebust@netapp.com> +Acked-by: Al Viro <viro@ZenIV.linux.org.uk> +Cc: Christoph Hellwig <hch@lst.de> +Cc: Andrew Morton <akpm@linux-foundation.org> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +--- + +Adjusted to apply to Debian's 2.6.18 by dann frazier <dannf@hp.com> + +diff -urpN linux-source-2.6.18.orig/fs/namei.c linux-source-2.6.18/fs/namei.c +--- linux-source-2.6.18.orig/fs/namei.c 2006-09-19 21:42:06.000000000 -0600 ++++ linux-source-2.6.18/fs/namei.c 2008-01-15 16:42:10.000000000 -0700 +@@ -1500,7 +1500,7 @@ int may_open(struct nameidata *nd, int a + if (S_ISLNK(inode->i_mode)) + return -ELOOP; + +- if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE)) ++ if (S_ISDIR(inode->i_mode) && (acc_mode & MAY_WRITE)) + return -EISDIR; + + error = vfs_permission(nd, acc_mode); +@@ -1519,7 +1519,7 @@ int may_open(struct nameidata *nd, int a + return -EACCES; + + flag &= ~O_TRUNC; +- } else if (IS_RDONLY(inode) && (flag & FMODE_WRITE)) ++ } else if (IS_RDONLY(inode) && (acc_mode & MAY_WRITE)) + return -EROFS; + /* + * An append-only file must be opened in append mode for writing. diff --git a/trunk/2.6.18/30060_i4l-isdn_ioctl-mem-overrun.patch b/trunk/2.6.18/30060_i4l-isdn_ioctl-mem-overrun.patch new file mode 100644 index 0000000..a44bb5b --- /dev/null +++ b/trunk/2.6.18/30060_i4l-isdn_ioctl-mem-overrun.patch @@ -0,0 +1,56 @@ +From: Karsten Keil <kkeil@suse.de> +Date: Sat, 1 Dec 2007 20:16:15 +0000 (-0800) +Subject: I4L: fix isdn_ioctl memory overrun vulnerability +X-Git-Tag: v2.6.24-rc4~16 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=eafe1aa37e6ec2d56f14732b5240c4dd09f0613a + +I4L: fix isdn_ioctl memory overrun vulnerability + +Fix possible memory overrun issue in the isdn ioctl code. + +Found by ADLAB <adlab@venustech.com.cn> + +Signed-off-by: Karsten Keil <kkeil@suse.de> +Cc: ADLAB <adlab@venustech.com.cn> +Cc: <stable@kernel.org> +Signed-off-by: Andrew Morton <akpm@linux-foundation.org> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +--- + +diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c +index c6df292..d695295 100644 +--- a/drivers/isdn/i4l/isdn_common.c ++++ b/drivers/isdn/i4l/isdn_common.c +@@ -1515,6 +1515,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) + if (copy_from_user(&iocts, argp, + sizeof(isdn_ioctl_struct))) + return -EFAULT; ++ iocts.drvid[sizeof(iocts.drvid)-1] = 0; + if (strlen(iocts.drvid)) { + if ((p = strchr(iocts.drvid, ','))) + *p = 0; +@@ -1599,6 +1600,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) + if (copy_from_user(&iocts, argp, + sizeof(isdn_ioctl_struct))) + return -EFAULT; ++ iocts.drvid[sizeof(iocts.drvid)-1] = 0; + if (strlen(iocts.drvid)) { + drvidx = -1; + for (i = 0; i < ISDN_MAX_DRIVERS; i++) +@@ -1643,7 +1645,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) + } else { + p = (char __user *) iocts.arg; + for (i = 0; i < 10; i++) { +- sprintf(bname, "%s%s", ++ snprintf(bname, sizeof(bname), "%s%s", + strlen(dev->drv[drvidx]->msn2eaz[i]) ? + dev->drv[drvidx]->msn2eaz[i] : "_", + (i < 9) ? "," : "\0"); +@@ -1673,6 +1675,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) + char *p; + if (copy_from_user(&iocts, argp, sizeof(isdn_ioctl_struct))) + return -EFAULT; ++ iocts.drvid[sizeof(iocts.drvid)-1] = 0; + if (strlen(iocts.drvid)) { + if ((p = strchr(iocts.drvid, ','))) + *p = 0; diff --git a/trunk/2.6.18/30061_vmsplice-security.patch b/trunk/2.6.18/30061_vmsplice-security.patch new file mode 100644 index 0000000..248bdba --- /dev/null +++ b/trunk/2.6.18/30061_vmsplice-security.patch @@ -0,0 +1,28 @@ +diff --git a/fs/splice.c b/fs/splice.c +index 684bca3..2d7e598 100644 +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -1122,6 +1122,11 @@ static int get_iovec_page_array(const struct iovec __user *iov, + size_t len; + int i; + ++ if (!access_ok(VERIFY_READ, iov, sizeof(struct iovec))) { ++ error = -EFAULT; ++ break; ++ } ++ + /* + * Get user address base and length for this iovec. + */ +@@ -1141,6 +1146,11 @@ static int get_iovec_page_array(const struct iovec __user *iov, + if (unlikely(!base)) + break; + ++ if (!access_ok(VERIFY_READ, base, len)) { ++ error = -EFAULT; ++ break; ++ } ++ + /* + * Get this base offset and number of pages, then map + * in the user pages. diff --git a/trunk/2.6.18/30062_clear-spurious-irq.patch b/trunk/2.6.18/30062_clear-spurious-irq.patch new file mode 100644 index 0000000..6873d8c --- /dev/null +++ b/trunk/2.6.18/30062_clear-spurious-irq.patch @@ -0,0 +1,34 @@ +From: Linus Torvalds <torvalds@woody.linux-foundation.org> +Date: Tue, 23 Jan 2007 22:16:31 +0000 (-0800) +Subject: Clear spurious irq stat information when adding irq handler +X-Git-Tag: v2.6.20-rc6~15 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=8528b0f1de1101c6002036fd53638fb21111d0ea + +Clear spurious irq stat information when adding irq handler + +Any newly added irq handler may obviously make any old spurious irq +status invalid, since the new handler may well be the thing that is +supposed to handle any interrupts that came in. + +So just clear the statistics when adding handlers. + +Pointed-out-by: Alan Cox <alan@lxorguk.ukuu.org.uk> +Acked-by: Thomas Gleixner <tglx@linutronix.de> +Acked-by: Ingo Molnar <mingo@elte.hu> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +--- + +diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c +index b385878..8b961ad 100644 +--- a/kernel/irq/manage.c ++++ b/kernel/irq/manage.c +@@ -315,6 +315,9 @@ int setup_irq(unsigned int irq, struct irqaction *new) + /* Undo nested disables: */ + desc->depth = 1; + } ++ /* Reset broken irq detection when installing new handler */ ++ desc->irq_count = 0; ++ desc->irqs_unhandled = 0; + spin_unlock_irqrestore(&desc->lock, flags); + + new->irq = irq; |