Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0
2 : /*
3 : * Copyright (c) 2000-2006 Silicon Graphics, Inc.
4 : * Copyright (c) 2012-2013 Red Hat, Inc.
5 : * All rights reserved.
6 : */
7 : #include "xfs.h"
8 : #include "xfs_fs.h"
9 : #include "xfs_format.h"
10 : #include "xfs_log_format.h"
11 : #include "xfs_shared.h"
12 : #include "xfs_trans_resv.h"
13 : #include "xfs_mount.h"
14 : #include "xfs_inode.h"
15 : #include "xfs_error.h"
16 : #include "xfs_trans.h"
17 : #include "xfs_buf_item.h"
18 : #include "xfs_log.h"
19 : #include "xfs_symlink_remote.h"
20 : #include "xfs_bit.h"
21 : #include "xfs_bmap.h"
22 : #include "xfs_health.h"
23 :
24 : /*
25 : * Each contiguous block has a header, so it is not just a simple pathlen
26 : * to FSB conversion.
27 : */
28 : int
29 27174398 : xfs_symlink_blocks(
30 : struct xfs_mount *mp,
31 : int pathlen)
32 : {
33 27174398 : int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
34 :
35 244464368 : return (pathlen + buflen - 1) / buflen;
36 : }
37 :
38 : int
39 22044422 : xfs_symlink_hdr_set(
40 : struct xfs_mount *mp,
41 : xfs_ino_t ino,
42 : uint32_t offset,
43 : uint32_t size,
44 : struct xfs_buf *bp)
45 : {
46 22044422 : struct xfs_dsymlink_hdr *dsl = bp->b_addr;
47 :
48 22044422 : if (!xfs_has_crc(mp))
49 : return 0;
50 :
51 22044422 : memset(dsl, 0, sizeof(struct xfs_dsymlink_hdr));
52 22044422 : dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);
53 22044422 : dsl->sl_offset = cpu_to_be32(offset);
54 22044422 : dsl->sl_bytes = cpu_to_be32(size);
55 22044422 : uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid);
56 22044185 : dsl->sl_owner = cpu_to_be64(ino);
57 22044185 : dsl->sl_blkno = cpu_to_be64(xfs_buf_daddr(bp));
58 22044185 : bp->b_ops = &xfs_symlink_buf_ops;
59 :
60 22044185 : return sizeof(struct xfs_dsymlink_hdr);
61 : }
62 :
63 : /*
64 : * Checking of the symlink header is split into two parts. the verifier does
65 : * CRC, location and bounds checking, the unpacking function checks the path
66 : * parameters and owner.
67 : */
68 : bool
69 216773933 : xfs_symlink_hdr_ok(
70 : xfs_ino_t ino,
71 : uint32_t offset,
72 : uint32_t size,
73 : struct xfs_buf *bp)
74 : {
75 216773933 : struct xfs_dsymlink_hdr *dsl = bp->b_addr;
76 :
77 433547866 : if (offset != be32_to_cpu(dsl->sl_offset))
78 : return false;
79 434392038 : if (size != be32_to_cpu(dsl->sl_bytes))
80 : return false;
81 217218570 : if (ino != be64_to_cpu(dsl->sl_owner))
82 0 : return false;
83 :
84 : /* ok */
85 : return true;
86 : }
87 :
88 : static xfs_failaddr_t
89 3690637 : xfs_symlink_verify(
90 : struct xfs_buf *bp)
91 : {
92 3690637 : struct xfs_mount *mp = bp->b_mount;
93 3690637 : struct xfs_dsymlink_hdr *dsl = bp->b_addr;
94 :
95 3690637 : if (!xfs_has_crc(mp))
96 0 : return __this_address;
97 3690637 : if (!xfs_verify_magic(bp, dsl->sl_magic))
98 0 : return __this_address;
99 3690637 : if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid))
100 0 : return __this_address;
101 3690637 : if (xfs_buf_daddr(bp) != be64_to_cpu(dsl->sl_blkno))
102 1 : return __this_address;
103 7381272 : if (be32_to_cpu(dsl->sl_offset) +
104 3690636 : be32_to_cpu(dsl->sl_bytes) >= XFS_SYMLINK_MAXLEN)
105 0 : return __this_address;
106 3690636 : if (dsl->sl_owner == 0)
107 0 : return __this_address;
108 3690636 : if (!xfs_log_check_lsn(mp, be64_to_cpu(dsl->sl_lsn)))
109 0 : return __this_address;
110 :
111 : return NULL;
112 : }
113 :
114 : static void
115 905868 : xfs_symlink_read_verify(
116 : struct xfs_buf *bp)
117 : {
118 905868 : struct xfs_mount *mp = bp->b_mount;
119 905868 : xfs_failaddr_t fa;
120 :
121 : /* no verification of non-crc buffers */
122 905868 : if (!xfs_has_crc(mp))
123 : return;
124 :
125 905868 : if (!xfs_buf_verify_cksum(bp, XFS_SYMLINK_CRC_OFF))
126 2 : xfs_verifier_error(bp, -EFSBADCRC, __this_address);
127 : else {
128 905865 : fa = xfs_symlink_verify(bp);
129 905865 : if (fa)
130 0 : xfs_verifier_error(bp, -EFSCORRUPTED, fa);
131 : }
132 : }
133 :
134 : static void
135 2778808 : xfs_symlink_write_verify(
136 : struct xfs_buf *bp)
137 : {
138 2778808 : struct xfs_mount *mp = bp->b_mount;
139 2778808 : struct xfs_buf_log_item *bip = bp->b_log_item;
140 2778808 : xfs_failaddr_t fa;
141 :
142 : /* no verification of non-crc buffers */
143 2778808 : if (!xfs_has_crc(mp))
144 : return;
145 :
146 2778808 : fa = xfs_symlink_verify(bp);
147 2778808 : if (fa) {
148 0 : xfs_verifier_error(bp, -EFSCORRUPTED, fa);
149 0 : return;
150 : }
151 :
152 2778808 : if (bip) {
153 2778808 : struct xfs_dsymlink_hdr *dsl = bp->b_addr;
154 2778808 : dsl->sl_lsn = cpu_to_be64(bip->bli_item.li_lsn);
155 : }
156 2778808 : xfs_buf_update_cksum(bp, XFS_SYMLINK_CRC_OFF);
157 : }
158 :
159 : const struct xfs_buf_ops xfs_symlink_buf_ops = {
160 : .name = "xfs_symlink",
161 : .magic = { 0, cpu_to_be32(XFS_SYMLINK_MAGIC) },
162 : .verify_read = xfs_symlink_read_verify,
163 : .verify_write = xfs_symlink_write_verify,
164 : .verify_struct = xfs_symlink_verify,
165 : };
166 :
167 : void
168 1043 : xfs_symlink_local_to_remote(
169 : struct xfs_trans *tp,
170 : struct xfs_buf *bp,
171 : struct xfs_inode *ip,
172 : struct xfs_ifork *ifp,
173 : void *priv)
174 : {
175 1043 : struct xfs_mount *mp = ip->i_mount;
176 1043 : char *buf;
177 :
178 1043 : xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SYMLINK_BUF);
179 :
180 1043 : if (!xfs_has_crc(mp)) {
181 0 : bp->b_ops = NULL;
182 0 : memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
183 0 : xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
184 0 : return;
185 : }
186 :
187 : /*
188 : * As this symlink fits in an inode literal area, it must also fit in
189 : * the smallest buffer the filesystem supports.
190 : */
191 1043 : ASSERT(BBTOB(bp->b_length) >=
192 : ifp->if_bytes + sizeof(struct xfs_dsymlink_hdr));
193 :
194 1043 : bp->b_ops = &xfs_symlink_buf_ops;
195 :
196 1043 : buf = bp->b_addr;
197 1043 : buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp);
198 2086 : memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes);
199 1043 : xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsymlink_hdr) +
200 1043 : ifp->if_bytes - 1);
201 : }
202 :
203 : /*
204 : * Verify the in-memory consistency of an inline symlink data fork. This
205 : * does not do on-disk format checks.
206 : */
207 : xfs_failaddr_t
208 6619828 : xfs_symlink_sf_verify_struct(
209 : void *sfp,
210 : int64_t size)
211 : {
212 6619828 : char *endp = sfp + size;
213 :
214 : /*
215 : * Zero length symlinks should never occur in memory as they are
216 : * never allowed to exist on disk.
217 : */
218 6619828 : if (!size)
219 0 : return __this_address;
220 :
221 : /* No negative sizes or overly long symlink targets. */
222 6619828 : if (size < 0 || size > XFS_SYMLINK_MAXLEN)
223 0 : return __this_address;
224 :
225 : /* No NULLs in the target either. */
226 13239656 : if (memchr(sfp, 0, size - 1))
227 2 : return __this_address;
228 :
229 : /* We /did/ null-terminate the buffer, right? */
230 6619826 : if (*endp != 0)
231 0 : return __this_address;
232 : return NULL;
233 : }
234 :
235 : xfs_failaddr_t
236 6619807 : xfs_symlink_shortform_verify(
237 : struct xfs_inode *ip)
238 : {
239 6619807 : struct xfs_ifork *ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK);
240 :
241 6619807 : ASSERT(ifp->if_format == XFS_DINODE_FMT_LOCAL);
242 :
243 6619807 : return xfs_symlink_sf_verify_struct(ifp->if_u1.if_data, ifp->if_bytes);
244 : }
245 :
246 : /* Read a remote symlink target into the buffer. */
247 : int
248 217263012 : xfs_symlink_remote_read(
249 : struct xfs_inode *ip,
250 : char *link)
251 : {
252 217263012 : struct xfs_mount *mp = ip->i_mount;
253 217263012 : struct xfs_bmbt_irec mval[XFS_SYMLINK_MAPS];
254 217263012 : struct xfs_buf *bp;
255 217263012 : xfs_daddr_t d;
256 217263012 : char *cur_chunk;
257 217263012 : int pathlen = ip->i_disk_size;
258 217263012 : int nmaps = XFS_SYMLINK_MAPS;
259 217263012 : int byte_cnt;
260 217263012 : int n;
261 217263012 : int error = 0;
262 217263012 : int fsblocks = 0;
263 217263012 : int offset;
264 :
265 217263012 : ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
266 :
267 217289970 : fsblocks = xfs_symlink_blocks(mp, pathlen);
268 217289970 : error = xfs_bmapi_read(ip, 0, fsblocks, mval, &nmaps, 0);
269 217293481 : if (error)
270 0 : goto out;
271 :
272 : offset = 0;
273 434635825 : for (n = 0; n < nmaps; n++) {
274 217292229 : d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
275 217292229 : byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
276 :
277 217292229 : error = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0,
278 : &bp, &xfs_symlink_buf_ops);
279 217198515 : if (xfs_metadata_is_sick(error))
280 2 : xfs_inode_mark_sick(ip, XFS_SICK_INO_SYMLINK);
281 217198515 : if (error)
282 2 : return error;
283 217198513 : byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
284 217198513 : if (pathlen < byte_cnt)
285 : byte_cnt = pathlen;
286 :
287 217198513 : cur_chunk = bp->b_addr;
288 217198513 : if (xfs_has_crc(mp)) {
289 217207405 : if (!xfs_symlink_hdr_ok(ip->i_ino, offset,
290 : byte_cnt, bp)) {
291 0 : xfs_inode_mark_sick(ip, XFS_SICK_INO_SYMLINK);
292 0 : error = -EFSCORRUPTED;
293 0 : xfs_alert(mp,
294 : "symlink header does not match required off/len/owner (0x%x/0x%x,0x%llx)",
295 : offset, byte_cnt, ip->i_ino);
296 0 : xfs_buf_relse(bp);
297 0 : goto out;
298 :
299 : }
300 :
301 217207405 : cur_chunk += sizeof(struct xfs_dsymlink_hdr);
302 : }
303 :
304 434397026 : memcpy(link + offset, cur_chunk, byte_cnt);
305 :
306 217198513 : pathlen -= byte_cnt;
307 217198513 : offset += byte_cnt;
308 :
309 217198513 : xfs_buf_relse(bp);
310 : }
311 217343596 : ASSERT(pathlen == 0);
312 :
313 217343596 : link[ip->i_disk_size] = '\0';
314 217343596 : error = 0;
315 :
316 : out:
317 : return error;
318 : }
319 :
320 : /* Write the symlink target into the inode. */
321 : int
322 27157510 : __xfs_symlink_write_target(
323 : struct xfs_trans *tp,
324 : struct xfs_inode *ip,
325 : xfs_ino_t owner,
326 : const char *target_path,
327 : int pathlen,
328 : xfs_fsblock_t fs_blocks,
329 : uint resblks)
330 : {
331 27157510 : struct xfs_bmbt_irec mval[XFS_SYMLINK_MAPS];
332 27157510 : struct xfs_mount *mp = tp->t_mountp;
333 27157510 : const char *cur_chunk;
334 27157510 : struct xfs_buf *bp;
335 27157510 : xfs_daddr_t d;
336 27157510 : int byte_cnt;
337 27157510 : int nmaps;
338 27157510 : int offset = 0;
339 27157510 : int n;
340 27157510 : int error;
341 :
342 : /*
343 : * If the symlink will fit into the inode, write it inline.
344 : */
345 27157510 : if (pathlen <= xfs_inode_data_fork_size(ip)) {
346 5112648 : xfs_init_local_fork(ip, XFS_DATA_FORK, target_path, pathlen);
347 :
348 5112635 : ip->i_disk_size = pathlen;
349 5112635 : ip->i_df.if_format = XFS_DINODE_FMT_LOCAL;
350 5112635 : xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE);
351 5112635 : return 0;
352 : }
353 :
354 22044862 : nmaps = XFS_SYMLINK_MAPS;
355 22044862 : error = xfs_bmapi_write(tp, ip, 0, fs_blocks, XFS_BMAPI_METADATA,
356 : resblks, mval, &nmaps);
357 22042060 : if (error)
358 : return error;
359 :
360 22042863 : ip->i_disk_size = pathlen;
361 22042863 : xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
362 :
363 22042863 : cur_chunk = target_path;
364 22042863 : offset = 0;
365 66127305 : for (n = 0; n < nmaps; n++) {
366 22040648 : char *buf;
367 :
368 22040648 : d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
369 22040648 : byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
370 22040648 : error = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
371 22040648 : BTOBB(byte_cnt), 0, &bp);
372 22043567 : if (error)
373 0 : return error;
374 22043567 : bp->b_ops = &xfs_symlink_buf_ops;
375 :
376 22043567 : byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
377 22043567 : byte_cnt = min(byte_cnt, pathlen);
378 :
379 22043567 : buf = bp->b_addr;
380 22043567 : buf += xfs_symlink_hdr_set(mp, owner, offset, byte_cnt, bp);
381 :
382 44084902 : memcpy(buf, cur_chunk, byte_cnt);
383 :
384 22042451 : cur_chunk += byte_cnt;
385 22042451 : pathlen -= byte_cnt;
386 22042451 : offset += byte_cnt;
387 :
388 22042451 : xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SYMLINK_BUF);
389 22043573 : xfs_trans_log_buf(tp, bp, 0, (buf + byte_cnt - 1) -
390 22043573 : (char *)bp->b_addr);
391 : }
392 22043794 : ASSERT(pathlen == 0);
393 : return 0;
394 : }
395 :
396 : /* Remove all the blocks from a symlink and invalidate buffers. */
397 : int
398 20976302 : xfs_symlink_remote_truncate(
399 : struct xfs_trans *tp,
400 : struct xfs_inode *ip)
401 : {
402 20976302 : struct xfs_bmbt_irec mval[XFS_SYMLINK_MAPS];
403 20976302 : struct xfs_mount *mp = tp->t_mountp;
404 20976302 : struct xfs_buf *bp;
405 20976302 : int nmaps = XFS_SYMLINK_MAPS;
406 20976302 : int done = 0;
407 20976302 : int i;
408 20976302 : int error;
409 :
410 : /* Read mappings and invalidate buffers. */
411 20976302 : error = xfs_bmapi_read(ip, 0, XFS_MAX_FILEOFF, mval, &nmaps, 0);
412 20975709 : if (error)
413 : return error;
414 :
415 41951397 : for (i = 0; i < nmaps; i++) {
416 62927251 : if (!xfs_bmap_is_real_extent(&mval[i]))
417 : break;
418 :
419 20975698 : error = xfs_trans_get_buf(tp, mp->m_ddev_targp,
420 20975698 : XFS_FSB_TO_DADDR(mp, mval[i].br_startblock),
421 20975698 : XFS_FSB_TO_BB(mp, mval[i].br_blockcount), 0,
422 : &bp);
423 20974475 : if (error)
424 0 : return error;
425 :
426 20974475 : xfs_trans_binval(tp, bp);
427 : }
428 :
429 : /* Unmap the remote blocks. */
430 20975699 : error = xfs_bunmapi(tp, ip, 0, XFS_MAX_FILEOFF, 0, nmaps, &done);
431 20975564 : if (error)
432 : return error;
433 20975564 : if (!done) {
434 0 : ASSERT(done);
435 0 : xfs_inode_mark_sick(ip, XFS_SICK_INO_SYMLINK);
436 0 : return -EFSCORRUPTED;
437 : }
438 :
439 20975564 : xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
440 20975564 : return 0;
441 : }
|