aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/sem.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/sem.c')
-rw-r--r--ipc/sem.c344
1 files changed, 228 insertions, 116 deletions
diff --git a/ipc/sem.c b/ipc/sem.c
index 013c7981f3c7..f7385bce5fd3 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -512,7 +512,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
512 INIT_LIST_HEAD(&sma->pending_const); 512 INIT_LIST_HEAD(&sma->pending_const);
513 INIT_LIST_HEAD(&sma->list_id); 513 INIT_LIST_HEAD(&sma->list_id);
514 sma->sem_nsems = nsems; 514 sma->sem_nsems = nsems;
515 sma->sem_ctime = get_seconds(); 515 sma->sem_ctime = ktime_get_real_seconds();
516 516
517 retval = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni); 517 retval = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
518 if (retval < 0) { 518 if (retval < 0) {
@@ -1163,14 +1163,14 @@ static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in,
1163 } 1163 }
1164} 1164}
1165 1165
1166static time_t get_semotime(struct sem_array *sma) 1166static time64_t get_semotime(struct sem_array *sma)
1167{ 1167{
1168 int i; 1168 int i;
1169 time_t res; 1169 time64_t res;
1170 1170
1171 res = sma->sems[0].sem_otime; 1171 res = sma->sems[0].sem_otime;
1172 for (i = 1; i < sma->sem_nsems; i++) { 1172 for (i = 1; i < sma->sem_nsems; i++) {
1173 time_t to = sma->sems[i].sem_otime; 1173 time64_t to = sma->sems[i].sem_otime;
1174 1174
1175 if (to > res) 1175 if (to > res)
1176 res = to; 1176 res = to;
@@ -1178,112 +1178,95 @@ static time_t get_semotime(struct sem_array *sma)
1178 return res; 1178 return res;
1179} 1179}
1180 1180
1181static int semctl_nolock(struct ipc_namespace *ns, int semid, 1181static int semctl_stat(struct ipc_namespace *ns, int semid,
1182 int cmd, int version, void __user *p) 1182 int cmd, struct semid64_ds *semid64)
1183{ 1183{
1184 int err;
1185 struct sem_array *sma; 1184 struct sem_array *sma;
1185 int id = 0;
1186 int err;
1186 1187
1187 switch (cmd) { 1188 memset(semid64, 0, sizeof(*semid64));
1188 case IPC_INFO:
1189 case SEM_INFO:
1190 {
1191 struct seminfo seminfo;
1192 int max_id;
1193
1194 err = security_sem_semctl(NULL, cmd);
1195 if (err)
1196 return err;
1197 1189
1198 memset(&seminfo, 0, sizeof(seminfo)); 1190 rcu_read_lock();
1199 seminfo.semmni = ns->sc_semmni; 1191 if (cmd == SEM_STAT) {
1200 seminfo.semmns = ns->sc_semmns; 1192 sma = sem_obtain_object(ns, semid);
1201 seminfo.semmsl = ns->sc_semmsl; 1193 if (IS_ERR(sma)) {
1202 seminfo.semopm = ns->sc_semopm; 1194 err = PTR_ERR(sma);
1203 seminfo.semvmx = SEMVMX; 1195 goto out_unlock;
1204 seminfo.semmnu = SEMMNU; 1196 }
1205 seminfo.semmap = SEMMAP; 1197 id = sma->sem_perm.id;
1206 seminfo.semume = SEMUME; 1198 } else {
1207 down_read(&sem_ids(ns).rwsem); 1199 sma = sem_obtain_object_check(ns, semid);
1208 if (cmd == SEM_INFO) { 1200 if (IS_ERR(sma)) {
1209 seminfo.semusz = sem_ids(ns).in_use; 1201 err = PTR_ERR(sma);
1210 seminfo.semaem = ns->used_sems; 1202 goto out_unlock;
1211 } else {
1212 seminfo.semusz = SEMUSZ;
1213 seminfo.semaem = SEMAEM;
1214 } 1203 }
1215 max_id = ipc_get_maxid(&sem_ids(ns));
1216 up_read(&sem_ids(ns).rwsem);
1217 if (copy_to_user(p, &seminfo, sizeof(struct seminfo)))
1218 return -EFAULT;
1219 return (max_id < 0) ? 0 : max_id;
1220 } 1204 }
1221 case IPC_STAT:
1222 case SEM_STAT:
1223 {
1224 struct semid64_ds tbuf;
1225 int id = 0;
1226
1227 memset(&tbuf, 0, sizeof(tbuf));
1228 1205
1229 rcu_read_lock(); 1206 err = -EACCES;
1230 if (cmd == SEM_STAT) { 1207 if (ipcperms(ns, &sma->sem_perm, S_IRUGO))
1231 sma = sem_obtain_object(ns, semid); 1208 goto out_unlock;
1232 if (IS_ERR(sma)) {
1233 err = PTR_ERR(sma);
1234 goto out_unlock;
1235 }
1236 id = sma->sem_perm.id;
1237 } else {
1238 sma = sem_obtain_object_check(ns, semid);
1239 if (IS_ERR(sma)) {
1240 err = PTR_ERR(sma);
1241 goto out_unlock;
1242 }
1243 }
1244 1209
1245 err = -EACCES; 1210 err = security_sem_semctl(sma, cmd);
1246 if (ipcperms(ns, &sma->sem_perm, S_IRUGO)) 1211 if (err)
1247 goto out_unlock; 1212 goto out_unlock;
1248 1213
1249 err = security_sem_semctl(sma, cmd); 1214 kernel_to_ipc64_perm(&sma->sem_perm, &semid64->sem_perm);
1250 if (err) 1215 semid64->sem_otime = get_semotime(sma);
1251 goto out_unlock; 1216 semid64->sem_ctime = sma->sem_ctime;
1217 semid64->sem_nsems = sma->sem_nsems;
1218 rcu_read_unlock();
1219 return id;
1252 1220
1253 kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);
1254 tbuf.sem_otime = get_semotime(sma);
1255 tbuf.sem_ctime = sma->sem_ctime;
1256 tbuf.sem_nsems = sma->sem_nsems;
1257 rcu_read_unlock();
1258 if (copy_semid_to_user(p, &tbuf, version))
1259 return -EFAULT;
1260 return id;
1261 }
1262 default:
1263 return -EINVAL;
1264 }
1265out_unlock: 1221out_unlock:
1266 rcu_read_unlock(); 1222 rcu_read_unlock();
1267 return err; 1223 return err;
1268} 1224}
1269 1225
1226static int semctl_info(struct ipc_namespace *ns, int semid,
1227 int cmd, void __user *p)
1228{
1229 struct seminfo seminfo;
1230 int max_id;
1231 int err;
1232
1233 err = security_sem_semctl(NULL, cmd);
1234 if (err)
1235 return err;
1236
1237 memset(&seminfo, 0, sizeof(seminfo));
1238 seminfo.semmni = ns->sc_semmni;
1239 seminfo.semmns = ns->sc_semmns;
1240 seminfo.semmsl = ns->sc_semmsl;
1241 seminfo.semopm = ns->sc_semopm;
1242 seminfo.semvmx = SEMVMX;
1243 seminfo.semmnu = SEMMNU;
1244 seminfo.semmap = SEMMAP;
1245 seminfo.semume = SEMUME;
1246 down_read(&sem_ids(ns).rwsem);
1247 if (cmd == SEM_INFO) {
1248 seminfo.semusz = sem_ids(ns).in_use;
1249 seminfo.semaem = ns->used_sems;
1250 } else {
1251 seminfo.semusz = SEMUSZ;
1252 seminfo.semaem = SEMAEM;
1253 }
1254 max_id = ipc_get_maxid(&sem_ids(ns));
1255 up_read(&sem_ids(ns).rwsem);
1256 if (copy_to_user(p, &seminfo, sizeof(struct seminfo)))
1257 return -EFAULT;
1258 return (max_id < 0) ? 0 : max_id;
1259}
1260
1270static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum, 1261static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum,
1271 unsigned long arg) 1262 int val)
1272{ 1263{
1273 struct sem_undo *un; 1264 struct sem_undo *un;
1274 struct sem_array *sma; 1265 struct sem_array *sma;
1275 struct sem *curr; 1266 struct sem *curr;
1276 int err, val; 1267 int err;
1277 DEFINE_WAKE_Q(wake_q); 1268 DEFINE_WAKE_Q(wake_q);
1278 1269
1279#if defined(CONFIG_64BIT) && defined(__BIG_ENDIAN)
1280 /* big-endian 64bit */
1281 val = arg >> 32;
1282#else
1283 /* 32bit or little-endian 64bit */
1284 val = arg;
1285#endif
1286
1287 if (val > SEMVMX || val < 0) 1270 if (val > SEMVMX || val < 0)
1288 return -ERANGE; 1271 return -ERANGE;
1289 1272
@@ -1327,7 +1310,7 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum,
1327 1310
1328 curr->semval = val; 1311 curr->semval = val;
1329 curr->sempid = task_tgid_vnr(current); 1312 curr->sempid = task_tgid_vnr(current);
1330 sma->sem_ctime = get_seconds(); 1313 sma->sem_ctime = ktime_get_real_seconds();
1331 /* maybe some queued-up processes were waiting for this */ 1314 /* maybe some queued-up processes were waiting for this */
1332 do_smart_update(sma, NULL, 0, 0, &wake_q); 1315 do_smart_update(sma, NULL, 0, 0, &wake_q);
1333 sem_unlock(sma, -1); 1316 sem_unlock(sma, -1);
@@ -1455,7 +1438,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
1455 for (i = 0; i < nsems; i++) 1438 for (i = 0; i < nsems; i++)
1456 un->semadj[i] = 0; 1439 un->semadj[i] = 0;
1457 } 1440 }
1458 sma->sem_ctime = get_seconds(); 1441 sma->sem_ctime = ktime_get_real_seconds();
1459 /* maybe some queued-up processes were waiting for this */ 1442 /* maybe some queued-up processes were waiting for this */
1460 do_smart_update(sma, NULL, 0, 0, &wake_q); 1443 do_smart_update(sma, NULL, 0, 0, &wake_q);
1461 err = 0; 1444 err = 0;
@@ -1532,23 +1515,17 @@ copy_semid_from_user(struct semid64_ds *out, void __user *buf, int version)
1532 * NOTE: no locks must be held, the rwsem is taken inside this function. 1515 * NOTE: no locks must be held, the rwsem is taken inside this function.
1533 */ 1516 */
1534static int semctl_down(struct ipc_namespace *ns, int semid, 1517static int semctl_down(struct ipc_namespace *ns, int semid,
1535 int cmd, int version, void __user *p) 1518 int cmd, struct semid64_ds *semid64)
1536{ 1519{
1537 struct sem_array *sma; 1520 struct sem_array *sma;
1538 int err; 1521 int err;
1539 struct semid64_ds semid64;
1540 struct kern_ipc_perm *ipcp; 1522 struct kern_ipc_perm *ipcp;
1541 1523
1542 if (cmd == IPC_SET) {
1543 if (copy_semid_from_user(&semid64, p, version))
1544 return -EFAULT;
1545 }
1546
1547 down_write(&sem_ids(ns).rwsem); 1524 down_write(&sem_ids(ns).rwsem);
1548 rcu_read_lock(); 1525 rcu_read_lock();
1549 1526
1550 ipcp = ipcctl_pre_down_nolock(ns, &sem_ids(ns), semid, cmd, 1527 ipcp = ipcctl_pre_down_nolock(ns, &sem_ids(ns), semid, cmd,
1551 &semid64.sem_perm, 0); 1528 &semid64->sem_perm, 0);
1552 if (IS_ERR(ipcp)) { 1529 if (IS_ERR(ipcp)) {
1553 err = PTR_ERR(ipcp); 1530 err = PTR_ERR(ipcp);
1554 goto out_unlock1; 1531 goto out_unlock1;
@@ -1568,10 +1545,10 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
1568 goto out_up; 1545 goto out_up;
1569 case IPC_SET: 1546 case IPC_SET:
1570 sem_lock(sma, NULL, -1); 1547 sem_lock(sma, NULL, -1);
1571 err = ipc_update_perm(&semid64.sem_perm, ipcp); 1548 err = ipc_update_perm(&semid64->sem_perm, ipcp);
1572 if (err) 1549 if (err)
1573 goto out_unlock0; 1550 goto out_unlock0;
1574 sma->sem_ctime = get_seconds(); 1551 sma->sem_ctime = ktime_get_real_seconds();
1575 break; 1552 break;
1576 default: 1553 default:
1577 err = -EINVAL; 1554 err = -EINVAL;
@@ -1592,6 +1569,8 @@ SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, unsigned long, arg)
1592 int version; 1569 int version;
1593 struct ipc_namespace *ns; 1570 struct ipc_namespace *ns;
1594 void __user *p = (void __user *)arg; 1571 void __user *p = (void __user *)arg;
1572 struct semid64_ds semid64;
1573 int err;
1595 1574
1596 if (semid < 0) 1575 if (semid < 0)
1597 return -EINVAL; 1576 return -EINVAL;
@@ -1602,9 +1581,15 @@ SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, unsigned long, arg)
1602 switch (cmd) { 1581 switch (cmd) {
1603 case IPC_INFO: 1582 case IPC_INFO:
1604 case SEM_INFO: 1583 case SEM_INFO:
1584 return semctl_info(ns, semid, cmd, p);
1605 case IPC_STAT: 1585 case IPC_STAT:
1606 case SEM_STAT: 1586 case SEM_STAT:
1607 return semctl_nolock(ns, semid, cmd, version, p); 1587 err = semctl_stat(ns, semid, cmd, &semid64);
1588 if (err < 0)
1589 return err;
1590 if (copy_semid_to_user(p, &semid64, version))
1591 err = -EFAULT;
1592 return err;
1608 case GETALL: 1593 case GETALL:
1609 case GETVAL: 1594 case GETVAL:
1610 case GETPID: 1595 case GETPID:
@@ -1612,15 +1597,120 @@ SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, unsigned long, arg)
1612 case GETZCNT: 1597 case GETZCNT:
1613 case SETALL: 1598 case SETALL:
1614 return semctl_main(ns, semid, semnum, cmd, p); 1599 return semctl_main(ns, semid, semnum, cmd, p);
1600 case SETVAL: {
1601 int val;
1602#if defined(CONFIG_64BIT) && defined(__BIG_ENDIAN)
1603 /* big-endian 64bit */
1604 val = arg >> 32;
1605#else
1606 /* 32bit or little-endian 64bit */
1607 val = arg;
1608#endif
1609 return semctl_setval(ns, semid, semnum, val);
1610 }
1611 case IPC_SET:
1612 if (copy_semid_from_user(&semid64, p, version))
1613 return -EFAULT;
1614 case IPC_RMID:
1615 return semctl_down(ns, semid, cmd, &semid64);
1616 default:
1617 return -EINVAL;
1618 }
1619}
1620
1621#ifdef CONFIG_COMPAT
1622
1623struct compat_semid_ds {
1624 struct compat_ipc_perm sem_perm;
1625 compat_time_t sem_otime;
1626 compat_time_t sem_ctime;
1627 compat_uptr_t sem_base;
1628 compat_uptr_t sem_pending;
1629 compat_uptr_t sem_pending_last;
1630 compat_uptr_t undo;
1631 unsigned short sem_nsems;
1632};
1633
1634static int copy_compat_semid_from_user(struct semid64_ds *out, void __user *buf,
1635 int version)
1636{
1637 memset(out, 0, sizeof(*out));
1638 if (version == IPC_64) {
1639 struct compat_semid64_ds *p = buf;
1640 return get_compat_ipc64_perm(&out->sem_perm, &p->sem_perm);
1641 } else {
1642 struct compat_semid_ds *p = buf;
1643 return get_compat_ipc_perm(&out->sem_perm, &p->sem_perm);
1644 }
1645}
1646
1647static int copy_compat_semid_to_user(void __user *buf, struct semid64_ds *in,
1648 int version)
1649{
1650 if (version == IPC_64) {
1651 struct compat_semid64_ds v;
1652 memset(&v, 0, sizeof(v));
1653 to_compat_ipc64_perm(&v.sem_perm, &in->sem_perm);
1654 v.sem_otime = in->sem_otime;
1655 v.sem_ctime = in->sem_ctime;
1656 v.sem_nsems = in->sem_nsems;
1657 return copy_to_user(buf, &v, sizeof(v));
1658 } else {
1659 struct compat_semid_ds v;
1660 memset(&v, 0, sizeof(v));
1661 to_compat_ipc_perm(&v.sem_perm, &in->sem_perm);
1662 v.sem_otime = in->sem_otime;
1663 v.sem_ctime = in->sem_ctime;
1664 v.sem_nsems = in->sem_nsems;
1665 return copy_to_user(buf, &v, sizeof(v));
1666 }
1667}
1668
1669COMPAT_SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, int, arg)
1670{
1671 void __user *p = compat_ptr(arg);
1672 struct ipc_namespace *ns;
1673 struct semid64_ds semid64;
1674 int version = compat_ipc_parse_version(&cmd);
1675 int err;
1676
1677 ns = current->nsproxy->ipc_ns;
1678
1679 if (semid < 0)
1680 return -EINVAL;
1681
1682 switch (cmd & (~IPC_64)) {
1683 case IPC_INFO:
1684 case SEM_INFO:
1685 return semctl_info(ns, semid, cmd, p);
1686 case IPC_STAT:
1687 case SEM_STAT:
1688 err = semctl_stat(ns, semid, cmd, &semid64);
1689 if (err < 0)
1690 return err;
1691 if (copy_compat_semid_to_user(p, &semid64, version))
1692 err = -EFAULT;
1693 return err;
1694 case GETVAL:
1695 case GETPID:
1696 case GETNCNT:
1697 case GETZCNT:
1698 case GETALL:
1699 case SETALL:
1700 return semctl_main(ns, semid, semnum, cmd, p);
1615 case SETVAL: 1701 case SETVAL:
1616 return semctl_setval(ns, semid, semnum, arg); 1702 return semctl_setval(ns, semid, semnum, arg);
1617 case IPC_RMID:
1618 case IPC_SET: 1703 case IPC_SET:
1619 return semctl_down(ns, semid, cmd, version, p); 1704 if (copy_compat_semid_from_user(&semid64, p, version))
1705 return -EFAULT;
1706 /* fallthru */
1707 case IPC_RMID:
1708 return semctl_down(ns, semid, cmd, &semid64);
1620 default: 1709 default:
1621 return -EINVAL; 1710 return -EINVAL;
1622 } 1711 }
1623} 1712}
1713#endif
1624 1714
1625/* If the task doesn't already have a undo_list, then allocate one 1715/* If the task doesn't already have a undo_list, then allocate one
1626 * here. We guarantee there is only one thread using this undo list, 1716 * here. We guarantee there is only one thread using this undo list,
@@ -1766,8 +1856,8 @@ out:
1766 return un; 1856 return un;
1767} 1857}
1768 1858
1769SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, 1859static long do_semtimedop(int semid, struct sembuf __user *tsops,
1770 unsigned, nsops, const struct timespec __user *, timeout) 1860 unsigned nsops, const struct timespec64 *timeout)
1771{ 1861{
1772 int error = -EINVAL; 1862 int error = -EINVAL;
1773 struct sem_array *sma; 1863 struct sem_array *sma;
@@ -1798,17 +1888,12 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
1798 } 1888 }
1799 1889
1800 if (timeout) { 1890 if (timeout) {
1801 struct timespec _timeout; 1891 if (timeout->tv_sec < 0 || timeout->tv_nsec < 0 ||
1802 if (copy_from_user(&_timeout, timeout, sizeof(*timeout))) { 1892 timeout->tv_nsec >= 1000000000L) {
1803 error = -EFAULT;
1804 goto out_free;
1805 }
1806 if (_timeout.tv_sec < 0 || _timeout.tv_nsec < 0 ||
1807 _timeout.tv_nsec >= 1000000000L) {
1808 error = -EINVAL; 1893 error = -EINVAL;
1809 goto out_free; 1894 goto out_free;
1810 } 1895 }
1811 jiffies_left = timespec_to_jiffies(&_timeout); 1896 jiffies_left = timespec64_to_jiffies(timeout);
1812 } 1897 }
1813 1898
1814 max = 0; 1899 max = 0;
@@ -2023,10 +2108,37 @@ out_free:
2023 return error; 2108 return error;
2024} 2109}
2025 2110
2111SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
2112 unsigned, nsops, const struct timespec __user *, timeout)
2113{
2114 if (timeout) {
2115 struct timespec64 ts;
2116 if (get_timespec64(&ts, timeout))
2117 return -EFAULT;
2118 return do_semtimedop(semid, tsops, nsops, &ts);
2119 }
2120 return do_semtimedop(semid, tsops, nsops, NULL);
2121}
2122
2123#ifdef CONFIG_COMPAT
2124COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems,
2125 unsigned, nsops,
2126 const struct compat_timespec __user *, timeout)
2127{
2128 if (timeout) {
2129 struct timespec64 ts;
2130 if (compat_get_timespec64(&ts, timeout))
2131 return -EFAULT;
2132 return do_semtimedop(semid, tsems, nsops, &ts);
2133 }
2134 return do_semtimedop(semid, tsems, nsops, NULL);
2135}
2136#endif
2137
2026SYSCALL_DEFINE3(semop, int, semid, struct sembuf __user *, tsops, 2138SYSCALL_DEFINE3(semop, int, semid, struct sembuf __user *, tsops,
2027 unsigned, nsops) 2139 unsigned, nsops)
2028{ 2140{
2029 return sys_semtimedop(semid, tsops, nsops, NULL); 2141 return do_semtimedop(semid, tsops, nsops, NULL);
2030} 2142}
2031 2143
2032/* If CLONE_SYSVSEM is set, establish sharing of SEM_UNDO state between 2144/* If CLONE_SYSVSEM is set, establish sharing of SEM_UNDO state between
@@ -2183,7 +2295,7 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
2183 struct user_namespace *user_ns = seq_user_ns(s); 2295 struct user_namespace *user_ns = seq_user_ns(s);
2184 struct kern_ipc_perm *ipcp = it; 2296 struct kern_ipc_perm *ipcp = it;
2185 struct sem_array *sma = container_of(ipcp, struct sem_array, sem_perm); 2297 struct sem_array *sma = container_of(ipcp, struct sem_array, sem_perm);
2186 time_t sem_otime; 2298 time64_t sem_otime;
2187 2299
2188 /* 2300 /*
2189 * The proc interface isn't aware of sem_lock(), it calls 2301 * The proc interface isn't aware of sem_lock(), it calls
@@ -2196,7 +2308,7 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
2196 sem_otime = get_semotime(sma); 2308 sem_otime = get_semotime(sma);
2197 2309
2198 seq_printf(s, 2310 seq_printf(s,
2199 "%10d %10d %4o %10u %5u %5u %5u %5u %10lu %10lu\n", 2311 "%10d %10d %4o %10u %5u %5u %5u %5u %10llu %10llu\n",
2200 sma->sem_perm.key, 2312 sma->sem_perm.key,
2201 sma->sem_perm.id, 2313 sma->sem_perm.id,
2202 sma->sem_perm.mode, 2314 sma->sem_perm.mode,