diff -u --recursive --new-file v2.0.1/linux/CREDITS linux/CREDITS --- v2.0.1/linux/CREDITS Sun Jun 9 13:28:40 1996 +++ linux/CREDITS Fri Jul 5 11:43:39 1996 @@ -1029,6 +1029,13 @@ S: Thunder Bay, Ontario S: CANADA P7C 5M9 +N: Yuri Per +E: yuri@pts.mipt.ru +D: Some smbfs fixes +S: Demonstratsii 8-382 +S: Tula 300000 +S: Russia + N: Kai Petzke E: wpp@marie.physik.tu-berlin.de W: http://physik.tu-berlin.de/~wpp diff -u --recursive --new-file v2.0.1/linux/Documentation/Changes linux/Documentation/Changes --- v2.0.1/linux/Documentation/Changes Wed Jul 3 22:05:06 1996 +++ linux/Documentation/Changes Fri Jul 5 18:58:56 1996 @@ -179,7 +179,9 @@ your computer shuts down fine but "INIT: error reading initrequest" or words to that effect scroll across your screen hundreds of times. To fix, upgrade to -ftp://ftp.cistron.nl/pub/people/miquels/debian/sysvinit-2.62.tar.gz. + +ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.64.tar.gz or +ftp://tsx-11.mit.edu /pub/linux/sources/sbin/sysvinit-2.64.tar.gz If you're trying to run NCSA httpd, you have to set pre-spawning of daemons to zero, as it incorrectly assumes SunOS behavior. I recommend diff -u --recursive --new-file v2.0.1/linux/Makefile linux/Makefile --- v2.0.1/linux/Makefile Wed Jul 3 22:05:06 1996 +++ linux/Makefile Wed Jul 3 22:06:38 1996 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 0 -SUBLEVEL = 1 +SUBLEVEL = 2 ARCH = i386 diff -u --recursive --new-file v2.0.1/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.0.1/linux/arch/alpha/config.in Wed Jun 5 10:41:27 1996 +++ linux/arch/alpha/config.in Thu Jul 4 08:51:42 1996 @@ -123,6 +123,15 @@ fi mainmenu_option next_comment +comment 'ISDN subsystem' + +tristate 'ISDN support' CONFIG_ISDN +if [ "$CONFIG_ISDN" != "n" ]; then + source drivers/isdn/Config.in +fi +endmenu + +mainmenu_option next_comment comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)' bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI diff -u --recursive --new-file v2.0.1/linux/arch/alpha/defconfig linux/arch/alpha/defconfig --- v2.0.1/linux/arch/alpha/defconfig Wed Jul 3 22:05:07 1996 +++ linux/arch/alpha/defconfig Fri Jul 5 13:48:38 1996 @@ -162,6 +162,11 @@ # CONFIG_ARCNET is not set # +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# # CD-ROM drivers (not for SCSI or IDE/ATAPI drives) # # CONFIG_CD_NO_IDESCSI is not set diff -u --recursive --new-file v2.0.1/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.0.1/linux/drivers/char/serial.c Wed Jul 3 22:05:08 1996 +++ linux/drivers/char/serial.c Thu Jul 4 00:00:22 1996 @@ -2755,8 +2755,9 @@ serial_driver.type = TTY_DRIVER_TYPE_SERIAL; serial_driver.subtype = SERIAL_TYPE_NORMAL; serial_driver.init_termios = tty_std_termios; - serial_driver.init_termios.c_lflag &=~ (ISIG | ICANON | ECHO); - serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; + serial_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver.flags = TTY_DRIVER_REAL_RAW; serial_driver.refcount = &serial_refcount; serial_driver.table = serial_table; serial_driver.termios = serial_termios; diff -u --recursive --new-file v2.0.1/linux/drivers/net/lance32.c linux/drivers/net/lance32.c --- v2.0.1/linux/drivers/net/lance32.c Tue May 7 16:22:29 1996 +++ linux/drivers/net/lance32.c Thu Jul 4 08:52:04 1996 @@ -789,8 +789,8 @@ lance32_get_stats(struct device *dev) { struct lance32_private *lp = (struct lance32_private *)dev->priv; - short ioaddr = dev->base_addr; - short saved_addr; + int ioaddr = dev->base_addr; + unsigned short saved_addr; unsigned long flags; save_flags(flags); @@ -809,7 +809,7 @@ static void lance32_set_multicast_list(struct device *dev) { - short ioaddr = dev->base_addr; + int ioaddr = dev->base_addr; struct lance32_private *lp = (struct lance32_private *)dev->priv; if (dev->flags&IFF_PROMISC) { diff -u --recursive --new-file v2.0.1/linux/fs/exec.c linux/fs/exec.c --- v2.0.1/linux/fs/exec.c Wed Jul 3 22:05:18 1996 +++ linux/fs/exec.c Fri Jul 5 15:06:38 1996 @@ -114,41 +114,34 @@ int open_inode(struct inode * inode, int mode) { - int error, fd; - struct file *f, **fpp; + int fd; if (!inode->i_op || !inode->i_op->default_file_ops) return -EINVAL; - f = get_empty_filp(); - if (!f) - return -ENFILE; - fd = 0; - fpp = current->files->fd; - for (;;) { - if (!*fpp) - break; - if (++fd >= NR_OPEN) { - f->f_count--; - return -EMFILE; + fd = get_unused_fd(); + if (fd >= 0) { + struct file * f = get_empty_filp(); + if (!f) { + put_unused_fd(fd); + return -ENFILE; } - fpp++; - } - *fpp = f; - f->f_flags = mode; - f->f_mode = (mode+1) & O_ACCMODE; - f->f_inode = inode; - f->f_pos = 0; - f->f_reada = 0; - f->f_op = inode->i_op->default_file_ops; - if (f->f_op->open) { - error = f->f_op->open(inode,f); - if (error) { - *fpp = NULL; - f->f_count--; - return error; + f->f_flags = mode; + f->f_mode = (mode+1) & O_ACCMODE; + f->f_inode = inode; + f->f_pos = 0; + f->f_reada = 0; + f->f_op = inode->i_op->default_file_ops; + if (f->f_op->open) { + int error = f->f_op->open(inode,f); + if (error) { + f->f_count--; + put_unused_fd(fd); + return error; + } } + current->files->fd[fd] = f; + inode->i_count++; } - inode->i_count++; return fd; } @@ -399,10 +392,45 @@ } /* - * This function flushes out all traces of the currently running executable so - * that a new one can be started + * These functions flushes out all traces of the currently running executable + * so that a new one can be started */ +static inline void flush_old_signals(struct signal_struct *sig) +{ + int i; + struct sigaction * sa = sig->action; + + for (i=32 ; i != 0 ; i--) { + sa->sa_mask = 0; + sa->sa_flags = 0; + if (sa->sa_handler != SIG_IGN) + sa->sa_handler = NULL; + sa++; + } +} + +static inline void flush_old_files(struct files_struct * files) +{ + unsigned long j; + + j = 0; + for (;;) { + unsigned long set, i; + + i = j * __NFDBITS; + if (i >= NR_OPEN) + break; + set = files->close_on_exec.fds_bits[j]; + files->close_on_exec.fds_bits[j] = 0; + j++; + for ( ; set ; i++,set >>= 1) { + if (set & 1) + sys_close(i); + } + } +} + void flush_old_exec(struct linux_binprm * bprm) { int i; @@ -429,16 +457,9 @@ if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || permission(bprm->inode,MAY_READ)) current->dumpable = 0; - for (i=0 ; i<32 ; i++) { - current->sig->action[i].sa_mask = 0; - current->sig->action[i].sa_flags = 0; - if (current->sig->action[i].sa_handler != SIG_IGN) - current->sig->action[i].sa_handler = NULL; - } - for (i=0 ; ifiles->close_on_exec)) - sys_close(i); - FD_ZERO(¤t->files->close_on_exec); + + flush_old_signals(current->sig); + flush_old_files(current->files); } /* diff -u --recursive --new-file v2.0.1/linux/fs/fcntl.c linux/fs/fcntl.c --- v2.0.1/linux/fs/fcntl.c Sun May 5 08:52:03 1996 +++ linux/fs/fcntl.c Thu Jul 4 21:23:45 1996 @@ -13,23 +13,24 @@ #include #include +#include + extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg); static inline int dupfd(unsigned int fd, unsigned int arg) { - if (fd >= NR_OPEN || !current->files->fd[fd]) + struct files_struct * files = current->files; + + if (fd >= NR_OPEN || !files->fd[fd]) return -EBADF; if (arg >= NR_OPEN) return -EINVAL; - while (arg < NR_OPEN) - if (current->files->fd[arg]) - arg++; - else - break; - if (arg >= NR_OPEN) + arg = find_next_zero_bit(&files->open_fds, NR_OPEN, arg); + if (arg >= current->rlim[RLIMIT_NOFILE].rlim_cur) return -EMFILE; - FD_CLR(arg, ¤t->files->close_on_exec); - (current->files->fd[arg] = current->files->fd[fd])->f_count++; + FD_SET(arg, &files->open_fds); + FD_CLR(arg, &files->close_on_exec); + (files->fd[arg] = files->fd[fd])->f_count++; return arg; } diff -u --recursive --new-file v2.0.1/linux/fs/open.c linux/fs/open.c --- v2.0.1/linux/fs/open.c Wed Jul 3 22:05:19 1996 +++ linux/fs/open.c Fri Jul 5 09:27:10 1996 @@ -19,6 +19,7 @@ #include #include +#include asmlinkage int sys_statfs(const char * path, struct statfs * buf) { @@ -496,11 +497,11 @@ * for the internal routines (ie open_namei()/follow_link() etc). 00 is * used by symlinks. */ -int do_open(const char * filename,int flags,int mode) +static int do_open(const char * filename,int flags,int mode, int fd) { struct inode * inode; struct file * f; - int flag,error,fd; + int flag,error; f = get_empty_filp(); if (!f) @@ -533,21 +534,9 @@ } f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); - /* - * We have to do this last, because we mustn't export - * an incomplete fd to other processes which may share - * the same file table with us. - */ - for(fd = 0; fd < NR_OPEN && fd < current->rlim[RLIMIT_NOFILE].rlim_cur; fd++) { - if (!current->files->fd[fd]) { - current->files->fd[fd] = f; - FD_CLR(fd,¤t->files->close_on_exec); - return fd; - } - } - error = -EMFILE; - if (f->f_op && f->f_op->release) - f->f_op->release(inode,f); + current->files->fd[fd] = f; + return 0; + cleanup_all: if (f->f_mode & FMODE_WRITE) put_write_access(inode); @@ -558,16 +547,44 @@ return error; } +/* + * Find a empty file descriptor entry, and mark it busy + */ +int get_unused_fd(void) +{ + int fd; + struct files_struct * files = current->files; + + fd = find_first_zero_bit(&files->open_fds, NR_OPEN); + if (fd < current->rlim[RLIMIT_NOFILE].rlim_cur) { + FD_SET(fd, &files->open_fds); + FD_CLR(fd, &files->close_on_exec); + return fd; + } + return -EMFILE; +} + +inline void put_unused_fd(int fd) +{ + FD_CLR(fd, ¤t->files->open_fds); +} + asmlinkage int sys_open(const char * filename,int flags,int mode) { char * tmp; - int error; + int fd, error; + fd = get_unused_fd(); + if (fd < 0) + return fd; error = getname(filename, &tmp); - if (error) - return error; - error = do_open(tmp,flags,mode); - putname(tmp); + if (!error) { + error = do_open(tmp,flags,mode, fd); + putname(tmp); + if (!error) + return fd; + } + put_unused_fd(fd); return error; } @@ -610,16 +627,20 @@ } asmlinkage int sys_close(unsigned int fd) -{ +{ + int error; struct file * filp; + struct files_struct * files; - if (fd >= NR_OPEN) - return -EBADF; - FD_CLR(fd, ¤t->files->close_on_exec); - if (!(filp = current->files->fd[fd])) - return -EBADF; - current->files->fd[fd] = NULL; - return (close_fp (filp)); + files = current->files; + error = -EBADF; + if (fd < NR_OPEN && (filp = files->fd[fd]) != NULL) { + put_unused_fd(fd); + FD_CLR(fd, &files->close_on_exec); + files->fd[fd] = NULL; + error = close_fp(filp); + } + return error; } /* diff -u --recursive --new-file v2.0.1/linux/fs/pipe.c linux/fs/pipe.c --- v2.0.1/linux/fs/pipe.c Wed Jul 3 22:05:19 1996 +++ linux/fs/pipe.c Thu Jul 4 21:17:24 1996 @@ -414,45 +414,58 @@ int do_pipe(int *fd) { struct inode * inode; - struct file *f[2]; + struct file *f1, *f2; + int error; int i,j; + error = ENFILE; + f1 = get_empty_filp(); + if (!f1) + goto no_files; + + f2 = get_empty_filp(); + if (!f2) + goto close_f1; + inode = get_pipe_inode(); if (!inode) - return -ENFILE; + goto close_f12; + + error = get_unused_fd(); + if (error < 0) + goto close_f12_inode; + i = error; - for(j=0 ; j<2 ; j++) - if (!(f[j] = get_empty_filp())) - break; - if (j < 2) { - iput(inode); - iput(inode); - if (j) - f[0]->f_count--; - return -ENFILE; - } - j=0; - for(i=0;j<2 && irlim[RLIMIT_NOFILE].rlim_cur;i++) - if (!current->files->fd[i]) { - current->files->fd[ fd[j]=i ] = f[j]; - j++; - } - if (j<2) { - iput(inode); - iput(inode); - f[0]->f_count--; - f[1]->f_count--; - if (j) - current->files->fd[fd[0]] = NULL; - return -EMFILE; - } - f[0]->f_inode = f[1]->f_inode = inode; - f[0]->f_pos = f[1]->f_pos = 0; - f[0]->f_flags = O_RDONLY; - f[0]->f_op = &read_pipe_fops; - f[0]->f_mode = 1; /* read */ - f[1]->f_flags = O_WRONLY; - f[1]->f_op = &write_pipe_fops; - f[1]->f_mode = 2; /* write */ + error = get_unused_fd(); + if (error < 0) + goto close_f12_inode_i; + j = error; + + f1->f_inode = f2->f_inode = inode; + /* read file */ + f1->f_pos = f2->f_pos = 0; + f1->f_flags = O_RDONLY; + f1->f_op = &read_pipe_fops; + f1->f_mode = 1; + /* write file */ + f2->f_flags = O_WRONLY; + f2->f_op = &write_pipe_fops; + f2->f_mode = 2; + current->files->fd[i] = f1; + current->files->fd[j] = f2; + fd[0] = i; + fd[1] = j; return 0; + +close_f12_inode_i: + put_unused_fd(i); +close_f12_inode: + inode->i_count--; + iput(inode); +close_f12: + f2->f_count--; +close_f1: + f1->f_count--; +no_files: + return error; } diff -u --recursive --new-file v2.0.1/linux/fs/select.c linux/fs/select.c --- v2.0.1/linux/fs/select.c Wed Sep 27 09:57:19 1995 +++ linux/fs/select.c Fri Jul 5 13:48:39 1996 @@ -92,11 +92,13 @@ int i,j; int max = -1; - for (j = 0 ; j < __FDSET_INTS ; j++) { + j = 0; + for (;;) { i = j * __NFDBITS; if (i >= n) break; set = in->fds_bits[j] | out->fds_bits[j] | ex->fds_bits[j]; + j++; for ( ; set ; i++,set >>= 1) { if (i >= n) goto end_check; @@ -113,9 +115,6 @@ n = max + 1; if(!(entry = (struct select_table_entry*) __get_free_page(GFP_KERNEL))) return -ENOMEM; - FD_ZERO(res_in); - FD_ZERO(res_out); - FD_ZERO(res_ex); count = 0; wait_table.nr = 0; wait_table.entry = entry; @@ -153,51 +152,79 @@ /* * We do a VERIFY_WRITE here even though we are only reading this time: * we'll write to it eventually.. + * + * Use "int" accesses to let user-mode fd_set's be int-aligned. */ -static int __get_fd_set(int nr, unsigned int * fs_pointer, fd_set * fdset) +static int __get_fd_set(unsigned long nr, int * fs_pointer, int * fdset) { - int error, i; - unsigned int * tmp; - - FD_ZERO(fdset); - if (!fs_pointer) - return 0; - error = verify_area(VERIFY_WRITE,fs_pointer,sizeof(fd_set)); - if (error) + /* round up nr to nearest "int" */ + nr = (nr + 8*sizeof(int)-1) / (8*sizeof(int)); + if (fs_pointer) { + int error = verify_area(VERIFY_WRITE,fs_pointer,nr*sizeof(int)); + if (!error) { + while (nr) { + *fdset = get_user(fs_pointer); + nr--; + fs_pointer++; + fdset++; + } + } return error; - tmp = fdset->fds_bits; - for (i = __FDSET_INTS; i > 0; i--) { - if (nr <= 0) - break; - *tmp = get_user(fs_pointer); - tmp++; - fs_pointer++; - nr -= 8 * sizeof(unsigned int); + } + while (nr) { + *fdset = 0; + nr--; + fdset++; } return 0; } -static void __set_fd_set(int nr, unsigned int * fs_pointer, unsigned int * fdset) +static void __set_fd_set(long nr, int * fs_pointer, int * fdset) { - int i; - if (!fs_pointer) return; - for (i = __FDSET_INTS; i > 0; i--) { - if (nr <= 0) - break; + while (nr >= 0) { put_user(*fdset, fs_pointer); + nr -= 8 * sizeof(int); fdset++; fs_pointer++; - nr -= 8 * sizeof(unsigned int); } } +/* We can do long accesses here, kernel fdsets are always long-aligned */ +static inline void __zero_fd_set(long nr, unsigned long * fdset) +{ + while (nr >= 0) { + *fdset = 0; + nr -= 8 * sizeof(unsigned long); + fdset++; + } +} + +/* + * Due to kernel stack usage, we use a _limited_ fd_set type here, and once + * we really start supporting >256 file descriptors we'll probably have to + * allocate the kernel fd_set copies dynamically.. (The kernel select routines + * are careful to touch only the defined low bits of any fd_set pointer, this + * is important for performance too). + * + * Note a few subtleties: we use "long" for the dummy, not int, and we do a + * subtract by 1 on the nr of file descriptors. The former is better for + * machines with long > int, and the latter allows us to test the bit count + * against "zero or positive", which can mostly be just a sign bit test.. + */ +typedef struct { + unsigned long dummy[NR_OPEN/(8*(sizeof(unsigned long)))]; +} limited_fd_set; + #define get_fd_set(nr,fsp,fdp) \ -__get_fd_set(nr, (unsigned int *) (fsp), fdp) +__get_fd_set(nr, (int *) (fsp), (int *) (fdp)) #define set_fd_set(nr,fsp,fdp) \ -__set_fd_set(nr, (unsigned int *) (fsp), (unsigned int *) (fdp)) +__set_fd_set((nr)-1, (int *) (fsp), (int *) (fdp)) + +#define zero_fd_set(nr,fdp) \ +__zero_fd_set((nr)-1, (unsigned long *) (fdp)) /* * We can actually return ERESTARTSYS instead of EINTR, but I'd @@ -209,31 +236,41 @@ */ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp) { - int i; - fd_set res_in, in; - fd_set res_out, out; - fd_set res_ex, ex; + int error; + limited_fd_set res_in, in; + limited_fd_set res_out, out; + limited_fd_set res_ex, ex; unsigned long timeout; + error = -EINVAL; if (n < 0) - return -EINVAL; + goto out; if (n > NR_OPEN) n = NR_OPEN; - if ((i = get_fd_set(n, inp, &in)) || - (i = get_fd_set(n, outp, &out)) || - (i = get_fd_set(n, exp, &ex))) return i; + if ((error = get_fd_set(n, inp, &in)) || + (error = get_fd_set(n, outp, &out)) || + (error = get_fd_set(n, exp, &ex))) goto out; timeout = ~0UL; if (tvp) { - i = verify_area(VERIFY_WRITE, tvp, sizeof(*tvp)); - if (i) - return i; + error = verify_area(VERIFY_WRITE, tvp, sizeof(*tvp)); + if (error) + goto out; timeout = ROUND_UP(get_user(&tvp->tv_usec),(1000000/HZ)); timeout += get_user(&tvp->tv_sec) * (unsigned long) HZ; if (timeout) timeout += jiffies + 1; } + zero_fd_set(n, &res_in); + zero_fd_set(n, &res_out); + zero_fd_set(n, &res_ex); current->timeout = timeout; - i = do_select(n, &in, &out, &ex, &res_in, &res_out, &res_ex); + error = do_select(n, + (fd_set *) &in, + (fd_set *) &out, + (fd_set *) &ex, + (fd_set *) &res_in, + (fd_set *) &res_out, + (fd_set *) &res_ex); timeout = current->timeout - jiffies - 1; current->timeout = 0; if ((long) timeout < 0) @@ -244,12 +281,17 @@ timeout *= (1000000/HZ); put_user(timeout, &tvp->tv_usec); } - if (i < 0) - return i; - if (!i && (current->signal & ~current->blocked)) - return -ERESTARTNOHAND; + if (error < 0) + goto out; + if (!error) { + error = -ERESTARTNOHAND; + if (current->signal & ~current->blocked) + goto out; + error = 0; + } set_fd_set(n, inp, &res_in); set_fd_set(n, outp, &res_out); set_fd_set(n, exp, &res_ex); - return i; +out: + return error; } diff -u --recursive --new-file v2.0.1/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c --- v2.0.1/linux/fs/smbfs/proc.c Wed Jul 3 22:05:19 1996 +++ linux/fs/smbfs/proc.c Fri Jul 5 11:43:38 1996 @@ -3,6 +3,7 @@ * * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke * + * 28/06/96 - Fixed long file name support (smb_proc_readdir_long) by Yuri Per */ #include @@ -1152,6 +1153,7 @@ int info_level = 1; char *p; + char *lastname; int i; int first, total_count; struct smb_dirent *current_entry; @@ -1171,9 +1173,15 @@ int ff_dir_handle=0; int loop_count = 0; - int dirlen = strlen(SMB_FINFO(dir)->path); - char mask[dirlen + 5]; + int dirlen = strlen(SMB_FINFO(dir)->path) + 3; + char *mask; + mask = smb_kmalloc(dirlen, GFP_KERNEL); + if (mask == NULL) + { + printk("smb_proc_readdir_long: Memory allocation failed\n"); + return -ENOMEM; + } strcpy(mask, SMB_FINFO(dir)->path); strcat(mask, "\\*"); @@ -1297,22 +1305,37 @@ p = resp_data; /* we might need the lastname for continuations */ + lastname = ""; if (ff_lastname > 0) { switch(info_level) { case 260: - ff_resume_key =0; - strcpy(mask,p+ff_lastname+94); + lastname = p + ff_lastname + 94; + ff_resume_key = 0; break; case 1: - strcpy(mask,p + ff_lastname + 1); + lastname = p + ff_lastname + 1; ff_resume_key = 0; break; } } - else - strcpy(mask,""); + + /* Increase size of mask, if it is too small */ + i = strlen(lastname) + 1; + if (i > dirlen) + { + smb_kfree_s(mask, 0); + dirlen = i; + mask = smb_kmalloc(dirlen, GFP_KERNEL); + if (mask == NULL) + { + printk("smb_proc_readdir_long: Memory allocation failed\n"); + result = -ENOMEM; + break; + } + strcpy(mask, lastname); + } /* Now we are ready to parse smb directory entries. */ @@ -1355,6 +1378,9 @@ } finished: + if (mask != NULL) + smb_kfree_s(mask, 0); + if (resp_data != NULL) { smb_kfree_s(resp_data, 0); resp_data = NULL; diff -u --recursive --new-file v2.0.1/linux/include/asm-alpha/errno.h linux/include/asm-alpha/errno.h --- v2.0.1/linux/include/asm-alpha/errno.h Wed Jul 3 22:05:19 1996 +++ linux/include/asm-alpha/errno.h Thu Jul 4 07:28:57 1996 @@ -106,9 +106,9 @@ #define ENOANO 100 /* No anode */ #define EBADRQC 101 /* Invalid request code */ #define EBADSLT 102 /* Invalid slot */ -#if 0 -#define EDEADLOCK 103 /* File locking deadlock error */ -#endif + +#define EDEADLOCK EDEADLK + #define EBFONT 104 /* Bad font file format */ #define ENONET 105 /* Machine is not on the network */ #define ENOLINK 106 /* Link has been severed */ diff -u --recursive --new-file v2.0.1/linux/include/asm-alpha/posix_types.h linux/include/asm-alpha/posix_types.h --- v2.0.1/linux/include/asm-alpha/posix_types.h Fri Apr 5 13:35:28 1996 +++ linux/include/asm-alpha/posix_types.h Fri Jul 5 13:48:39 1996 @@ -74,18 +74,18 @@ #undef __FD_ZERO static __inline__ void __FD_ZERO(__kernel_fd_set *p) { - unsigned int *tmp = p->fds_bits; + unsigned long *tmp = p->fds_bits; int i; - if (__builtin_constant_p(__FDSET_INTS)) { - switch (__FDSET_INTS) { + if (__builtin_constant_p(__FDSET_LONGS)) { + switch (__FDSET_LONGS) { case 8: tmp[0] = 0; tmp[1] = 0; tmp[2] = 0; tmp[3] = 0; tmp[4] = 0; tmp[5] = 0; tmp[6] = 0; tmp[7] = 0; return; } } - i = __FDSET_INTS; + i = __FDSET_LONGS; while (i) { i--; *tmp = 0; diff -u --recursive --new-file v2.0.1/linux/include/asm-i386/errno.h linux/include/asm-i386/errno.h --- v2.0.1/linux/include/asm-i386/errno.h Wed Jul 3 22:05:19 1996 +++ linux/include/asm-i386/errno.h Thu Jul 4 07:28:57 1996 @@ -58,9 +58,9 @@ #define ENOANO 55 /* No anode */ #define EBADRQC 56 /* Invalid request code */ #define EBADSLT 57 /* Invalid slot */ -#if 0 -#define EDEADLOCK 58 /* File locking deadlock error */ -#endif + +#define EDEADLOCK EDEADLK + #define EBFONT 59 /* Bad font file format */ #define ENOSTR 60 /* Device not a stream */ #define ENODATA 61 /* No data available */ diff -u --recursive --new-file v2.0.1/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.0.1/linux/include/linux/fs.h Wed Jul 3 22:05:20 1996 +++ linux/include/linux/fs.h Fri Jul 5 18:24:23 1996 @@ -623,6 +623,8 @@ extern void insert_inode_hash(struct inode *); extern void clear_inode(struct inode *); extern struct inode * get_pipe_inode(void); +extern int get_unused_fd(void); +extern void put_unused_fd(int); extern struct file * get_empty_filp(void); extern int close_fp(struct file *filp); extern struct buffer_head * get_hash_table(kdev_t dev, int block, int size); diff -u --recursive --new-file v2.0.1/linux/include/linux/in.h linux/include/linux/in.h --- v2.0.1/linux/include/linux/in.h Tue May 7 16:22:38 1996 +++ linux/include/linux/in.h Fri Jul 5 15:10:58 1996 @@ -101,7 +101,7 @@ #define INADDR_BROADCAST ((unsigned long int) 0xffffffff) /* Address indicating an error return. */ -#define INADDR_NONE 0xffffffff +#define INADDR_NONE ((unsigned long int) 0xffffffff) /* Network number for local host loopback. */ #define IN_LOOPBACKNET 127 diff -u --recursive --new-file v2.0.1/linux/include/linux/posix_types.h linux/include/linux/posix_types.h --- v2.0.1/linux/include/linux/posix_types.h Wed Jul 3 22:05:20 1996 +++ linux/include/linux/posix_types.h Fri Jul 5 13:48:39 1996 @@ -27,22 +27,22 @@ * use the ones here. */ #undef __NFDBITS -#define __NFDBITS (8 * sizeof(unsigned int)) +#define __NFDBITS (8 * sizeof(unsigned long)) #undef __FD_SETSIZE #define __FD_SETSIZE 1024 -#undef __FDSET_INTS -#define __FDSET_INTS (__FD_SETSIZE/__NFDBITS) +#undef __FDSET_LONGS +#define __FDSET_LONGS (__FD_SETSIZE/__NFDBITS) #undef __FDELT #define __FDELT(d) ((d) / __NFDBITS) #undef __FDMASK -#define __FDMASK(d) (1 << ((d) % __NFDBITS)) +#define __FDMASK(d) (1UL << ((d) % __NFDBITS)) typedef struct { - unsigned int fds_bits [__FDSET_INTS]; + unsigned long fds_bits [__FDSET_LONGS]; } __kernel_fd_set; #include diff -u --recursive --new-file v2.0.1/linux/include/linux/sched.h linux/include/linux/sched.h --- v2.0.1/linux/include/linux/sched.h Mon Jun 3 16:46:58 1996 +++ linux/include/linux/sched.h Fri Jul 5 18:24:23 1996 @@ -108,19 +108,17 @@ asmlinkage void schedule(void); -/* ??? */ +/* Open file table structure */ struct files_struct { - /* ??? */ int count; - /* bit mask to close fds on exec */ fd_set close_on_exec; - /* do we have at most NR_OPEN available fds? I assume fd i maps into - * each open file */ + fd_set open_fds; struct file * fd[NR_OPEN]; }; #define INIT_FILES { \ 1, \ + { { 0, } }, \ { { 0, } }, \ { NULL, } \ } diff -u --recursive --new-file v2.0.1/linux/include/net/tcp.h linux/include/net/tcp.h --- v2.0.1/linux/include/net/tcp.h Tue May 21 19:52:38 1996 +++ linux/include/net/tcp.h Fri Jul 5 18:29:39 1996 @@ -174,22 +174,6 @@ extern void tcp_delack_timer(unsigned long); extern void tcp_retransmit_timer(unsigned long); -/* - * Default sequence number picking algorithm. - * As close as possible to RFC 793, which - * suggests using a 250kHz clock. - * Further reading shows this assumes 2MB/s networks. - * For 10MB/s ethernet, a 1MHz clock is appropriate. - * That's funny, Linux has one built in! Use it! - */ - -static inline u32 tcp_init_seq(void) -{ - struct timeval tv; - do_gettimeofday(&tv); - return tv.tv_usec+tv.tv_sec*1000000; -} - static __inline__ int tcp_old_window(struct sock * sk) { return sk->window - (sk->acked_seq - sk->lastwin_seq); diff -u --recursive --new-file v2.0.1/linux/kernel/exit.c linux/kernel/exit.c --- v2.0.1/linux/kernel/exit.c Wed Jul 3 22:05:20 1996 +++ linux/kernel/exit.c Fri Jul 5 13:48:39 1996 @@ -393,6 +393,26 @@ } } +static inline void close_files(struct files_struct * files) +{ + int i, j; + + j = 0; + for (;;) { + unsigned long set = files->open_fds.fds_bits[j]; + i = j * __NFDBITS; + j++; + if (i >= NR_OPEN) + break; + while (set) { + if (set & 1) + close_fp(files->fd[i]); + i++; + set >>= 1; + } + } +} + static inline void __exit_files(struct task_struct *tsk) { struct files_struct * files = tsk->files; @@ -400,14 +420,7 @@ if (files) { tsk->files = NULL; if (!--files->count) { - int i; - for (i=0 ; ifd[i]; - if (!filp) - continue; - files->fd[i] = NULL; - close_fp(filp); - } + close_files(files); kfree(files); } } diff -u --recursive --new-file v2.0.1/linux/kernel/fork.c linux/kernel/fork.c --- v2.0.1/linux/kernel/fork.c Wed Jul 3 22:05:20 1996 +++ linux/kernel/fork.c Thu Jul 4 20:09:41 1996 @@ -160,22 +160,33 @@ static inline int copy_files(unsigned long clone_flags, struct task_struct * tsk) { int i; + struct files_struct *oldf, *newf; + struct file **old_fds, **new_fds; + oldf = current->files; if (clone_flags & CLONE_FILES) { - current->files->count++; + oldf->count++; return 0; } - tsk->files = kmalloc(sizeof(*tsk->files), GFP_KERNEL); - if (!tsk->files) + + newf = kmalloc(sizeof(*newf), GFP_KERNEL); + tsk->files = newf; + if (!newf) return -1; - tsk->files->count = 1; - memcpy(&tsk->files->close_on_exec, ¤t->files->close_on_exec, - sizeof(tsk->files->close_on_exec)); - for (i = 0; i < NR_OPEN; i++) { - struct file * f = current->files->fd[i]; + + newf->count = 1; + newf->close_on_exec = oldf->close_on_exec; + newf->open_fds = oldf->open_fds; + + old_fds = oldf->fd; + new_fds = newf->fd; + for (i = NR_OPEN; i != 0; i--) { + struct file * f = *old_fds; + old_fds++; + *new_fds = f; + new_fds++; if (f) f->f_count++; - tsk->files->fd[i] = f; } return 0; } diff -u --recursive --new-file v2.0.1/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v2.0.1/linux/net/ipv4/af_inet.c Wed Jul 3 22:05:23 1996 +++ linux/net/ipv4/af_inet.c Fri Jul 5 18:17:12 1996 @@ -926,7 +926,7 @@ * Reuse ? */ - if (!sk2->dead) + if (!sk2->reuse || sk2->state==TCP_LISTEN) { sti(); return(-EADDRINUSE); diff -u --recursive --new-file v2.0.1/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.0.1/linux/net/ipv4/tcp.c Wed Jul 3 22:05:23 1996 +++ linux/net/ipv4/tcp.c Fri Jul 5 18:17:12 1996 @@ -202,6 +202,7 @@ * improvement. * Stefan Magdalinski : adjusted tcp_readable() to fix FIONREAD * Willy Konynenberg : Transparent proxying support. + * Theodore Ts'o : Do secure TCP sequence numbers. * * To Fix: * Fast path the code. Two things here - fix the window calculation @@ -427,6 +428,7 @@ #include #include #include +#include #include #include @@ -1886,6 +1888,36 @@ goto out; } +/* + * Check that a TCP address is unique, don't allow multiple + * connects to/from the same address + */ +static int tcp_unique_address(u32 saddr, u16 snum, u32 daddr, u16 dnum) +{ + int retval = 1; + struct sock * sk; + + /* Make sure we are allowed to connect here. */ + cli(); + for (sk = tcp_prot.sock_array[snum & (SOCK_ARRAY_SIZE -1)]; + sk != NULL; sk = sk->next) + { + /* hash collision? */ + if (sk->num != snum) + continue; + if (sk->saddr != saddr) + continue; + if (sk->daddr != daddr) + continue; + if (sk->dummy_th.dest != dnum) + continue; + retval = 0; + break; + } + sti(); + return retval; +} + /* * This will initiate an outgoing connection. @@ -1921,7 +1953,7 @@ * connect() to INADDR_ANY means loopback (BSD'ism). */ - if(usin->sin_addr.s_addr==INADDR_ANY) + if (usin->sin_addr.s_addr==INADDR_ANY) usin->sin_addr.s_addr=ip_my_addr(); /* @@ -1931,27 +1963,26 @@ if ((atype=ip_chk_addr(usin->sin_addr.s_addr)) == IS_BROADCAST || atype==IS_MULTICAST) return -ENETUNREACH; + if (!tcp_unique_address(sk->saddr, sk->num, usin->sin_addr.s_addr, usin->sin_port)) + return -EADDRNOTAVAIL; + lock_sock(sk); sk->daddr = usin->sin_addr.s_addr; - sk->write_seq = tcp_init_seq(); - sk->window_seq = sk->write_seq; - sk->rcv_ack_seq = sk->write_seq -1; + sk->rcv_ack_cnt = 1; sk->err = 0; sk->dummy_th.dest = usin->sin_port; - release_sock(sk); buff = sock_wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL); if (buff == NULL) { + release_sock(sk); return(-ENOMEM); } - lock_sock(sk); buff->sk = sk; buff->free = 0; buff->localroute = sk->localroute; - /* * Put in the IP header and routing stuff. */ @@ -1967,6 +1998,15 @@ if ((rt = sk->ip_route_cache) != NULL && !sk->saddr) sk->saddr = rt->rt_src; sk->rcv_saddr = sk->saddr; + + /* + * Set up our outgoing TCP sequence number + */ + sk->write_seq = secure_tcp_sequence_number(sk->saddr, sk->daddr, + sk->dummy_th.source, + usin->sin_port); + sk->window_seq = sk->write_seq; + sk->rcv_ack_seq = sk->write_seq -1; t1 = (struct tcphdr *) skb_put(buff,sizeof(struct tcphdr)); diff -u --recursive --new-file v2.0.1/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v2.0.1/linux/net/ipv4/tcp_input.c Wed Jul 3 22:05:23 1996 +++ linux/net/ipv4/tcp_input.c Thu Jul 4 12:54:01 1996 @@ -28,9 +28,12 @@ * Eric Schenk : Skip fast retransmit on small windows. * Eric schenk : Fixes to retransmission code to * : avoid extra retransmission. + * Theodore Ts'o : Do secure TCP sequence numbers. */ #include +#include +#include #include /* @@ -208,7 +211,17 @@ * from the far end, but sometimes it means the far end lost * an ACK we sent, so we better send an ACK. */ - tcp_send_ack(sk); + /* + * BEWARE! Unconditional answering by ack to out-of-window ack + * can result in infinite exchange of empty acks. + * This check cures bug, found by Michiel Boland, but + * not another possible cases. + * If we are in TCP_TIME_WAIT, we have already received + * FIN, so that our peer need not window update. If our + * ACK were lost, peer would retransmit his FIN anyway. --ANK + */ + if (sk->state != TCP_TIME_WAIT || ntohl(th->seq) != end_seq) + tcp_send_ack(sk); } /* @@ -1722,6 +1735,7 @@ struct tcphdr *th; struct sock *sk; int syn_ok=0; + __u32 seq; #ifdef CONFIG_IP_TRANSPARENT_PROXY int r; #endif @@ -1859,10 +1873,12 @@ } /* - * Guess we need to make a new socket up + * Guess we need to make a new socket up */ - - tcp_conn_request(sk, skb, daddr, saddr, opt, dev, tcp_init_seq()); + seq = secure_tcp_sequence_number(saddr, daddr, + skb->h.th->dest, + skb->h.th->source); + tcp_conn_request(sk, skb, daddr, saddr, opt, dev, seq); /* * Now we have several options: In theory there is nothing else diff -u --recursive --new-file v2.0.1/linux/net/socket.c linux/net/socket.c --- v2.0.1/linux/net/socket.c Wed Jul 3 22:05:23 1996 +++ linux/net/socket.c Thu Jul 4 21:26:25 1996 @@ -172,36 +172,31 @@ static int get_fd(struct inode *inode) { int fd; - struct file *file; /* * Find a file descriptor suitable for return to the user. */ - file = get_empty_filp(); - if (!file) - return(-1); + fd = get_unused_fd(); + if (fd >= 0) { + struct file *file = get_empty_filp(); - for (fd = 0; fd < NR_OPEN; ++fd) - if (!current->files->fd[fd]) - break; - if (fd == NR_OPEN) - { - file->f_count = 0; - return(-1); - } + if (!file) { + put_unused_fd(fd); + return -ENFILE; + } - FD_CLR(fd, ¤t->files->close_on_exec); current->files->fd[fd] = file; - file->f_op = &socket_file_ops; - file->f_mode = 3; - file->f_flags = O_RDWR; - file->f_count = 1; - file->f_inode = inode; - if (inode) - inode->i_count++; - file->f_pos = 0; - return(fd); + file->f_op = &socket_file_ops; + file->f_mode = 3; + file->f_flags = O_RDWR; + file->f_count = 1; + file->f_inode = inode; + if (inode) + inode->i_count++; + file->f_pos = 0; + } + return fd; } diff -u --recursive --new-file v2.0.1/linux/net/unix/af_unix.c linux/net/unix/af_unix.c --- v2.0.1/linux/net/unix/af_unix.c Fri May 17 15:32:21 1996 +++ linux/net/unix/af_unix.c Fri Jul 5 16:57:33 1996 @@ -710,10 +710,9 @@ int num=cmsg->cmsg_len-sizeof(struct cmsghdr); int i; int *fdp=(int *)cmsg->cmsg_data; - num/=4; /* Odd bytes are forgotten in BSD not errored */ - - if(num>=UNIX_MAX_FD) + num /= sizeof(int); /* Odd bytes are forgotten in BSD not errored */ + if (num >= UNIX_MAX_FD) return -EINVAL; /* @@ -728,9 +727,9 @@ #if 0 printk("testing fd %d\n", fd); #endif - if(fd < 0|| fd >=NR_OPEN) + if (fd < 0 || fd >= NR_OPEN) return -EBADF; - if(current->files->fd[fd]==NULL) + if (current->files->fd[fd]==NULL) return -EBADF; } @@ -759,30 +758,6 @@ } } -/* - * Count the free descriptors available to a process. - * Interpretation issue: Is the limit the highest descriptor (buggy - * allowing passed fd's higher up to cause a limit to be exceeded) - - * but how the old code did it - or like this... - */ - -static int unix_files_free(void) -{ - int i; - int n=0; - for (i=0;ifiles->fd[i]) - n++; - } - - i=NR_OPEN; - if(i>current->rlim[RLIMIT_NOFILE].rlim_cur) - i=current->rlim[RLIMIT_NOFILE].rlim_cur; - if(n>=i) - return 0; - return i-n; -} /* * Perform the AF_UNIX file descriptor pass out functionality. This @@ -795,50 +770,39 @@ /* count of space in parent for fds */ int cmnum; struct file **fp; - struct file **ufp; - int *cmfptr=NULL; /* =NULL To keep gcc happy */ - /* number of fds actually passed */ + int *cmfptr; int fdnum; - int ffree; - int ufn=0; - if(cmsg==NULL) - cmnum=0; - else - { - cmnum=cmsg->cmsg_len-sizeof(struct cmsghdr); - cmnum/=sizeof(int); - cmfptr=(int *)&cmsg->cmsg_data; + cmfptr = NULL; + cmnum = 0; + if (cmsg) + { + cmnum = (cmsg->cmsg_len-sizeof(struct cmsghdr)) / sizeof(int); + cmfptr = (int *)&cmsg->cmsg_data; } - memcpy(&fdnum,skb->h.filp,sizeof(int)); - fp=(struct file **)(skb->h.filp+sizeof(int)); - if(cmnum>fdnum) - cmnum=fdnum; - ffree=unix_files_free(); - if(cmnum>ffree) - cmnum=ffree; - ufp=¤t->files->fd[0]; - + fdnum = *(int *)skb->h.filp; + fp = (struct file **)(skb->h.filp+sizeof(long)); + + if (cmnum > fdnum) + cmnum = fdnum; + /* * Copy those that fit */ - for(i=0;ifiles->close_on_exec); + int new_fd = get_unused_fd(); + if (new_fd < 0) + break; + current->files->fd[new_fd]=fp[i]; + *cmfptr++ = new_fd; unix_notinflight(fp[i]); } /* * Dump those that don't */ - for(;ih.filp=kmalloc(sizeof(int)+fpnum*sizeof(struct file *), + skb->h.filp = kmalloc(sizeof(long)+fpnum*sizeof(struct file *), GFP_KERNEL); /* number of descriptors starts block */ - memcpy(skb->h.filp,&fpnum,sizeof(int)); + *(int *)skb->h.filp = fpnum; /* actual descriptors */ - memcpy(skb->h.filp+sizeof(int),fp,fpnum*sizeof(struct file *)); + memcpy(skb->h.filp+sizeof(long),fp,fpnum*sizeof(struct file *)); skb->destructor = unix_destruct_fds; }