diff -Nur linux-2.4.20-quota-ctx/kernel/signal.c linux-2.4.20/kernel/signal.c --- s/kernel/signal.c 2000-00-00 00:00:00.000000000 +0000 +++ e/kernel/signal.c 2000-00-00 00:00:00.000000000 +0000 @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -1351,18 +1352,259 @@ return 0; } +//------------------------------------------------------------------ + +// ToDo: +// List (c|sh)ould be replaced by hash +// Need to profile to assess the situation + +static LIST_HEAD( ctx_names ); + +#define MAX_CTX_NAME 32 + +struct ctx_name +{ + struct list_head list_entry; + int ctx; + char name[ MAX_CTX_NAME + 1]; +}; + +static void* ctx_names_clicker = 0; // void * to avoid having to cast + // when stored in filp->private_data + +//------------------------------------------------------------------ + +struct ctx_name * +__find_pcn_by_name( char * name ) +{ + struct list_head *p = ctx_names.next; + struct ctx_name *pcn; + for( ; p!=&ctx_names; p=p->next ) { + pcn = list_entry(p, struct ctx_name, list_entry); + if( !strcmp(pcn->name, name) ) + return pcn; + } + return NULL; +} + +//------------------------------------------------------------------ + +struct ctx_name * +__find_pcn_by_ctx( int ctx ) +{ + struct list_head *p = ctx_names.next; + struct ctx_name *pcn; + for( ; p!=&ctx_names; p=p->next ) { + pcn = list_entry(p, struct ctx_name, list_entry); + if( pcn->ctx == ctx) + return pcn; + } + return NULL; +} + +//------------------------------------------------------------------ + +int +get_ctx_from_name( char * name ) +{ + struct ctx_name * pcn = __find_pcn_by_name( name ); + if( pcn ) + return pcn->ctx; + + return 0; +} + +//------------------------------------------------------------------ + +char * +get_name_from_ctx_buf( int ctx, char *to ) +{ + struct ctx_name * pcn = __find_pcn_by_ctx( ctx ); + if( pcn ) { + strcpy(to, pcn->name ); + return to; + } + + return NULL; +} + +//------------------------------------------------------------------ + +char * +get_name_from_ctx( int ctx ) +{ + struct ctx_name * pcn = __find_pcn_by_ctx( ctx ); + if( pcn && pcn->name[0] ) + return pcn->name; + + return NULL; +} + +//------------------------------------------------------------------ + +int +register_ctx_name( int ctx, char * name ) +{ + struct ctx_name * pcn = __find_pcn_by_name( name ); + if( pcn == NULL ) { + pcn = kmalloc(sizeof(struct ctx_name), GFP_KERNEL); + if( pcn ) { + strcpy( pcn->name, name ); + pcn->ctx = ctx; + ++ctx_names_clicker; + list_add_tail( &pcn->list_entry, &ctx_names ); + return 0; + } + } + + return -1; +} + +//------------------------------------------------------------------ + +int +re_register_ctx_name( int ctx_old, int ctx_new ) +{ + struct ctx_name * pcn = __find_pcn_by_ctx( ctx_old ); + if( pcn ) { + ++ctx_names_clicker; + pcn->ctx = ctx_new; + return 0; + } + + return -1; +} + +//------------------------------------------------------------------ + +void +unregister_ctx_name( char * name ) +{ + struct ctx_name * pcn = __find_pcn_by_name( name ); + if( !pcn ) + { + ++ctx_names_clicker; + list_del( &pcn->list_entry ); + kfree( pcn ); + } +} + +//------------------------------------------------------------------ + +// Implementation for /proc/kernel/ctx/names + +int proc_ctx_names(ctl_table *ctl, int write, struct file * filp, void *buffer_in, size_t *lenp) +{ + int ret = 0; + + if( !write ) { + size_t len = *lenp; + size_t total = 0, section = 0; + + if( filp->private_data == 0 || // First section or + filp->private_data == ctx_names_clicker ){ // no change in data + struct list_head *ph = ctx_names.next; + struct ctx_name *pcn; + const int LINE_SIZE = 63; + char line[LINE_SIZE+1]; + + char * buffer = kmalloc( len, GFP_KERNEL ); + + if( !buffer ) + return -ENOMEM; + + for( ; ph!=&ctx_names; ph=ph->next ) { + pcn = list_entry(ph, struct ctx_name, list_entry); + if( pcn ) { + int add = snprintf( line, LINE_SIZE, "%d %s\n", pcn->ctx, pcn->name ); + + if( add ) { + if( total + add <= filp->f_pos ) // Don't retread old ground + total += add; + else { + if( section + add <= len ) { + strcpy(buffer + section, line); + section += add; + total += add; + } + else { + // More data to suck, but label to avoid smudging + if( !filp->private_data ) + filp->private_data = ctx_names_clicker; + break; + } + } + } + else { + printk( KERN_WARNING "proc_ctx_names sprint failed\n" ); + break; + } + } + } + + if( section && copy_to_user(buffer_in, buffer, section) ) + ret = -EFAULT; + + kfree( buffer ); + + *lenp = section; // *lenp is non-error case return value of sys_read + filp->f_pos += section; + } + else + ret = -EUCLEAN; // Data changed + } + + return ret; +} + +//------------------------------------------------------------------ + /* Change to a new security context and reduce the capability basic set of the current process */ asmlinkage int -sys_new_s_context(int ctx, __u32 remove_cap, int flags) +sys_new_s_context(int ctx, __u32 remove_cap, int flags, char * name ) { #define MAX_S_CONTEXT 65535 /* Arbitrary limit */ int ret = -EPERM; + int ctx_from_name = 0; + + if( name ) { + if( strlen(name) > MAX_CTX_NAME ) { + printk( KERN_ERR "'%s' too long in sys_new_s_context() call (max: %d)\n", name, MAX_CTX_NAME ); + return -EINVAL; + } + + ctx_from_name = get_ctx_from_name(name); + + if( ctx == 0 ) { + if( ctx_from_name == 0 ) { + printk( KERN_ERR "Can't find a live '%s' to enter\n", name ); + return -ECHILD; + } + + ctx = ctx_from_name; + } + } + if (ctx == -1){ if (current->s_info == NULL || (current->s_info->flags & S_CTX_INFO_LOCK) == 0){ + + if( ctx_from_name ) { + struct task_struct *p; + read_lock(&tasklist_lock); + for_each_task(p) { + if( p->s_context == ctx_from_name ){ + read_unlock(&tasklist_lock); + printk( KERN_ERR "Can't reuse context name '%s' whilst it's still in use\n", name ); + return -EBUSY; + } + } + read_unlock(&tasklist_lock); + } + /* Ok we allocate a new context. For now, we just increase */ /* it. Wrap around possible, so we loop */ static int alloc_ctx=1; @@ -1372,7 +1614,7 @@ int found = 0; struct task_struct *p; alloc_ctx++; - /* The s_context 1 is special. It sess all processes */ + /* The s_context 1 is special. It sees all processes */ if (alloc_ctx == 1){ alloc_ctx++; }else if (alloc_ctx > MAX_S_CONTEXT){ @@ -1390,8 +1632,16 @@ read_unlock(&tasklist_lock); if (!found) break; } + ret = switch_user_struct(alloc_ctx); if (ret == 0) { + if( name ){ + if( ctx_from_name ) + re_register_ctx_name( ctx_from_name, alloc_ctx ); + else + register_ctx_name( alloc_ctx, name ); + } + current->s_context = alloc_ctx; current->cap_bset &= (~remove_cap); ret = alloc_ctx; @@ -1416,47 +1666,55 @@ current->s_info->flags |= flags; } } - }else if (ctx <= 0 || ctx > MAX_S_CONTEXT){ - ret = -EINVAL; - }else if (current->s_context == 0 - && capable(CAP_SYS_ADMIN) - && (current->s_info == NULL - ||(current->s_info->flags & S_CTX_INFO_LOCK) == 0)){ - /* The root context can become any context it wants */ - int found = 0; - struct task_struct *p; - /* Check if in use so we reuse the same context_info */ - read_lock(&tasklist_lock); - ret = ctx; - for_each_task(p) { - if (p->s_context == ctx){ - found = 1; - if (p->s_info == NULL - || (p->s_info->flags & S_CTX_INFO_PRIVATE)==0){ - sys_release_s_info(current); - sys_assign_s_info (p); - current->s_info = p->s_info; - }else{ - ret = -EPERM; + } + else + { + if( ctx_from_name ) + ctx = ctx_from_name; + + if (ctx <= 0 || ctx > MAX_S_CONTEXT){ + ret = -EINVAL; + }else if (current->s_context == 0 + && capable(CAP_SYS_ADMIN) + && (current->s_info == NULL + || (current->s_info->flags & S_CTX_INFO_LOCK) == 0)){ + /* The root context can become any context it wants */ + int found = 0; + struct task_struct *p; + /* Check if in use so we reuse the same context_info */ + read_lock(&tasklist_lock); + ret = ctx; + for_each_task(p) { + if (p->s_context == ctx){ + found = 1; + if (p->s_info == NULL + || (p->s_info->flags & S_CTX_INFO_PRIVATE)==0){ + sys_release_s_info(current); + sys_assign_s_info (p); + current->s_info = p->s_info; + }else{ + ret = -EPERM; + } } break; } - } - read_unlock(&tasklist_lock); - if (ret == ctx) { - ret = switch_user_struct(ctx); - if (ret == 0) { - current->s_context = ctx; - current->cap_bset &= (~remove_cap); - if (!found) { - sys_alloc_s_info(); - } - if (current->s_info != NULL) { - current->s_info->flags |= flags; + read_unlock(&tasklist_lock); + if (ret == ctx) { + ret = switch_user_struct(ctx); + if (ret == 0) { + current->s_context = ctx; + current->cap_bset &= (~remove_cap); + if (!found) { + sys_alloc_s_info(); + } + if (current->s_info != NULL) { + current->s_info->flags |= flags; + } } } } } + return ret; } diff -Nur somewhere/kernel/sysctl.c erehwemos/kernel/sysctl.c --- 1/kernel/sysctl.c 2003-02-24 18:46:04.000000000 +0000 +++ 2/kernel/sysctl.c 2003-02-24 18:45:12.000000000 +0000 @@ -91,9 +91,13 @@ enum { CTX_SYSCTRL_CTX_PLACEHOLDER = 0, + CTX_SYSCTRL_CTX_NAMES=1, // string: info on context names }; +extern proc_handler proc_ctx_names; + static ctl_table ctx_table[] = { + {CTX_SYSCTRL_CTX_NAMES,"names", NULL,0,0444,NULL,&proc_ctx_names}, {0} }; #endif diff -Nur old/fs/proc/array.c new/fs/proc/array.c --- old/fs/proc/array.c 2003-04-01 11:30:20.000000000 +0100 +++ new/fs/proc/array.c 2003-04-01 11:04:55.000000000 +0100 @@ -279,6 +279,8 @@ cap_t(p->cap_bset)); } +char * +get_name_from_ctx( int ctx ); int proc_pid_status(struct task_struct *task, char * buffer) { @@ -313,6 +315,8 @@ } *buffer++ = ']'; *buffer++ = '\n'; + char * ctxname = get_name_from_ctx( task->s_context ); + buffer += sprintf (buffer,"ctxname: %s\n", ctxname?ctxname:"" ); buffer += sprintf (buffer,"ctxticks: %d %ld %d\n" ,atomic_read(&task->s_info->ticks),task->counter ,task->s_info->refcount);