• R/O
  • HTTP
  • SSH
  • HTTPS

linux-2.4.36: Commit

2.4.36-stable kernel tree


Commit MetaInfo

Revision57812a4772fa73f264b59ae31c5cc277630b1ff5 (tree)
Time2008-11-10 00:22:14
AuthorDavid Miller <davem@dave...>
CommiterWilly Tarreau

Log Message

net: Fix recursive descent in scm_destroy().

[backport of 2.6 commit f8d570a4745835f2238a33b537218a1bb03fc671]

scm_destroy() walks the list of file descriptors in the scm_fp_list
pointed to by the scm_cookie argument.

Those, in turn, can close sockets and invoke scm_destroy() again.

There is nothing which limits how deeply this can occur.

The idea for how to fix this is from Linus. Basically, we do all of
the fput()s at the top level by collecting all of the scm_fp_list
objects hit by an fput(). Inside of the initial scm_destroy() we
keep running the list until it is empty.

Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Willy Tarreau <w@1wt.eu>

Change Summary

Incremental Difference

--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -415,6 +415,8 @@ struct task_struct {
415415
416416 /* journalling filesystem info */
417417 void *journal_info;
418+
419+ struct list_head *scm_work_list;
418420 };
419421
420422 /*
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -8,8 +8,9 @@
88
99 struct scm_fp_list
1010 {
11- int count;
12- struct file *fp[SCM_MAX_FD];
11+ struct list_head list;
12+ int count;
13+ struct file *fp[SCM_MAX_FD];
1314 };
1415
1516 struct scm_cookie
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -70,6 +70,7 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
7070 if (!fpl)
7171 return -ENOMEM;
7272 *fplp = fpl;
73+ INIT_LIST_HEAD(&fpl->list);
7374 fpl->count = 0;
7475 }
7576 fpp = &fpl->fp[fpl->count];
@@ -101,9 +102,25 @@ void __scm_destroy(struct scm_cookie *scm)
101102
102103 if (fpl) {
103104 scm->fp = NULL;
104- for (i=fpl->count-1; i>=0; i--)
105- fput(fpl->fp[i]);
106- kfree(fpl);
105+ if (current->scm_work_list) {
106+ list_add_tail(&fpl->list, current->scm_work_list);
107+ } else {
108+ LIST_HEAD(work_list);
109+
110+ current->scm_work_list = &work_list;
111+
112+ list_add(&fpl->list, &work_list);
113+ while (!list_empty(&work_list)) {
114+ fpl = list_entry(work_list.next, struct scm_fp_list, list);
115+
116+ list_del(&fpl->list);
117+ for (i=fpl->count-1; i>=0; i--)
118+ fput(fpl->fp[i]);
119+ kfree(fpl);
120+ }
121+
122+ current->scm_work_list = NULL;
123+ }
107124 }
108125 }
109126
@@ -263,6 +280,7 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
263280
264281 new_fpl = kmalloc(sizeof(*fpl), GFP_KERNEL);
265282 if (new_fpl) {
283+ INIT_LIST_HEAD(&new_fpl->list);
266284 for (i=fpl->count-1; i>=0; i--)
267285 get_file(fpl->fp[i]);
268286 memcpy(new_fpl, fpl, sizeof(*fpl));
Show on old repository browser