2.4.36-stable kernel tree
リビジョン | e11056494e595ad9c13d04ac4db0eadd7a59b5e9 (tree) |
---|---|
日時 | 2006-08-27 20:26:37 |
作者 | Sridhar Samudrala <sri@us.i...> |
コミッター | Willy Tarreau |
[PATCH] [SCTP] Local privilege elevation - CVE-2006-3745
Avoid the use of buggy get_user_iov_size(). sctp_make_abort_user()
now takes the msg_len along with the msg so that we don't have to
recalculate the bytes in iovec. It also uses memcpy_fromiovec()
so that we don't go beyond the length of the allocated buffer.
Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>
@@ -410,19 +410,6 @@ static inline int sctp_list_single_entry(struct list_head *head) | ||
410 | 410 | return ((head->next != head) && (head->next == head->prev)); |
411 | 411 | } |
412 | 412 | |
413 | -/* Calculate the size (in bytes) occupied by the data of an iovec. */ | |
414 | -static inline size_t get_user_iov_size(struct iovec *iov, int iovlen) | |
415 | -{ | |
416 | - size_t retval = 0; | |
417 | - | |
418 | - for (; iovlen > 0; --iovlen) { | |
419 | - retval += iov->iov_len; | |
420 | - iov++; | |
421 | - } | |
422 | - | |
423 | - return retval; | |
424 | -} | |
425 | - | |
426 | 413 | /* Generate a random jitter in the range of -50% ~ +50% of input RTO. */ |
427 | 414 | static inline __s32 sctp_jitter(__u32 rto) |
428 | 415 | { |
@@ -221,8 +221,7 @@ struct sctp_chunk *sctp_make_abort_no_data(const struct sctp_association *, | ||
221 | 221 | const struct sctp_chunk *, |
222 | 222 | __u32 tsn); |
223 | 223 | struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *, |
224 | - const struct sctp_chunk *, | |
225 | - const struct msghdr *); | |
224 | + const struct msghdr *, size_t msg_len); | |
226 | 225 | struct sctp_chunk *sctp_make_abort_violation(const struct sctp_association *, |
227 | 226 | const struct sctp_chunk *, |
228 | 227 | const __u8 *, |
@@ -798,38 +798,26 @@ no_mem: | ||
798 | 798 | |
799 | 799 | /* Helper to create ABORT with a SCTP_ERROR_USER_ABORT error. */ |
800 | 800 | struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *asoc, |
801 | - const struct sctp_chunk *chunk, | |
802 | - const struct msghdr *msg) | |
801 | + const struct msghdr *msg, | |
802 | + size_t paylen) | |
803 | 803 | { |
804 | 804 | struct sctp_chunk *retval; |
805 | - void *payload = NULL, *payoff; | |
806 | - size_t paylen = 0; | |
807 | - struct iovec *iov = NULL; | |
808 | - int iovlen = 0; | |
809 | - | |
810 | - if (msg) { | |
811 | - iov = msg->msg_iov; | |
812 | - iovlen = msg->msg_iovlen; | |
813 | - paylen = get_user_iov_size(iov, iovlen); | |
814 | - } | |
805 | + void *payload = NULL; | |
806 | + int err; | |
815 | 807 | |
816 | - retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen); | |
808 | + retval = sctp_make_abort(asoc, NULL, sizeof(sctp_errhdr_t) + paylen); | |
817 | 809 | if (!retval) |
818 | 810 | goto err_chunk; |
819 | 811 | |
820 | 812 | if (paylen) { |
821 | 813 | /* Put the msg_iov together into payload. */ |
822 | - payload = kmalloc(paylen, GFP_ATOMIC); | |
814 | + payload = kmalloc(paylen, GFP_KERNEL); | |
823 | 815 | if (!payload) |
824 | 816 | goto err_payload; |
825 | - payoff = payload; | |
826 | 817 | |
827 | - for (; iovlen > 0; --iovlen) { | |
828 | - if (copy_from_user(payoff, iov->iov_base,iov->iov_len)) | |
829 | - goto err_copy; | |
830 | - payoff += iov->iov_len; | |
831 | - iov++; | |
832 | - } | |
818 | + err = memcpy_fromiovec(payload, msg->msg_iov, paylen); | |
819 | + if (err < 0) | |
820 | + goto err_copy; | |
833 | 821 | } |
834 | 822 | |
835 | 823 | sctp_init_cause(retval, SCTP_ERROR_USER_ABORT, payload, paylen); |
@@ -3990,18 +3990,12 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort( | ||
3990 | 3990 | * from its upper layer, but retransmits data to the far end |
3991 | 3991 | * if necessary to fill gaps. |
3992 | 3992 | */ |
3993 | - struct msghdr *msg = arg; | |
3994 | - struct sctp_chunk *abort; | |
3993 | + struct sctp_chunk *abort = arg; | |
3995 | 3994 | sctp_disposition_t retval; |
3996 | 3995 | |
3997 | 3996 | retval = SCTP_DISPOSITION_CONSUME; |
3998 | 3997 | |
3999 | - /* Generate ABORT chunk to send the peer. */ | |
4000 | - abort = sctp_make_abort_user(asoc, NULL, msg); | |
4001 | - if (!abort) | |
4002 | - retval = SCTP_DISPOSITION_NOMEM; | |
4003 | - else | |
4004 | - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); | |
3998 | + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); | |
4005 | 3999 | |
4006 | 4000 | /* Even if we can't send the ABORT due to low memory delete the |
4007 | 4001 | * TCB. This is a departure from our typical NOMEM handling. |
@@ -4123,8 +4117,7 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort( | ||
4123 | 4117 | void *arg, |
4124 | 4118 | sctp_cmd_seq_t *commands) |
4125 | 4119 | { |
4126 | - struct msghdr *msg = arg; | |
4127 | - struct sctp_chunk *abort; | |
4120 | + struct sctp_chunk *abort = arg; | |
4128 | 4121 | sctp_disposition_t retval; |
4129 | 4122 | |
4130 | 4123 | /* Stop T1-init timer */ |
@@ -4132,12 +4125,7 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort( | ||
4132 | 4125 | SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); |
4133 | 4126 | retval = SCTP_DISPOSITION_CONSUME; |
4134 | 4127 | |
4135 | - /* Generate ABORT chunk to send the peer */ | |
4136 | - abort = sctp_make_abort_user(asoc, NULL, msg); | |
4137 | - if (!abort) | |
4138 | - retval = SCTP_DISPOSITION_NOMEM; | |
4139 | - else | |
4140 | - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); | |
4128 | + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); | |
4141 | 4129 | |
4142 | 4130 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, |
4143 | 4131 | SCTP_STATE(SCTP_STATE_CLOSED)); |
@@ -1199,8 +1199,16 @@ SCTP_STATIC int sctp_sendmsg(struct sock *sk, struct msghdr *msg, int msg_len) | ||
1199 | 1199 | goto out_unlock; |
1200 | 1200 | } |
1201 | 1201 | if (sinfo_flags & MSG_ABORT) { |
1202 | + struct sctp_chunk *chunk; | |
1203 | + | |
1204 | + chunk = sctp_make_abort_user(asoc, msg, msg_len); | |
1205 | + if (!chunk) { | |
1206 | + err = -ENOMEM; | |
1207 | + goto out_unlock; | |
1208 | + } | |
1209 | + | |
1202 | 1210 | SCTP_DEBUG_PRINTK("Aborting association: %p\n", asoc); |
1203 | - sctp_primitive_ABORT(asoc, msg); | |
1211 | + sctp_primitive_ABORT(asoc, chunk); | |
1204 | 1212 | err = 0; |
1205 | 1213 | goto out_unlock; |
1206 | 1214 | } |