Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag '6.12-rc-ksmbd-server-fixes-part1' of git://git.samba.org/ksmbd

Pull smb server updates from Steve French:
"Four ksmbd server fixes, three for stable:

- Fix an issue where the directory can't be deleted if the share is
on a file system that does not provide dot and dotdot entries

- Fix file creation failure if the parent name of pathname is case
sensitive

- Fix write failure with FILE_APPEND_DATA flags

- Add reference count to connection struct to protect UAF of oplocks
on multichannel"

* tag '6.12-rc-ksmbd-server-fixes-part1' of git://git.samba.org/ksmbd:
ksmbd: handle caseless file creation
ksmbd: make __dir_empty() compatible with POSIX
ksmbd: add refcnt to ksmbd_conn struct
ksmbd: allow write with FILE_APPEND_DATA

+31 -51
+3 -1
fs/smb/server/connection.c
··· 39 39 xa_destroy(&conn->sessions); 40 40 kvfree(conn->request_buf); 41 41 kfree(conn->preauth_info); 42 - kfree(conn); 42 + if (atomic_dec_and_test(&conn->refcnt)) 43 + kfree(conn); 43 44 } 44 45 45 46 /** ··· 69 68 conn->um = NULL; 70 69 atomic_set(&conn->req_running, 0); 71 70 atomic_set(&conn->r_count, 0); 71 + atomic_set(&conn->refcnt, 1); 72 72 conn->total_credits = 1; 73 73 conn->outstanding_credits = 0; 74 74
+1
fs/smb/server/connection.h
··· 106 106 bool signing_negotiated; 107 107 __le16 signing_algorithm; 108 108 bool binding; 109 + atomic_t refcnt; 109 110 }; 110 111 111 112 struct ksmbd_conn_ops {
+16 -39
fs/smb/server/oplock.c
··· 51 51 init_waitqueue_head(&opinfo->oplock_brk); 52 52 atomic_set(&opinfo->refcount, 1); 53 53 atomic_set(&opinfo->breaking_cnt, 0); 54 + atomic_inc(&opinfo->conn->refcnt); 54 55 55 56 return opinfo; 56 57 } ··· 125 124 { 126 125 if (opinfo->is_lease) 127 126 free_lease(opinfo); 127 + if (opinfo->conn && atomic_dec_and_test(&opinfo->conn->refcnt)) 128 + kfree(opinfo->conn); 128 129 kfree(opinfo); 129 130 } 130 131 ··· 166 163 !atomic_inc_not_zero(&opinfo->refcount)) 167 164 opinfo = NULL; 168 165 else { 169 - atomic_inc(&opinfo->conn->r_count); 170 166 if (ksmbd_conn_releasing(opinfo->conn)) { 171 - atomic_dec(&opinfo->conn->r_count); 172 167 atomic_dec(&opinfo->refcount); 173 168 opinfo = NULL; 174 169 } ··· 178 177 return opinfo; 179 178 } 180 179 181 - static void opinfo_conn_put(struct oplock_info *opinfo) 180 + void opinfo_put(struct oplock_info *opinfo) 182 181 { 183 - struct ksmbd_conn *conn; 184 - 185 182 if (!opinfo) 186 183 return; 187 184 188 - conn = opinfo->conn; 189 - /* 190 - * Checking waitqueue to dropping pending requests on 191 - * disconnection. waitqueue_active is safe because it 192 - * uses atomic operation for condition. 193 - */ 194 - if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q)) 195 - wake_up(&conn->r_count_q); 196 - opinfo_put(opinfo); 197 - } 198 - 199 - void opinfo_put(struct oplock_info *opinfo) 200 - { 201 185 if (!atomic_dec_and_test(&opinfo->refcount)) 202 186 return; 203 187 ··· 1113 1127 if (!atomic_inc_not_zero(&opinfo->refcount)) 1114 1128 continue; 1115 1129 1116 - atomic_inc(&opinfo->conn->r_count); 1117 - if (ksmbd_conn_releasing(opinfo->conn)) { 1118 - atomic_dec(&opinfo->conn->r_count); 1130 + if (ksmbd_conn_releasing(opinfo->conn)) 1119 1131 continue; 1120 - } 1121 1132 1122 1133 oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE); 1123 - opinfo_conn_put(opinfo); 1134 + opinfo_put(opinfo); 1124 1135 } 1125 1136 } 1126 1137 up_read(&p_ci->m_lock); ··· 1150 1167 if (!atomic_inc_not_zero(&opinfo->refcount)) 1151 1168 continue; 1152 1169 1153 - atomic_inc(&opinfo->conn->r_count); 1154 - if (ksmbd_conn_releasing(opinfo->conn)) { 1155 - atomic_dec(&opinfo->conn->r_count); 1170 + if (ksmbd_conn_releasing(opinfo->conn)) 1156 1171 continue; 1157 - } 1158 1172 oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE); 1159 - opinfo_conn_put(opinfo); 1173 + opinfo_put(opinfo); 1160 1174 } 1161 1175 } 1162 1176 up_read(&p_ci->m_lock); ··· 1232 1252 prev_opinfo = opinfo_get_list(ci); 1233 1253 if (!prev_opinfo || 1234 1254 (prev_opinfo->level == SMB2_OPLOCK_LEVEL_NONE && lctx)) { 1235 - opinfo_conn_put(prev_opinfo); 1255 + opinfo_put(prev_opinfo); 1236 1256 goto set_lev; 1237 1257 } 1238 1258 prev_op_has_lease = prev_opinfo->is_lease; ··· 1242 1262 if (share_ret < 0 && 1243 1263 prev_opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE) { 1244 1264 err = share_ret; 1245 - opinfo_conn_put(prev_opinfo); 1265 + opinfo_put(prev_opinfo); 1246 1266 goto err_out; 1247 1267 } 1248 1268 1249 1269 if (prev_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH && 1250 1270 prev_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) { 1251 - opinfo_conn_put(prev_opinfo); 1271 + opinfo_put(prev_opinfo); 1252 1272 goto op_break_not_needed; 1253 1273 } 1254 1274 1255 1275 list_add(&work->interim_entry, &prev_opinfo->interim_list); 1256 1276 err = oplock_break(prev_opinfo, SMB2_OPLOCK_LEVEL_II); 1257 - opinfo_conn_put(prev_opinfo); 1277 + opinfo_put(prev_opinfo); 1258 1278 if (err == -ENOENT) 1259 1279 goto set_lev; 1260 1280 /* Check all oplock was freed by close */ ··· 1317 1337 return; 1318 1338 if (brk_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH && 1319 1339 brk_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) { 1320 - opinfo_conn_put(brk_opinfo); 1340 + opinfo_put(brk_opinfo); 1321 1341 return; 1322 1342 } 1323 1343 1324 1344 brk_opinfo->open_trunc = is_trunc; 1325 1345 list_add(&work->interim_entry, &brk_opinfo->interim_list); 1326 1346 oplock_break(brk_opinfo, SMB2_OPLOCK_LEVEL_II); 1327 - opinfo_conn_put(brk_opinfo); 1347 + opinfo_put(brk_opinfo); 1328 1348 } 1329 1349 1330 1350 /** ··· 1356 1376 if (!atomic_inc_not_zero(&brk_op->refcount)) 1357 1377 continue; 1358 1378 1359 - atomic_inc(&brk_op->conn->r_count); 1360 - if (ksmbd_conn_releasing(brk_op->conn)) { 1361 - atomic_dec(&brk_op->conn->r_count); 1379 + if (ksmbd_conn_releasing(brk_op->conn)) 1362 1380 continue; 1363 - } 1364 1381 1365 1382 rcu_read_unlock(); 1366 1383 if (brk_op->is_lease && (brk_op->o_lease->state & ··· 1388 1411 brk_op->open_trunc = is_trunc; 1389 1412 oplock_break(brk_op, SMB2_OPLOCK_LEVEL_NONE); 1390 1413 next: 1391 - opinfo_conn_put(brk_op); 1414 + opinfo_put(brk_op); 1392 1415 rcu_read_lock(); 1393 1416 } 1394 1417 rcu_read_unlock();
+8 -11
fs/smb/server/vfs.c
··· 496 496 int err = 0; 497 497 498 498 if (work->conn->connection_type) { 499 - if (!(fp->daccess & FILE_WRITE_DATA_LE)) { 499 + if (!(fp->daccess & (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE))) { 500 500 pr_err("no right to write(%pD)\n", fp->filp); 501 501 err = -EACCES; 502 502 goto out; ··· 1115 1115 struct ksmbd_readdir_data *buf; 1116 1116 1117 1117 buf = container_of(ctx, struct ksmbd_readdir_data, ctx); 1118 - buf->dirent_count++; 1118 + if (!is_dot_dotdot(name, namlen)) 1119 + buf->dirent_count++; 1119 1120 1120 - return buf->dirent_count <= 2; 1121 + return !buf->dirent_count; 1121 1122 } 1122 1123 1123 1124 /** ··· 1138 1137 readdir_data.dirent_count = 0; 1139 1138 1140 1139 err = iterate_dir(fp->filp, &readdir_data.ctx); 1141 - if (readdir_data.dirent_count > 2) 1140 + if (readdir_data.dirent_count) 1142 1141 err = -ENOTEMPTY; 1143 1142 else 1144 1143 err = 0; ··· 1167 1166 if (cmp < 0) 1168 1167 cmp = strncasecmp((char *)buf->private, name, namlen); 1169 1168 if (!cmp) { 1170 - memcpy((char *)buf->private, name, namlen); 1169 + memcpy((char *)buf->private, name, buf->used); 1171 1170 buf->dirent_count = 1; 1172 1171 return false; 1173 1172 } ··· 1235 1234 char *filepath; 1236 1235 size_t path_len, remain_len; 1237 1236 1238 - filepath = kstrdup(name, GFP_KERNEL); 1239 - if (!filepath) 1240 - return -ENOMEM; 1241 - 1237 + filepath = name; 1242 1238 path_len = strlen(filepath); 1243 1239 remain_len = path_len; 1244 1240 ··· 1278 1280 err = -EINVAL; 1279 1281 out2: 1280 1282 path_put(parent_path); 1281 - out1: 1282 - kfree(filepath); 1283 1283 } 1284 1284 1285 + out1: 1285 1286 if (!err) { 1286 1287 err = mnt_want_write(parent_path->mnt); 1287 1288 if (err) {
+3
fs/smb/server/vfs_cache.c
··· 863 863 list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) { 864 864 if (op->conn != conn) 865 865 continue; 866 + if (op->conn && atomic_dec_and_test(&op->conn->refcnt)) 867 + kfree(op->conn); 866 868 op->conn = NULL; 867 869 } 868 870 up_write(&ci->m_lock); ··· 967 965 if (op->conn) 968 966 continue; 969 967 op->conn = fp->conn; 968 + atomic_inc(&op->conn->refcnt); 970 969 } 971 970 up_write(&ci->m_lock); 972 971