Bug #75790 memcahced SET command accepts negative values for expire time
Submitted: 5 Feb 2015 10:08 Modified: 23 Mar 2015 14:11
Reporter: Umesh Shastry Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Memcached Severity:S2 (Serious)
Version:5.7.6, 5.6.24 OS:Any
Assigned to: CPU Architecture:Any

[5 Feb 2015 10:08] Umesh Shastry
Description:
Observed that SET command accepts negative values for expire time

How to repeat:
// 5.7.6
// Build used

commit: 1d5409f947189064bafdbd6c437640fe690ebbbd
date: 2015-02-04 15:27:26 +0100
build-date: 2015-02-04 17:04:31 +0100
short: 1d5409f
branch: mysql-trunk

MySQL source 5.7.6

[umshastr@hod03]/export/umesh/mysql-5.7.6: bin/mysql -uroot -p -S /tmp/mysql_ushastry.sock < share/innodb_memcached_config.sql
Enter password:
[umshastr@hod03]/export/umesh/mysql-5.7.6: bin/mysql -uroot -p -S /tmp/mysql_ushastry.sock
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 19
Server version: 5.7.6-m16-enterprise-commercial-advanced MySQL Enterprise Server - Advanced Edition (Commercial)

Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> install plugin daemon_memcached soname "libmemcached.so";
Query OK, 0 rows affected (0.00 sec)

mysql> update innodb_memcache.cache_policies set get_policy='cache_only',set_policy='cache_only',delete_policy='cache_only',flush_policy='cache_only';                                            Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> uninstall plugin daemon_memcached;
Query OK, 0 rows affected (2.00 sec)

mysql> install plugin daemon_memcached soname "libmemcached.so";
Query OK, 0 rows affected (0.00 sec)

mysql> select * from innodb_memcache.cache_policies;
+--------------+------------+------------+---------------+--------------+
| policy_name  | get_policy | set_policy | delete_policy | flush_policy |
+--------------+------------+------------+---------------+--------------+
| cache_policy | cache_only | cache_only | cache_only    | cache_only   |
+--------------+------------+------------+---------------+--------------+
1 row in set (0.00 sec)

## telnet session confirms that SET command accepts negative values for expire time column

[umshastr@hod03]~: telnet localhost 11211
Trying ::1...
Connected to localhost.
Escape character is '^]'.
set k 0 -60 1
v
STORED
get k
VALUE k 0 1
v
END
set k 0 -90000 1
v
STORED
get k
VALUE k 0 1
v
END

// cache_policy Innodb only

mysql> update innodb_memcache.cache_policies set get_policy='innodb_only',set_policy='innodb_only',delete_policy='innodb_only',flush_policy='innodb_only';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> uninstall plugin daemon_memcached;
Query OK, 0 rows affected (2.01 sec)

mysql> install plugin daemon_memcached soname "libmemcached.so";
Query OK, 0 rows affected (0.00 sec)

mysql> select * from innodb_memcache.cache_policies;
+--------------+-------------+-------------+---------------+--------------+
| policy_name  | get_policy  | set_policy  | delete_policy | flush_policy |
+--------------+-------------+-------------+---------------+--------------+
| cache_policy | innodb_only | innodb_only | innodb_only   | innodb_only  |
+--------------+-------------+-------------+---------------+--------------+
1 row in set (0.00 sec)

## telnet session confirms that SET command accepts negative values for expire time column

[umshastr@hod03]~: telnet localhost 11211
Trying ::1...
Connected to localhost.
Escape character is '^]'.
set k 0 -60 1
v
STORED
get k
VALUE k 0 1
v
END
set k 0 -25000000 1
v
STORED
get k
VALUE k 0 1
v
END

// CLI session

mysql> select * from test.demo_test;
+----+--------------+------+------+-----------+
| c1 | c2           | c3   | c4   | c5        |
+----+--------------+------+------+-----------+
| AA | HELLO, HELLO |    8 |    0 |         0 |
| k  | v            |    0 |    2 | -25000000 |
+----+--------------+------+------+-----------+
2 rows in set (0.00 sec)

Suggested fix:
We can not expect that expiration will happen in the past and hence negative values should not be allowed to set
[13 Feb 2015 8:38] MySQL Verification Team
// with 5.6.24

// from CLI session ( cache only policy)

[umshastr@hod03]/export/umesh/mysql-5.6.24: bin/mysql -uroot -p  -S /tmp/mysql_ushastry.sock < share/innodb_memcached_config.sql
Enter password:
[umshastr@hod03]/export/umesh/mysql-5.6.24: bin/mysql -uroot -p  -S /tmp/mysql_ushastry.sock
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 15
Server version: 5.6.24-enterprise-commercial-advanced MySQL Enterprise Server - Advanced Edition (Commercial)

Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> install plugin daemon_memcached soname "libmemcached.so";
Query OK, 0 rows affected (0.00 sec)

mysql> update innodb_memcache.cache_policies set get_policy='cache_only',set_policy='cache_only',delete_policy='cache_only',flush_policy='cache_only';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> uninstall plugin daemon_memcached;
Query OK, 0 rows affected (2.00 sec)

mysql> install plugin daemon_memcached soname "libmemcached.so";
Query OK, 0 rows affected (0.00 sec)

mysql> select * from innodb_memcache.cache_policies;
+--------------+------------+------------+---------------+--------------+
| policy_name  | get_policy | set_policy | delete_policy | flush_policy |
+--------------+------------+------------+---------------+--------------+
| cache_policy | cache_only | cache_only | cache_only    | cache_only   |
+--------------+------------+------------+---------------+--------------+
1 row in set (0.00 sec)

// from telnet session

[umshastr@hod03]/export/umesh/mysql-5.7.6: telnet localhost 11211
Trying ::1...
Connected to localhost.
Escape character is '^]'.
set k 0 -60 1
v
STORED
get k
VALUE k 0 1
v
END
set k 0 -90000 1
v
STORED
get k
VALUE k 0 1
v
END

//  ( with innodb only policy)

mysql> update innodb_memcache.cache_policies set get_policy='innodb_only',set_policy='innodb_only',delete_policy='innodb_only',flush_policy='innodb_only';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> uninstall plugin daemon_memcached;
Query OK, 0 rows affected (2.00 sec)

mysql> install plugin daemon_memcached soname "libmemcached.so";
Query OK, 0 rows affected (0.00 sec)

mysql>  select * from innodb_memcache.cache_policies;
+--------------+-------------+-------------+---------------+--------------+
| policy_name  | get_policy  | set_policy  | delete_policy | flush_policy |
+--------------+-------------+-------------+---------------+--------------+
| cache_policy | innodb_only | innodb_only | innodb_only   | innodb_only  |
+--------------+-------------+-------------+---------------+--------------+
1 row in set (0.00 sec)

[umshastr@hod03]/export/umesh/mysql-5.7.6:  telnet localhost 11211
Trying ::1...
Connected to localhost.
Escape character is '^]'.
set k 0 -60 1
v
STORED
get k
VALUE k 0 1
v
END
set k 0 -25000000 1
v
STORED
get k
VALUE k 0 1
v
END

// from cli

mysql> select * from test.demo_test;
+----+--------------+------+------+-----------+
| c1 | c2           | c3   | c4   | c5        |
+----+--------------+------+------+-----------+
| AA | HELLO, HELLO |    8 |    0 |         0 |
| k  | v            |    0 |    4 | -25000000 |
+----+--------------+------+------+-----------+
2 rows in set (0.00 sec)
[23 Feb 2015 11:26] MySQL Verification Team
Confirmed that 5.6 is also affected(included 5.6.24 in version).

Thanks,
Umesh
[23 Mar 2015 14:11] Daniel Price
Posted by developer:
 
Fixed as of the upcoming 5.6.25, 5.7.8, 5.8.0 releases, and here's the changelog entry:

The "memcached" "set" command permitted a negative expire time value.
Expire time is stored internally as an unsigned integer. A negative value
would be converted to a large number and accepted. The maximum expire time
value is now restricted to "INT_MAX32" to prevent negative expire time
values. 

Thank you for the bug report.
[23 Mar 2015 14:11] Daniel Price
Fixed as of the upcoming 5.6.25, 5.7.8, 5.8.0 releases, and here's the changelog entry:

The "memcached" "set" command permitted a negative expire time value.
Expire time is stored internally as an unsigned integer. A negative value
would be converted to a large number and accepted. The maximum expire time
value is now restricted to "INT_MAX32" to prevent negative expire time
values. 

Thank you for the bug report.
[23 Jun 2015 16:20] Laurynas Biveinis
commit 159be46cef763c5ed283cc7c2462e04336114ca2
Author: aditya <aditya.a@oracle.com>
Date:   Fri Mar 20 15:28:02 2015 +0530

    Bug #20478242    MEMCAHCED SET COMMAND ACCEPTS NEGATIVE VALUES FOR EXPIRE TIME
    
    PROBLEM
    
    Inside memcached server the expire time is stored as unsigned int,so when the
    user gives a negative value it is converted to a large number and is accepted.
    
    FIX
    
    Simple and easy fix is to restrict the maximum value of expire time to INT_MAX32
    since any negative value will be greater than this and we can reject it.
    
    Also removed useless assert in  innodb_flush_sync_conn() function