@@ -123,6 +123,7 @@ static const int NR_TYPES = ARRAY_SIZE(max_vals);
123
123
static struct input_handler kbd_handler ;
124
124
static DEFINE_SPINLOCK (kbd_event_lock );
125
125
static DEFINE_SPINLOCK (led_lock );
126
+ static DEFINE_SPINLOCK (func_buf_lock ); /* guard 'func_buf' and friends */
126
127
static unsigned long key_down [BITS_TO_LONGS (KEY_CNT )]; /* keyboard key bitmap */
127
128
static unsigned char shift_down [NR_SHIFT ]; /* shift state counters.. */
128
129
static bool dead_key_next ;
@@ -1990,11 +1991,12 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
1990
1991
char * p ;
1991
1992
u_char * q ;
1992
1993
u_char __user * up ;
1993
- int sz ;
1994
+ int sz , fnw_sz ;
1994
1995
int delta ;
1995
1996
char * first_free , * fj , * fnw ;
1996
1997
int i , j , k ;
1997
1998
int ret ;
1999
+ unsigned long flags ;
1998
2000
1999
2001
if (!capable (CAP_SYS_TTY_CONFIG ))
2000
2002
perm = 0 ;
@@ -2037,18 +2039,27 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
2037
2039
goto reterr ;
2038
2040
}
2039
2041
2042
+ fnw = NULL ;
2043
+ fnw_sz = 0 ;
2044
+ /* race aginst other writers */
2045
+ again :
2046
+ spin_lock_irqsave (& func_buf_lock , flags );
2040
2047
q = func_table [i ];
2048
+
2049
+ /* fj pointer to next entry after 'q' */
2041
2050
first_free = funcbufptr + (funcbufsize - funcbufleft );
2042
2051
for (j = i + 1 ; j < MAX_NR_FUNC && !func_table [j ]; j ++ )
2043
2052
;
2044
2053
if (j < MAX_NR_FUNC )
2045
2054
fj = func_table [j ];
2046
2055
else
2047
2056
fj = first_free ;
2048
-
2057
+ /* buffer usage increase by new entry */
2049
2058
delta = (q ? - strlen (q ) : 1 ) + strlen (kbs -> kb_string );
2059
+
2050
2060
if (delta <= funcbufleft ) { /* it fits in current buf */
2051
2061
if (j < MAX_NR_FUNC ) {
2062
+ /* make enough space for new entry at 'fj' */
2052
2063
memmove (fj + delta , fj , first_free - fj );
2053
2064
for (k = j ; k < MAX_NR_FUNC ; k ++ )
2054
2065
if (func_table [k ])
@@ -2061,20 +2072,28 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
2061
2072
sz = 256 ;
2062
2073
while (sz < funcbufsize - funcbufleft + delta )
2063
2074
sz <<= 1 ;
2064
- fnw = kmalloc (sz , GFP_KERNEL );
2065
- if (!fnw ) {
2066
- ret = - ENOMEM ;
2067
- goto reterr ;
2075
+ if (fnw_sz != sz ) {
2076
+ spin_unlock_irqrestore (& func_buf_lock , flags );
2077
+ kfree (fnw );
2078
+ fnw = kmalloc (sz , GFP_KERNEL );
2079
+ fnw_sz = sz ;
2080
+ if (!fnw ) {
2081
+ ret = - ENOMEM ;
2082
+ goto reterr ;
2083
+ }
2084
+ goto again ;
2068
2085
}
2069
2086
2070
2087
if (!q )
2071
2088
func_table [i ] = fj ;
2089
+ /* copy data before insertion point to new location */
2072
2090
if (fj > funcbufptr )
2073
2091
memmove (fnw , funcbufptr , fj - funcbufptr );
2074
2092
for (k = 0 ; k < j ; k ++ )
2075
2093
if (func_table [k ])
2076
2094
func_table [k ] = fnw + (func_table [k ] - funcbufptr );
2077
2095
2096
+ /* copy data after insertion point to new location */
2078
2097
if (first_free > fj ) {
2079
2098
memmove (fnw + (fj - funcbufptr ) + delta , fj , first_free - fj );
2080
2099
for (k = j ; k < MAX_NR_FUNC ; k ++ )
@@ -2087,7 +2106,9 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
2087
2106
funcbufleft = funcbufleft - delta + sz - funcbufsize ;
2088
2107
funcbufsize = sz ;
2089
2108
}
2109
+ /* finally insert item itself */
2090
2110
strcpy (func_table [i ], kbs -> kb_string );
2111
+ spin_unlock_irqrestore (& func_buf_lock , flags );
2091
2112
break ;
2092
2113
}
2093
2114
ret = 0 ;
0 commit comments